+ * 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
+ * @cmnd: CDB to send
+ * @cmnd_size: size in bytes of @cmnd
+ * @timeout: timeout for this request
+ * @copy_sense: request sense data if set to 1
+ *
+ * This function is used to send a scsi command down to a target device
+ * as part of the error recovery process. If @copy_sense is 0 the command
+ * sent must be one that does not transfer any data. If @copy_sense is 1
+ * the command must be REQUEST_SENSE and this functions copies out the
+ * sense buffer it got into @scmd->sense_buffer.