]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/scsi_lib.c
[SCSI] simplify scsi_io_completion()
[linux-2.6-omap-h63xx.git] / drivers / scsi / scsi_lib.c
index 148d3af92aefad04fa42c48780ba4138e8033e59..ecfbbd30dce530ac24830f56f293a13c85cdeef3 100644 (file)
@@ -875,16 +875,24 @@ static void scsi_end_bidi_request(struct scsi_cmnd *cmd)
  *              (the normal case for most drivers), we don't need
  *              the logic to deal with cleaning up afterwards.
  *
- *             We must do one of several things here:
- *
- *             a) Call scsi_end_request.  This will finish off the
- *                specified number of sectors.  If we are done, the
- *                command block will be released, and the queue
- *                function will be goosed.  If we are not done, then
- *                scsi_end_request will directly goose the queue.
- *
- *             b) We can just use scsi_requeue_command() here.  This would
- *                be used if we just wanted to retry, for example.
+ *             We must call scsi_end_request().  This will finish off
+ *             the specified number of sectors.  If we are done, the
+ *             command block will be released and the queue function
+ *             will be goosed.  If we are not done then we have to
+ *             figure out what to do next:
+ *
+ *             a) We can call scsi_requeue_command().  The request
+ *                will be unprepared and put back on the queue.  Then
+ *                a new command will be created for it.  This should
+ *                be used if we made forward progress, or if we want
+ *                to switch from READ(10) to READ(6) for example.
+ *
+ *             b) We can call scsi_queue_insert().  The request will
+ *                be put back on the queue and retried using the same
+ *                command as before, possibly after a delay.
+ *
+ *             c) We can call blk_end_request() with -EIO to fail
+ *                the remainder of the request.
  */
 void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 {
@@ -896,6 +904,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
        struct scsi_sense_hdr sshdr;
        int sense_valid = 0;
        int sense_deferred = 0;
+       enum {ACTION_FAIL, ACTION_REPREP, ACTION_RETRY,
+             ACTION_DELAYED_RETRY} action;
+       char *description = NULL;
 
        if (result) {
                sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
@@ -947,10 +958,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                return;
        this_count = blk_rq_bytes(req);
 
-       /* good_bytes = 0, or (inclusive) there were leftovers and
-        * result = 0, so scsi_end_request couldn't retry.
-        */
-       if (sense_valid && !sense_deferred) {
+       if (host_byte(result) == DID_RESET) {
+               /* Third party bus reset or reset for error recovery
+                * reasons.  Just retry the command and see what
+                * happens.
+                */
+               action = ACTION_RETRY;
+       } else if (sense_valid && !sense_deferred) {
                switch (sshdr.sense_key) {
                case UNIT_ATTENTION:
                        if (cmd->device->removable) {
@@ -958,16 +972,15 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                                 * and quietly refuse further access.
                                 */
                                cmd->device->changed = 1;
-                               scsi_end_request(cmd, -EIO, this_count, 1);
-                               return;
+                               description = "Media Changed";
+                               action = ACTION_FAIL;
                        } else {
                                /* Must have been a power glitch, or a
                                 * bus reset.  Could not have been a
                                 * media change, so we just retry the
-                                * request and see what happens.
+                                * command and see what happens.
                                 */
-                               scsi_requeue_command(q, cmd);
-                               return;
+                               action = ACTION_RETRY;
                        }
                        break;
                case ILLEGAL_REQUEST:
@@ -983,21 +996,18 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                            sshdr.asc == 0x20 && sshdr.ascq == 0x00) &&
                            (cmd->cmnd[0] == READ_10 ||
                             cmd->cmnd[0] == WRITE_10)) {
+                               /* This will issue a new 6-byte command. */
                                cmd->device->use_10_for_rw = 0;
-                               /* This will cause a retry with a
-                                * 6-byte command.
-                                */
-                               scsi_requeue_command(q, cmd);
-                       } else if (sshdr.asc == 0x10) /* DIX */
-                               scsi_end_request(cmd, -EIO, this_count, 0);
-                       else
-                               scsi_end_request(cmd, -EIO, this_count, 1);
-                       return;
+                               action = ACTION_REPREP;
+                       } else
+                               action = ACTION_FAIL;
+                       break;
                case ABORTED_COMMAND:
                        if (sshdr.asc == 0x10) { /* DIF */
-                               scsi_end_request(cmd, -EIO, this_count, 0);
-                               return;
-                       }
+                               action = ACTION_FAIL;
+                               description = "Data Integrity Failure";
+                       } else
+                               action = ACTION_RETRY;
                        break;
                case NOT_READY:
                        /* If the device is in the process of becoming
@@ -1012,49 +1022,57 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                                case 0x07: /* operation in progress */
                                case 0x08: /* Long write in progress */
                                case 0x09: /* self test in progress */
-                                       scsi_requeue_command(q, cmd);
-                                       return;
-                               default:
+                                       action = ACTION_DELAYED_RETRY;
                                        break;
                                }
+                       } else {
+                               description = "Device not ready";
+                               action = ACTION_FAIL;
                        }
-                       if (!(req->cmd_flags & REQ_QUIET))
-                               scsi_cmd_print_sense_hdr(cmd,
-                                                        "Device not ready",
-                                                        &sshdr);
-
-                       scsi_end_request(cmd, -EIO, this_count, 1);
-                       return;
+                       break;
                case VOLUME_OVERFLOW:
-                       if (!(req->cmd_flags & REQ_QUIET)) {
-                               scmd_printk(KERN_INFO, cmd,
-                                           "Volume overflow, CDB: ");
-                               __scsi_print_command(cmd->cmnd);
-                               scsi_print_sense("", cmd);
-                       }
                        /* See SSC3rXX or current. */
-                       scsi_end_request(cmd, -EIO, this_count, 1);
-                       return;
+                       action = ACTION_FAIL;
+                       break;
                default:
+                       description = "Unhandled sense code";
+                       action = ACTION_FAIL;
                        break;
                }
+       } else {
+               description = "Unhandled error code";
+               action = ACTION_FAIL;
        }
-       if (host_byte(result) == DID_RESET) {
-               /* Third party bus reset or reset for error recovery
-                * reasons.  Just retry the request and see what
-                * happens.
-                */
-               scsi_requeue_command(q, cmd);
-               return;
-       }
-       if (result) {
+
+       switch (action) {
+       case ACTION_FAIL:
+               /* Give up and fail the remainder of the request */
                if (!(req->cmd_flags & REQ_QUIET)) {
+                       if (description)
+                               scmd_printk(KERN_INFO, cmd, "%s",
+                                           description);
                        scsi_print_result(cmd);
                        if (driver_byte(result) & DRIVER_SENSE)
                                scsi_print_sense("", cmd);
                }
+               blk_end_request(req, -EIO, blk_rq_bytes(req));
+               scsi_next_command(cmd);
+               break;
+       case ACTION_REPREP:
+               /* Unprep the request and put it back at the head of the queue.
+                * A new command will be prepared and issued.
+                */
+               scsi_requeue_command(q, cmd);
+               break;
+       case ACTION_RETRY:
+               /* Retry the same command immediately */
+               scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY);
+               break;
+       case ACTION_DELAYED_RETRY:
+               /* Retry the same command after a delay */
+               scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+               break;
        }
-       scsi_end_request(cmd, -EIO, this_count, !result);
 }
 
 static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb,