scsi: make asynchronous aborts mandatory
Subsystems (2)
cover scsi: make asynchronous aborts mandatory
Hi all,
asynchronous abort have been activated since v3.14, and we haven't received any failure reports so far. So we should make asynchronous aborts mandatory and remove the no_async_aborts flag from the SCSI host structure.
With this we can also cleanup the failure path in SCSI EH.
Hannes Reinecke (3):
scsi: make scsi_eh_scmd_add() always succeed
scsi: make eh_eflags persistent
scsi: make asynchronous aborts mandatory
Documentation/scsi/scsi_eh.txt | 31 +++++------ drivers/scsi/scsi_error.c | 113 +++++++---------------------------------- drivers/scsi/scsi_lib.c | 4 +- drivers/scsi/scsi_priv.h | 3 +- include/scsi/scsi_eh.h | 1 + include/scsi/scsi_host.h | 5 -- 6 files changed, 34 insertions(+), 123 deletions(-)
Signature · 1 line
1.8.5.2
PATCH 1/3 scsi: make scsi_eh_scmd_add() always succeed
BLK_EH_HANDLED does not work with scsi commands, as we need to release the associated buffers correctly.
And scsi_eh_scmd_add() currently only will fail if no error handler thread is started (which will never be the case) or if the state machine encounters an illegal transition. As state machine transitions don't have any real meaning we can also force setting of the new state and
make scsi_dh_scmd_add() a void function.
With that we'll never have to resort to return BLK_EH_HANDLED.
--- drivers/scsi/scsi_error.c | 30 +++++++++--------------------- drivers/scsi/scsi_lib.c | 4 ++-- drivers/scsi/scsi_priv.h | 2 +- 3 files changed, 12 insertions(+), 24 deletions(-)
drivers/scsi/scsi_error.c +9 -21
@@ -163,14 +163,7 @@ scmd_eh_abort_handler(struct work_struct *work) } } -if (!scsi_eh_scmd_add (scmd,0 )) { -SCSI_LOG_ERROR_RECOVERY (3 , -scmd_printk (KERN_WARNING , scmd, -"scmd %p terminate " -"aborted command\n" , scmd)); -set_host_byte (scmd,DID_TIME_OUT ); -scsi_finish_command (scmd); - } +scsi_eh_scmd_add (scmd,0 ); }/**
@@ -228,37 +221,33 @@ scsi_abort_command(struct scsi_cmnd *scmd)* scsi_eh_scmd_add - add scsi cmd to error handling. * @scmd: scmd to run eh on. * @eh_flag: optional SCSI_EH flag. -* -* Return value: -* 0 on failure. */ -int scsi_eh_scmd_add (struct scsi_cmnd *scmd,int eh_flag) +void scsi_eh_scmd_add (struct scsi_cmnd *scmd,int eh_flag) {struct Scsi_Host *shost = scmd->device->host;unsigned long flags; -int ret =0 ; -if (!shost->ehandler) -return 0 ; +WARN_ON (!shost->ehandler);spin_lock_irqsave (shost->host_lock, flags); +/* +* Force SHOST_RECOVERY even for illegal state transitions; +* we cannot handle failed commands otherwise. +*/ if (scsi_host_set_state (shost,SHOST_RECOVERY ))if (scsi_host_set_state (shost,SHOST_CANCEL_RECOVERY )) - goto out_unlock; + shost->shost_state =SHOST_RECOVERY ;if (shost->eh_deadline !=-1 && !shost->last_reset) shost->last_reset = jiffies; - ret =1 ;if (scmd->eh_eflags &SCSI_EH_ABORT_SCHEDULED ) eh_flag &= ~SCSI_EH_CANCEL_CMD ; scmd->eh_eflags |= eh_flag;list_add_tail (&scmd->eh_entry, &shost->eh_cmd_q); shost->host_failed++;scsi_eh_wakeup (shost); - out_unlock:spin_unlock_irqrestore (shost->host_lock, flags); -return ret; }/**
@@ -294,8 +283,7 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)return BLK_EH_NOT_HANDLED ;set_host_byte (scmd,DID_TIME_OUT ); -if (!scsi_eh_scmd_add (scmd,SCSI_EH_CANCEL_CMD )) - rtn =BLK_EH_HANDLED ; +scsi_eh_scmd_add (scmd,SCSI_EH_CANCEL_CMD ); }return rtn;
drivers/scsi/scsi_lib.c +2 -2
@@ -1647,8 +1647,8 @@ static void scsi_softirq_done(struct request *rq)scsi_queue_insert (cmd,SCSI_MLQUEUE_DEVICE_BUSY );break ;default : -if (!scsi_eh_scmd_add (cmd,0 )) -scsi_finish_command (cmd); +scsi_eh_scmd_add (cmd,0 ); +break ; } }
drivers/scsi/scsi_priv.h +1 -1
@@ -72,7 +72,7 @@ extern enum blk_eh_timer_return scsi_times_out(struct request *req);extern int scsi_error_handler (void *host);extern int scsi_decide_disposition (struct scsi_cmnd *cmd);extern void scsi_eh_wakeup (struct Scsi_Host *shost); -extern int scsi_eh_scmd_add (struct scsi_cmnd *,int ); +extern void scsi_eh_scmd_add (struct scsi_cmnd *,int );void scsi_eh_ready_devs (struct Scsi_Host *shost,struct list_head *work_q,struct list_head *done_q);
Signature · 1 line
1.8.5.2
Re: [PATCH 1/3] scsi: make scsi_eh_scmd_add() always succeed
Quoted 2 lines · Hannes Reinecke
BLK_EH_HANDLEDdoes not work with scsi commands, as we need to release the associated buffers correctly.
Which particular error do you see? The ->eh_timed_out routines can return BLK_EH_HANDLED, and libata, iscsi and fc actually do, so we'll need to fix these issues either way.
Quoted 3 lines
And
scsi_eh_scmd_add()currently only will fail if no error handler thread is started (which will never be the case)
Yes.
Quoted 6 lines
or if the state machine encounters an illegal transition. As state machine transitions don't have any real meaning we can also force setting of the new state and make
scsi_dh_scmd_add()a void function.
With that we'll never have to resort to returnBLK_EH_HANDLED.
Which kind of transition did you see rejected? Neither a CREATED or DEL_(RECOVERY) state should be possible when invoking the error handler, so I'd rather see asserts here than overriding the state machine. te RECOVERY state from a RUNNING or existing RECOVERY state, which leaves CREATED, CANCEL, DEL, CANCEL_RECOVERY or DEL_RECOVERY.
Re: [PATCH 1/3] scsi: make scsi_eh_scmd_add() always succeed
Quoted 8 lines · Christoph Hellwig
Quoted 2 lines · Hannes Reinecke
BLK_EH_HANDLEDdoes not work with scsi commands, as we need to release the associated buffers correctly.Which particular error do you see? The ->eh_timed_out routines can return
BLK_EH_HANDLED, and libata, iscsi and fc actually do, so we'll need to fix these issues either way.
Hmm. Looking closer it seem that you are correct. However, the main point still stands; there is no way scsi_eh_scmd_add() can legitimately fail.
Quoted 13 lines
Quoted 3 lines
And
scsi_eh_scmd_add()currently only will fail if no error handler thread is started (which will never be the case)Yes.
Quoted 6 lines
or if the state machine encounters an illegal transition. As state machine transitions don't have any real meaning we can also force setting of the new state and make
scsi_dh_scmd_add()a void function.
With that we'll never have to resort to returnBLK_EH_HANDLED.
Quoted 6 lines
Which kind of transition did you see rejected? Neither a CREATED or
DEL_(RECOVERY)state should be possible when invoking the error handler, so I'd rather see asserts here than overriding the state machine. te RECOVERY state from a RUNNING or existing RECOVERY state, which leaves CREATED, CANCEL, DEL,CANCEL_RECOVERYorDEL_RECOVERY.
I did not see any rejection so far.
However, we're calling scsi_host_set_state(), which _might_ fail. And we need to have a way of either
a) make sure that it cannot fail prior to calling it
or
b) handling the failure.
So I'm fine with using asserts here.
I'll be updating the patch (and description)
Cheers,
Hannes
Signature · 8 lines
Dr. Hannes Reinecke zSeries & Storage [email protected] +49 911 74053 688 SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: J. Hawn, J. Guild, F. Imendörffer, HRB 21284 (AG Nürnberg) -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 2/3 scsi: make eh_eflags persistent
In reply to Hannes ReineckeTo detect if a failed command has been retried we must not clear scmd->eh_eflags when EH finishes.
The flag should be persistent throughout the lifetime of the command.
--- Documentation/scsi/scsi_eh.txt | 3 --- drivers/scsi/scsi_error.c | 4 ++-- include/scsi/scsi_eh.h | 1 + 3 files changed, 3 insertions(+), 5 deletions(-)
Documentation/scsi/scsi_eh.txt +0 -3
@@ -264,7 +264,6 @@ scmd->allowed. 3. scmd recovered ACTION: scsi_eh_finish_cmd() is invoked to EH-finish scmd - shost->host_failed-- - - clear scmd->eh_eflags - scsi_setup_cmd_retry() - move from local eh_work_q to local eh_done_q LOCKING: none
@@ -452,8 +451,6 @@ except for #1 must be implemented by eh_strategy_handler(). - shost->host_failed is zero. - - Each scmd's eh_eflags field is cleared. - - Each scmd is in such a state that scsi_setup_cmd_retry() on the scmd doesn't make any difference.
drivers/scsi/scsi_error.c +2 -2
@@ -183,7 +183,6 @@ scsi_abort_command(struct scsi_cmnd *scmd)/* * Retry after abort failed, escalate to next level. */ - scmd->eh_eflags &= ~SCSI_EH_ABORT_SCHEDULED ;SCSI_LOG_ERROR_RECOVERY (3 ,scmd_printk (KERN_INFO , scmd,"scmd %p previous abort failed\n" , scmd));
@@ -926,6 +925,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, ses->result = scmd->result; ses->underflow = scmd->underflow; ses->prot_op = scmd->prot_op; + ses->eh_eflags = scmd->eh_eflags; scmd->prot_op =SCSI_PROT_NORMAL ; scmd->eh_eflags =0 ;
@@ -989,6 +989,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) scmd->result = ses->result; scmd->underflow = ses->underflow; scmd->prot_op = ses->prot_op; + scmd->eh_eflags = ses->eh_eflags; }EXPORT_SYMBOL (scsi_eh_restore_cmnd);
@@ -1122,7 +1123,6 @@ static int scsi_eh_action(struct scsi_cmnd *scmd, int rtn)void scsi_eh_finish_cmd (struct scsi_cmnd *scmd,struct list_head *done_q) { scmd->device->host->host_failed--; - scmd->eh_eflags =0 ;list_move_tail (&scmd->eh_entry, done_q); }EXPORT_SYMBOL (scsi_eh_finish_cmd);
include/scsi/scsi_eh.h +1 -0
@@ -78,6 +78,7 @@ extern int scsi_reset_provider(struct scsi_device *, int);struct scsi_eh_save {/* saved state */ int result; +int eh_eflags;enum dma_data_direction data_direction;unsigned underflow;unsigned char cmd_len;
Signature · 1 line
1.8.5.2
PATCH 3/3 scsi: make asynchronous aborts mandatory
In reply to Hannes ReineckeThere hasn't been any reports for HBAs where asynchronous abort would not work, so we should make it mandatory and remove the fallback.
--- Documentation/scsi/scsi_eh.txt | 28 +++++++------- drivers/scsi/scsi_error.c | 85 +++++------------------------------------- drivers/scsi/scsi_lib.c | 2 +- drivers/scsi/scsi_priv.h | 3 +- include/scsi/scsi_host.h | 5 --- 5 files changed, 24 insertions(+), 99 deletions(-)
Documentation/scsi/scsi_eh.txt +13 -15
@@ -70,7 +70,7 @@ with the command. scmd is requeued to blk queue. - otherwise - scsi_eh_scmd_add(scmd, 0) is invoked for the command. See + scsi_eh_scmd_add(scmd) is invoked for the command. See [1-3] for details of this function.
@@ -103,13 +103,15 @@ function eh_timed_out() callback did not handle the command. Step #2 is taken. - 2. If the host supports asynchronous completion (as indicated by the - no_async_abort setting in the host template) scsi_abort_command() - is invoked to schedule an asynchrous abort. If that fails - Step #3 is taken. + 2. scsi_abort_command() is invoked to schedule an asynchrous abort + (Seee [1-3] for more information). + Asynchronous abort are not invoked for commands which have + SCSI_EH_ABORT_SCHEDULED set (this indicates that the command + already had been aborted once, and this is a retry which failed), + or when the EH deadline is expired. In these case Step #3 is taken. - 2. scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD) is invoked for the - command. See [1-3] for more information. + 3. scsi_eh_scmd_add(scmd) is invoked for the + command. See [1-4] for more information. [1-3] Asynchronous command aborts
@@ -124,16 +126,13 @@ function scmds enter EH via scsi_eh_scmd_add(), which does the following. - 1. Turns on scmd->eh_eflags as requested. It's 0 for error - completions and SCSI_EH_CANCEL_CMD for timeouts. + 1. Links scmd->eh_entry to shost->eh_cmd_q - 2. Links scmd->eh_entry to shost->eh_cmd_q + 2. Sets SHOST_RECOVERY bit in shost->shost_state - 3. Sets SHOST_RECOVERY bit in shost->shost_state + 3. Increments shost->host_failed - 4. Increments shost->host_failed - - 5. Wakes up SCSI EH thread if shost->host_busy == shost->host_failed + 4. Wakes up SCSI EH thread if shost->host_busy == shost->host_failed As can be seen above, once any scmd is added to shost->eh_cmd_q, SHOST_RECOVERY shost_state bit is turned on. This prevents any new
@@ -249,7 +248,6 @@ scmd->allowed. 1. Error completion / time out ACTION: scsi_eh_scmd_add() is invoked for scmd - - set scmd->eh_eflags - add scmd to shost->eh_cmd_q - set SHOST_RECOVERY - shost->host_failed++
drivers/scsi/scsi_error.c +9 -76
140 lines not on this page · raw message
drivers/scsi/scsi_lib.c +1 -1
@@ -1647,7 +1647,7 @@ static void scsi_softirq_done(struct request *rq)scsi_queue_insert (cmd,SCSI_MLQUEUE_DEVICE_BUSY );break ;default : -scsi_eh_scmd_add (cmd,0 ); +scsi_eh_scmd_add (cmd);break ; } }
drivers/scsi/scsi_priv.h +1 -2
@@ -18,7 +18,6 @@ struct scsi_nl_hdr;/* * Scsi Error Handler Flags */ -#define SCSI_EH_CANCEL_CMD 0x0001/* Cancel this cmd */ #define SCSI_EH_ABORT_SCHEDULED 0x0002/* Abort has been scheduled */ #define SCSI_SENSE_VALID (scmd) \
@@ -72,7 +71,7 @@ extern enum blk_eh_timer_return scsi_times_out(struct request *req);extern int scsi_error_handler (void *host);extern int scsi_decide_disposition (struct scsi_cmnd *cmd);extern void scsi_eh_wakeup (struct Scsi_Host *shost); -extern void scsi_eh_scmd_add (struct scsi_cmnd *,int ); +extern void scsi_eh_scmd_add (struct scsi_cmnd *);void scsi_eh_ready_devs (struct Scsi_Host *shost,struct list_head *work_q,struct list_head *done_q);
include/scsi/scsi_host.h +0 -5
@@ -460,11 +460,6 @@ struct scsi_host_template { unsigned no_write_same:1;/* -* True if asynchronous aborts are not supported -*/ - unsigned no_async_abort:1; - -/* * Countdown for host blocking with no commands outstanding. */ unsigned int max_host_blocked;
Signature · 1 line
1.8.5.2
This leaves a stale comment reference to scsi_eh_abort_cmds in libsas. Also while grepping for that I found out that sas aborts don't work anymore with the async abort code due to this beautiful code in sas_eh_abort_handler:
if (current != host->ehandler) return FAILED;
so you'll need another patch to fix that up. In the longer run we really should both kill sas_eh_abort_handler and bring SAS EH more in line with the rest of the world.