scsi: core: Add limitless cmd retry support

Add infinite retry support to SCSI midlayer by combining common checks for
retries into some helper functions, and then checking for the
-1/SCSI_CMD_RETRIES_NO_LIMIT.

Link: https://lore.kernel.org/r/1601566554-26752-2-git-send-email-michael.christie@oracle.com
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Mike Christie 2020-10-01 10:35:53 -05:00 committed by Martin K. Petersen
parent 7010645ba7
commit 2a242d59d6
3 changed files with 43 additions and 20 deletions

View File

@ -116,6 +116,14 @@ static int scsi_host_eh_past_deadline(struct Scsi_Host *shost)
return 1; return 1;
} }
static bool scsi_cmd_retry_allowed(struct scsi_cmnd *cmd)
{
if (cmd->allowed == SCSI_CMD_RETRIES_NO_LIMIT)
return true;
return ++cmd->retries <= cmd->allowed;
}
/** /**
* scmd_eh_abort_handler - Handle command aborts * scmd_eh_abort_handler - Handle command aborts
* @work: command to be aborted. * @work: command to be aborted.
@ -151,7 +159,7 @@ scmd_eh_abort_handler(struct work_struct *work)
"eh timeout, not retrying " "eh timeout, not retrying "
"aborted command\n")); "aborted command\n"));
} else if (!scsi_noretry_cmd(scmd) && } else if (!scsi_noretry_cmd(scmd) &&
(++scmd->retries <= scmd->allowed)) { scsi_cmd_retry_allowed(scmd)) {
SCSI_LOG_ERROR_RECOVERY(3, SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_WARNING, scmd, scmd_printk(KERN_WARNING, scmd,
"retry aborted command\n")); "retry aborted command\n"));
@ -1264,11 +1272,18 @@ int scsi_eh_get_sense(struct list_head *work_q,
* upper level. * upper level.
*/ */
if (rtn == SUCCESS) if (rtn == SUCCESS)
/* we don't want this command reissued, just /*
* finished with the sense data, so set * We don't want this command reissued, just finished
* retries to the max allowed to ensure it * with the sense data, so set retries to the max
* won't get reissued */ * allowed to ensure it won't get reissued. If the user
scmd->retries = scmd->allowed; * has requested infinite retries, we also want to
* finish this command, so force completion by setting
* retries and allowed to the same value.
*/
if (scmd->allowed == SCSI_CMD_RETRIES_NO_LIMIT)
scmd->retries = scmd->allowed = 1;
else
scmd->retries = scmd->allowed;
else if (rtn != NEEDS_RETRY) else if (rtn != NEEDS_RETRY)
continue; continue;
@ -1944,8 +1959,7 @@ maybe_retry:
* the request was not marked fast fail. Note that above, * the request was not marked fast fail. Note that above,
* even if the request is marked fast fail, we still requeue * even if the request is marked fast fail, we still requeue
* for queue congestion conditions (QUEUE_FULL or BUSY) */ * for queue congestion conditions (QUEUE_FULL or BUSY) */
if ((++scmd->retries) <= scmd->allowed if (scsi_cmd_retry_allowed(scmd) && !scsi_noretry_cmd(scmd)) {
&& !scsi_noretry_cmd(scmd)) {
return NEEDS_RETRY; return NEEDS_RETRY;
} else { } else {
/* /*
@ -2091,8 +2105,7 @@ void scsi_eh_flush_done_q(struct list_head *done_q)
list_for_each_entry_safe(scmd, next, done_q, eh_entry) { list_for_each_entry_safe(scmd, next, done_q, eh_entry) {
list_del_init(&scmd->eh_entry); list_del_init(&scmd->eh_entry);
if (scsi_device_online(scmd->device) && if (scsi_device_online(scmd->device) &&
!scsi_noretry_cmd(scmd) && !scsi_noretry_cmd(scmd) && scsi_cmd_retry_allowed(scmd)) {
(++scmd->retries <= scmd->allowed)) {
SCSI_LOG_ERROR_RECOVERY(3, SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd, scmd_printk(KERN_INFO, scmd,
"%s: flush retry cmd\n", "%s: flush retry cmd\n",

View File

@ -669,6 +669,23 @@ static void scsi_io_completion_reprep(struct scsi_cmnd *cmd,
scsi_mq_requeue_cmd(cmd); scsi_mq_requeue_cmd(cmd);
} }
static bool scsi_cmd_runtime_exceeced(struct scsi_cmnd *cmd)
{
struct request *req = cmd->request;
unsigned long wait_for;
if (cmd->allowed == SCSI_CMD_RETRIES_NO_LIMIT)
return false;
wait_for = (cmd->allowed + 1) * req->timeout;
if (time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
scmd_printk(KERN_ERR, cmd, "timing out command, waited %lus\n",
wait_for/HZ);
return true;
}
return false;
}
/* Helper for scsi_io_completion() when special action required. */ /* Helper for scsi_io_completion() when special action required. */
static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result) static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
{ {
@ -677,7 +694,6 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
int level = 0; int level = 0;
enum {ACTION_FAIL, ACTION_REPREP, ACTION_RETRY, enum {ACTION_FAIL, ACTION_REPREP, ACTION_RETRY,
ACTION_DELAYED_RETRY} action; ACTION_DELAYED_RETRY} action;
unsigned long wait_for = (cmd->allowed + 1) * req->timeout;
struct scsi_sense_hdr sshdr; struct scsi_sense_hdr sshdr;
bool sense_valid; bool sense_valid;
bool sense_current = true; /* false implies "deferred sense" */ bool sense_current = true; /* false implies "deferred sense" */
@ -782,8 +798,7 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
} else } else
action = ACTION_FAIL; action = ACTION_FAIL;
if (action != ACTION_FAIL && if (action != ACTION_FAIL && scsi_cmd_runtime_exceeced(cmd))
time_before(cmd->jiffies_at_alloc + wait_for, jiffies))
action = ACTION_FAIL; action = ACTION_FAIL;
switch (action) { switch (action) {
@ -1456,7 +1471,6 @@ static bool scsi_mq_lld_busy(struct request_queue *q)
static void scsi_softirq_done(struct request *rq) static void scsi_softirq_done(struct request *rq)
{ {
struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
unsigned long wait_for = (cmd->allowed + 1) * rq->timeout;
int disposition; int disposition;
INIT_LIST_HEAD(&cmd->eh_entry); INIT_LIST_HEAD(&cmd->eh_entry);
@ -1466,13 +1480,8 @@ static void scsi_softirq_done(struct request *rq)
atomic_inc(&cmd->device->ioerr_cnt); atomic_inc(&cmd->device->ioerr_cnt);
disposition = scsi_decide_disposition(cmd); disposition = scsi_decide_disposition(cmd);
if (disposition != SUCCESS && if (disposition != SUCCESS && scsi_cmd_runtime_exceeced(cmd))
time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
scmd_printk(KERN_ERR, cmd,
"timing out command, waited %lus\n",
wait_for/HZ);
disposition = SUCCESS; disposition = SUCCESS;
}
scsi_log_completion(cmd, disposition); scsi_log_completion(cmd, disposition);

View File

@ -15,6 +15,7 @@ struct scsi_host_template;
struct Scsi_Host; struct Scsi_Host;
struct scsi_nl_hdr; struct scsi_nl_hdr;
#define SCSI_CMD_RETRIES_NO_LIMIT -1
/* /*
* Scsi Error Handler Flags * Scsi Error Handler Flags