|
@@ -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.
|