]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/scsi_error.c
[SCSI] scsi_error: Fix lost EH commands
[linux-2.6-omap-h63xx.git] / drivers / scsi / scsi_error.c
index 2dce06a58c08292ab42dc001b8f84aac4605d600..b8edcf5b54511be2f10fc9690fd01fbdd4dfb99e 100644 (file)
@@ -457,6 +457,128 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
                complete(eh_action);
 }
 
+/**
+ * scsi_try_host_reset - ask host adapter to reset itself
+ * @scmd:      SCSI cmd to send hsot reset.
+ **/
+static int scsi_try_host_reset(struct scsi_cmnd *scmd)
+{
+       unsigned long flags;
+       int rtn;
+
+       SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n",
+                                         __FUNCTION__));
+
+       if (!scmd->device->host->hostt->eh_host_reset_handler)
+               return FAILED;
+
+       rtn = scmd->device->host->hostt->eh_host_reset_handler(scmd);
+
+       if (rtn == SUCCESS) {
+               if (!scmd->device->host->hostt->skip_settle_delay)
+                       ssleep(HOST_RESET_SETTLE_TIME);
+               spin_lock_irqsave(scmd->device->host->host_lock, flags);
+               scsi_report_bus_reset(scmd->device->host,
+                                     scmd_channel(scmd));
+               spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+       }
+
+       return rtn;
+}
+
+/**
+ * scsi_try_bus_reset - ask host to perform a bus reset
+ * @scmd:      SCSI cmd to send bus reset.
+ **/
+static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
+{
+       unsigned long flags;
+       int rtn;
+
+       SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n",
+                                         __FUNCTION__));
+
+       if (!scmd->device->host->hostt->eh_bus_reset_handler)
+               return FAILED;
+
+       rtn = scmd->device->host->hostt->eh_bus_reset_handler(scmd);
+
+       if (rtn == SUCCESS) {
+               if (!scmd->device->host->hostt->skip_settle_delay)
+                       ssleep(BUS_RESET_SETTLE_TIME);
+               spin_lock_irqsave(scmd->device->host->host_lock, flags);
+               scsi_report_bus_reset(scmd->device->host,
+                                     scmd_channel(scmd));
+               spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+       }
+
+       return rtn;
+}
+
+/**
+ * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev
+ * @scmd:      SCSI cmd used to send BDR
+ *
+ * Notes:
+ *    There is no timeout for this operation.  if this operation is
+ *    unreliable for a given host, then the host itself needs to put a
+ *    timer on it, and set the host back to a consistent state prior to
+ *    returning.
+ **/
+static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
+{
+       int rtn;
+
+       if (!scmd->device->host->hostt->eh_device_reset_handler)
+               return FAILED;
+
+       rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd);
+       if (rtn == SUCCESS) {
+               scmd->device->was_reset = 1;
+               scmd->device->expecting_cc_ua = 1;
+       }
+
+       return rtn;
+}
+
+static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
+{
+       if (!scmd->device->host->hostt->eh_abort_handler)
+               return FAILED;
+
+       return scmd->device->host->hostt->eh_abort_handler(scmd);
+}
+
+/**
+ * scsi_try_to_abort_cmd - Ask host to abort a running command.
+ * @scmd:      SCSI cmd to abort from Lower Level.
+ *
+ * Notes:
+ *    This function will not return until the user's completion function
+ *    has been called.  there is no timeout on this operation.  if the
+ *    author of the low-level driver wishes this operation to be timed,
+ *    they can provide this facility themselves.  helper functions in
+ *    scsi_error.c can be supplied to make this easier to do.
+ **/
+static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
+{
+       /*
+        * scsi_done was called just after the command timed out and before
+        * we had a chance to process it. (db)
+        */
+       if (scmd->serial_number == 0)
+               return SUCCESS;
+       return __scsi_try_to_abort_cmd(scmd);
+}
+
+static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
+{
+       if (__scsi_try_to_abort_cmd(scmd) != SUCCESS)
+               if (scsi_try_bus_device_reset(scmd) != SUCCESS)
+                       if (scsi_try_bus_reset(scmd) != SUCCESS)
+                               scsi_try_host_reset(scmd);
+}
+
 /**
  * scsi_send_eh_cmnd  - submit a scsi command as part of error recory
  * @scmd:       SCSI command structure to hijack
@@ -584,13 +706,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
                        break;
                }
        } else {
-               /*
-                * FIXME(eric) - we are not tracking whether we could
-                * abort a timed out command or not.  not sure how
-                * we should treat them differently anyways.
-                */
-               if (shost->hostt->eh_abort_handler)
-                       shost->hostt->eh_abort_handler(scmd);
+               scsi_abort_eh_cmnd(scmd);
                rtn = FAILED;
        }
 
