diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 815e7d63f3e2..f89de23a6807 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -291,11 +291,48 @@ static void scsi_eh_inc_host_failed(struct rcu_head *head)
spin_unlock_irqrestore(shost->host_lock, flags);
}
+#define SCSI_EH_NO_HANDLER 1
/**
* scsi_eh_scmd_add - add scsi cmd to error handling.
* @scmd: scmd to run eh on.
*/
-void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
+static void __scsi_eh_scmd_add(struct scsi_cmnd *scmd)
+void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
+{
+ struct scsi_device *sdev = scmd->device;
+ struct scsi_target *starget = scsi_target(sdev);
+ struct Scsi_Host *shost = sdev->host;
+
+ if (unlikely(scsi_host_in_recovery(shost)))
+ __scsi_eh_scmd_add(scmd);
+
+ if (unlikely(scsi_target_in_recovery(starget)))
+ if (__scsi_eh_scmd_add_starget(scmd))
+ __scsi_eh_scmd_add(scmd);
+
+ if (__scsi_eh_scmd_add_sdev(scmd))
+ if (__scsi_eh_scmd_add_starget(scmd))
+ __scsi_eh_scmd_add(scmd);
+}
+static inline int scsi_device_in_recovery(struct scsi_device *sdev)
+{
+ struct scsi_device_eh *eh = sdev->eh;
+
+ if (eh && eh->is_busy)
+ return eh->is_busy(sdev);
+ return 0;
+}
+static inline int scsi_target_in_recovery(struct scsi_target *starget)
+{
+ struct scsi_target_eh *eh = starget->eh;
+
+ if (eh && eh->is_busy)
+ return eh->is_busy(starget);
+ return 0;
+}
+struct scsi_device_eh {
+ /*
+ * add scsi command to error handler so it would be handuled by
+ * driver's error handle strategy
+ */
+ void (*add_cmnd)(struct scsi_cmnd *scmd);
+
+ /*
+ * to judge if the device is busy handling errors, called before
+ * dispatch scsi cmnd
+ *
+ * return 0 if it's ready to accepy scsi cmnd
+ * return 0 if it's in error handle, command's would not be dispatched
+ */
+ int (*is_busy)(struct scsi_device *sdev);
+
+ /*
+ * wakeup device's error handle
+ *
+ * usually the error handler strategy would not run at once when
+ * error command is added. This function would be called when any
+ * scsi cmnd is finished or when scsi cmnd is added.
+ */
+ int (*wakeup)(struct scsi_device *sdev);
+
+ /*
+ * data entity for device specific error handler
+ */
+ unsigned long driver_data[];
+};