Skip to content

Commit

Permalink
scsi: make asynchronous aborts mandatory
Browse files Browse the repository at this point in the history
There hasn't been any reports for HBAs where asynchronous abort
would not work, so we should make it mandatory and remove
the fallback.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Hannes Reinecke authored and Martin K. Petersen committed Apr 6, 2017
1 parent 2171b6d commit a065863
Show file tree
Hide file tree
Showing 5 changed files with 15 additions and 94 deletions.
18 changes: 6 additions & 12 deletions Documentation/scsi/scsi_eh.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.


Expand Down Expand Up @@ -103,9 +103,7 @@ 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.
2. scsi_abort_command() is invoked to schedule an asynchrous abort.
Asynchronous abort are not invoked for commands which the
SCSI_EH_ABORT_SCHEDULED flag is set (this indicates that the command
already had been aborted once, and this is a retry which failed),
Expand All @@ -127,16 +125,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
Expand Down Expand Up @@ -252,7 +247,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++
Expand Down
81 changes: 7 additions & 74 deletions drivers/scsi/scsi_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ scmd_eh_abort_handler(struct work_struct *work)
}
}

scsi_eh_scmd_add(scmd, 0);
scsi_eh_scmd_add(scmd);
}

/**
Expand Down Expand Up @@ -221,9 +221,8 @@ static void scsi_eh_reset(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.
*/
void scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
{
struct Scsi_Host *shost = scmd->device->host;
unsigned long flags;
Expand All @@ -239,9 +238,6 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
if (shost->eh_deadline != -1 && !shost->last_reset)
shost->last_reset = jiffies;

if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED)
eh_flag &= ~SCSI_EH_CANCEL_CMD;
scmd->eh_eflags |= eh_flag;
scsi_eh_reset(scmd);
list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
shost->host_failed++;
Expand Down Expand Up @@ -275,10 +271,9 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
rtn = host->hostt->eh_timed_out(scmd);

if (rtn == BLK_EH_NOT_HANDLED) {
if (host->hostt->no_async_abort ||
scsi_abort_command(scmd) != SUCCESS) {
if (scsi_abort_command(scmd) != SUCCESS) {
set_host_byte(scmd, DID_TIME_OUT);
scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD);
scsi_eh_scmd_add(scmd);
}
}

Expand Down Expand Up @@ -331,7 +326,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
list_for_each_entry(scmd, work_q, eh_entry) {
if (scmd->device == sdev) {
++total_failures;
if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD)
if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED)
++cmd_cancel;
else
++cmd_failed;
Expand Down Expand Up @@ -1154,8 +1149,7 @@ int scsi_eh_get_sense(struct list_head *work_q,
* should not get sense.
*/
list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
if ((scmd->eh_eflags & SCSI_EH_CANCEL_CMD) ||
(scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) ||
if ((scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) ||
SCSI_SENSE_VALID(scmd))
continue;

Expand Down Expand Up @@ -1295,61 +1289,6 @@ static int scsi_eh_test_devices(struct list_head *cmd_list,
return list_empty(work_q);
}


/**
* scsi_eh_abort_cmds - abort pending commands.
* @work_q: &list_head for pending commands.
* @done_q: &list_head for processed commands.
*
* Decription:
* Try and see whether or not it makes sense to try and abort the
* running command. This only works out to be the case if we have one
* command that has timed out. If the command simply failed, it makes
* no sense to try and abort the command, since as far as the shost
* adapter is concerned, it isn't running.
*/
static int scsi_eh_abort_cmds(struct list_head *work_q,
struct list_head *done_q)
{
struct scsi_cmnd *scmd, *next;
LIST_HEAD(check_list);
int rtn;
struct Scsi_Host *shost;

list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
if (!(scmd->eh_eflags & SCSI_EH_CANCEL_CMD))
continue;
shost = scmd->device->host;
if (scsi_host_eh_past_deadline(shost)) {
list_splice_init(&check_list, work_q);
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
"%s: skip aborting cmd, past eh deadline\n",
current->comm));
return list_empty(work_q);
}
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
"%s: aborting cmd\n", current->comm));
rtn = scsi_try_to_abort_cmd(shost->hostt, scmd);
if (rtn == FAILED) {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
"%s: aborting cmd failed\n",
current->comm));
list_splice_init(&check_list, work_q);
return list_empty(work_q);
}
scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD;
if (rtn == FAST_IO_FAIL)
scsi_eh_finish_cmd(scmd, done_q);
else
list_move_tail(&scmd->eh_entry, &check_list);
}

return scsi_eh_test_devices(&check_list, work_q, done_q, 0);
}

/**
* scsi_eh_try_stu - Send START_UNIT to device.
* @scmd: &scsi_cmnd to send START_UNIT
Expand Down Expand Up @@ -1692,11 +1631,6 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q,
sdev_printk(KERN_INFO, scmd->device, "Device offlined - "
"not ready after error recovery\n");
scsi_device_set_state(scmd->device, SDEV_OFFLINE);
if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD) {
/*
* FIXME: Handle lost cmds.
*/
}
scsi_eh_finish_cmd(scmd, done_q);
}
return;
Expand Down Expand Up @@ -2140,8 +2074,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)
SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(shost, &eh_work_q));

if (!scsi_eh_get_sense(&eh_work_q, &eh_done_q))
if (!scsi_eh_abort_cmds(&eh_work_q, &eh_done_q))
scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q);
scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q);

spin_lock_irqsave(shost->host_lock, flags);
if (shost->eh_deadline != -1)
Expand Down
2 changes: 1 addition & 1 deletion drivers/scsi/scsi_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1593,7 +1593,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;
}
}
Expand Down
3 changes: 1 addition & 2 deletions drivers/scsi/scsi_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 0 additions & 5 deletions include/scsi/scsi_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,11 +451,6 @@ struct scsi_host_template {
/* True if the controller does not support WRITE SAME */
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.
*/
Expand Down

0 comments on commit a065863

Please sign in to comment.