[PATCH 2/7] Allow requeuement on DID_SOFT_ERROR

Bernd Schubert
2008-11-26T17:46:57Z

Activate the error handler if DID_SOFT_ERROR failed to often, but only
for commands which have a scmd->allowed > 1.
Also make a function out of a goto-block.

Signed-off-by: Bernd Schubert <bs@q-leap.de>

---
drivers/scsi/scsi_error.c | 65 +++++++++++++++++++++++++++++++---------------
1 file changed, 45 insertions(+), 20 deletions(-)

Index: linux-2.6/drivers/scsi/scsi_error.c
===================================================================
--- linux-2.6.orig/drivers/scsi/scsi_error.c
+++ linux-2.6/drivers/scsi/scsi_error.c
@@ -1271,6 +1271,47 @@ int scsi_noretry_cmd(struct scsi_cmnd *s
}

/**
+ * maybe_retry - decide if to retry a scsi-command or to return an error
+ * @scmd: scsi command to examine
+ * @retry_code ADD_TO_MLQUEUE or NEEDS_RETRY
+ *
+ * Notes:
+ * Returning FAILED will activate the error handler,
+ * returning SUCCESS will fail the scsi command
+ **/
+static int maybe_retry(struct scsi_cmnd *scmd, int retry_code)
+{
+ struct scsi_device *sdev = scmd->device;
+
+ scmd->retries++;
+
+ /* we requeue for retry because the error was retryable, and
+ * the request was not marked fast fail. Note that above,
+ * even if the request is marked fast fail, we still requeue
+ * for queue congestion conditions (QUEUE_FULL or BUSY) */
+ if (scmd->retries <= scmd->allowed
+ && !blk_noretry_request(scmd->request)) {
+ return retry_code;
+ } else if (scmd->retries <= scmd->allowed + 1
+ && !blk_noretry_request(scmd->request)
+ && retry_code == ADD_TO_MLQUEUE
+ && scmd->allowed > 1) {
+ /*
+ * activate error recovery
+ */
+ sdev_printk(KERN_INFO, sdev, "scmd retry %d/%d\n",
+ scmd->retries, scmd->allowed + 1);
+ return FAILED;
+ } else {
+ /*
+ * no more retries - report this one back to upper level.
+ */
+ return SUCCESS;
+ }
+}
+
+
+/**
* scsi_decide_disposition - Disposition a cmd on return from LLD.
* @scmd: SCSI cmd to examine.
*
@@ -1336,7 +1377,7 @@ int scsi_decide_disposition(struct scsi_
* and not get stuck in a loop.
*/
case DID_SOFT_ERROR:
- goto maybe_retry;
+ return maybe_retry(scmd, ADD_TO_MLQUEUE);
case DID_IMM_RETRY:
return NEEDS_RETRY;

@@ -1350,7 +1391,7 @@ int scsi_decide_disposition(struct scsi_
* based on its timers and recovery capablilities if
* there are enough retries.
*/
- goto maybe_retry;
+ return maybe_retry(scmd, NEEDS_RETRY);
case DID_TRANSPORT_FAILFAST:
/*
* The transport decided to failfast the IO (most likely
@@ -1369,7 +1410,7 @@ int scsi_decide_disposition(struct scsi_

case DID_BUS_BUSY:
case DID_PARITY:
- goto maybe_retry;
+ return maybe_retry(scmd, NEEDS_RETRY);
case DID_TIME_OUT:
/*
* when we scan the bus, we get timeout messages for
@@ -1418,7 +1459,7 @@ int scsi_decide_disposition(struct scsi_
case CHECK_CONDITION:
rtn = scsi_check_sense(scmd);
if (rtn == NEEDS_RETRY)
- goto maybe_retry;
+ return maybe_retry(scmd, NEEDS_RETRY);
/* if rtn == FAILED, we have no sense information;
* returning FAILED will wake the error handler thread
* to collect the sense and redo the decide
@@ -1441,22 +1482,6 @@ int scsi_decide_disposition(struct scsi_
return FAILED;
}
return FAILED;
-
- maybe_retry:
-
- /* we requeue for retry because the error was retryable, and
- * the request was not marked fast fail. Note that above,
- * even if the request is marked fast fail, we still requeue
- * for queue congestion conditions (QUEUE_FULL or BUSY) */
- if ((++scmd->retries) <= scmd->allowed
- && !scsi_noretry_cmd(scmd)) {
- return NEEDS_RETRY;
- } else {
- /*
- * no more retries - report this one back to upper level.
- */
- return SUCCESS;
- }
}

/**