@@ -722,31 +838,6 @@ int scsi_eh_get_sense(struct list_head *work_q,
 }
 EXPORT_SYMBOL_GPL(scsi_eh_get_sense);
 
-/**
- * scsi_try_to_abort_cmd - Ask host to abort a running command.
- * @scmd:      SCSI cmd to abort from Lower Level.
- *
- * Notes:
- *    This function will not return until the user's completion function
- *    has been called.  there is no timeout on this operation.  if the
- *    author of the low-level driver wishes this operation to be timed,
- *    they can provide this facility themselves.  helper functions in
- *    scsi_error.c can be supplied to make this easier to do.
- **/
-static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
-{
-       if (!scmd->device->host->hostt->eh_abort_handler)
-               return FAILED;
-
-       /*
-        * scsi_done was called just after the command timed out and before
-        * we had a chance to process it. (db)
-        */
-       if (scmd->serial_number == 0)
-               return SUCCESS;
-       return scmd->device->host->hostt->eh_abort_handler(scmd);
-}
-
 /**
  * scsi_eh_tur - Send TUR to device.
  * @scmd:      Scsi cmd to send TUR
@@ -820,32 +911,6 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
        return list_empty(work_q);
 }
 
-/**
- * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev
- * @scmd:      SCSI cmd used to send BDR       
- *
- * Notes:
- *    There is no timeout for this operation.  if this operation is
- *    unreliable for a given host, then the host itself needs to put a
- *    timer on it, and set the host back to a consistent state prior to
- *    returning.
- **/
-static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
-{
-       int rtn;
-
-       if (!scmd->device->host->hostt->eh_device_reset_handler)
-               return FAILED;
-
-       rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd);
-       if (rtn == SUCCESS) {
-               scmd->device->was_reset = 1;
-               scmd->device->expecting_cc_ua = 1;
-       }
-
-       return rtn;
-}
-
 /**
  * scsi_eh_try_stu - Send START_UNIT to device.
  * @scmd:      Scsi cmd to send START_UNIT
@@ -976,64 +1041,6 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
        return list_empty(work_q);
 }
 
-/**
- * scsi_try_bus_reset - ask host to perform a bus reset
- * @scmd:      SCSI cmd to send bus reset.
- **/
-static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
-{
-       unsigned long flags;
-       int rtn;
-
-       SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n",
-                                         __FUNCTION__));
-
-       if (!scmd->device->host->hostt->eh_bus_reset_handler)
-               return FAILED;
-
-       rtn = scmd->device->host->hostt->eh_bus_reset_handler(scmd);
-
-       if (rtn == SUCCESS) {
-               if (!scmd->device->host->hostt->skip_settle_delay)
-                       ssleep(BUS_RESET_SETTLE_TIME);
-               spin_lock_irqsave(scmd->device->host->host_lock, flags);
-               scsi_report_bus_reset(scmd->device->host,
-                                     scmd_channel(scmd));
-               spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
-       }
-
-       return rtn;
-}
-
-/**
- * scsi_try_host_reset - ask host adapter to reset itself
- * @scmd:      SCSI cmd to send hsot reset.
- **/
-static int scsi_try_host_reset(struct scsi_cmnd *scmd)
-{
-       unsigned long flags;
-       int rtn;
-
-       SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n",
-                                         __FUNCTION__));
-
-       if (!scmd->device->host->hostt->eh_host_reset_handler)
-               return FAILED;
-
-       rtn = scmd->device->host->hostt->eh_host_reset_handler(scmd);
-
-       if (rtn == SUCCESS) {
-               if (!scmd->device->host->hostt->skip_settle_delay)
-                       ssleep(HOST_RESET_SETTLE_TIME);
-               spin_lock_irqsave(scmd->device->host->host_lock, flags);
-               scsi_report_bus_reset(scmd->device->host,
-                                     scmd_channel(scmd));
-               spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
-       }
-
-       return rtn;
-}
-
 /**
  * scsi_eh_bus_reset - send a bus reset 
  * @shost:     scsi host being recovered.