]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/scsi_lib.c
Merge commit 'kumar/kumar-next' into next
[linux-2.6-omap-h63xx.git] / drivers / scsi / scsi_lib.c
index 148d3af92aefad04fa42c48780ba4138e8033e59..f2f51e0333eb3b8c8cd1b30fcffe22dd92a03284 100644 (file)
@@ -183,13 +183,15 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
  * @timeout:   request timeout in seconds
  * @retries:   number of times to retry request
  * @flags:     or into request flags;
+ * @resid:     optional residual length
  *
  * returns the req->errors value which is the scsi_cmnd result
  * field.
  */
 int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
                 int data_direction, void *buffer, unsigned bufflen,
-                unsigned char *sense, int timeout, int retries, int flags)
+                unsigned char *sense, int timeout, int retries, int flags,
+                int *resid)
 {
        struct request *req;
        int write = (data_direction == DMA_TO_DEVICE);
@@ -224,6 +226,8 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
        if (unlikely(req->data_len > 0 && req->data_len <= bufflen))
                memset(buffer + (bufflen - req->data_len), 0, req->data_len);
 
+       if (resid)
+               *resid = req->data_len;
        ret = req->errors;
  out:
        blk_put_request(req);
@@ -235,7 +239,8 @@ EXPORT_SYMBOL(scsi_execute);
 
 int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
                     int data_direction, void *buffer, unsigned bufflen,
-                    struct scsi_sense_hdr *sshdr, int timeout, int retries)
+                    struct scsi_sense_hdr *sshdr, int timeout, int retries,
+                    int *resid)
 {
        char *sense = NULL;
        int result;
@@ -246,7 +251,7 @@ int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
                        return DRIVER_ERROR << 24;
        }
        result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen,
-                             sense, timeout, retries, 0);
+                             sense, timeout, retries, 0, resid);
        if (sshdr)
                scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr);
 
@@ -875,16 +880,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:
+ *             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) 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.
+ *             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 just use scsi_requeue_command() here.  This would
- *                be used if we just wanted to retry, 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 +909,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 +963,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 +977,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 +1001,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 +1027,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,
@@ -1998,7 +2021,7 @@ scsi_mode_select(struct scsi_device *sdev, int pf, int sp, int modepage,
        }
 
        ret = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, real_buffer, len,
-                              sshdr, timeout, retries);
+                              sshdr, timeout, retries, NULL);
        kfree(real_buffer);
        return ret;
 }
@@ -2063,7 +2086,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
        memset(buffer, 0, len);
 
        result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
-                                 sshdr, timeout, retries);
+                                 sshdr, timeout, retries, NULL);
 
        /* This code looks awful: what it's doing is making sure an
         * ILLEGAL REQUEST sense return identifies the actual command
@@ -2145,7 +2168,7 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
        /* try to eat the UNIT_ATTENTION if there are enough retries */
        do {
                result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
-                                         timeout, retries);
+                                         timeout, retries, NULL);
                if (sdev->removable && scsi_sense_valid(sshdr) &&
                    sshdr->sense_key == UNIT_ATTENTION)
                        sdev->changed = 1;