[PATCH] SCSI: implement shost->host_eh_scheduled
authorTejun Heo <htejun@gmail.com>
Mon, 15 May 2006 11:57:20 +0000 (20:57 +0900)
committerTejun Heo <htejun@gmail.com>
Mon, 15 May 2006 11:57:20 +0000 (20:57 +0900)
libata needs to invoke EH without scmd.  This patch adds
shost->host_eh_scheduled to implement such behavior.

Currently the only user of this feature is libata and no general
interface is defined.  This patch simply adds handling for
host_eh_scheduled where needed and exports scsi_eh_wakeup() to
modules.  The rest is upto libata.  This is the result of the
following discussion.

http://thread.gmane.org/gmane.linux.scsi/23853/focus=9760

In short, SCSI host is not supposed to know about exceptions unrelated
to specific device or command.  Such exceptions should be handled by
transport layer proper.  However, the distinction is not essential to
ATA and libata is planning to depart from SCSI, so, for the time
being, libata will be using SCSI EH to handle such exceptions.

Signed-off-by: Tejun Heo <htejun@gmail.com>
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
include/scsi/scsi_eh.h
include/scsi/scsi_host.h

index 1c75646f9689da6a9d2160744e7e402f8ac27b50..9ca71cbefce0bb4125afccc5778f8b25ea0a4f30 100644 (file)
@@ -56,6 +56,7 @@ void scsi_eh_wakeup(struct Scsi_Host *shost)
                                printk("Waking error handler thread\n"));
        }
 }
+EXPORT_SYMBOL_GPL(scsi_eh_wakeup);
 
 /**
  * scsi_eh_scmd_add - add scsi cmd to error handling.
@@ -1517,7 +1518,7 @@ int scsi_error_handler(void *data)
         */
        set_current_state(TASK_INTERRUPTIBLE);
        while (!kthread_should_stop()) {
-               if (shost->host_failed == 0 ||
+               if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
                    shost->host_failed != shost->host_busy) {
                        SCSI_LOG_ERROR_RECOVERY(1,
                                printk("Error handler scsi_eh_%d sleeping\n",
index 7b0f9a3810d2fba1ac0794f820193e9a832e82ae..c55d195b6f4f2f6e933df97b14d89ffc17308649 100644 (file)
@@ -566,7 +566,7 @@ void scsi_device_unbusy(struct scsi_device *sdev)
        spin_lock_irqsave(shost->host_lock, flags);
        shost->host_busy--;
        if (unlikely(scsi_host_in_recovery(shost) &&
-                    shost->host_failed))
+                    (shost->host_failed || shost->host_eh_scheduled)))
                scsi_eh_wakeup(shost);
        spin_unlock(shost->host_lock);
        spin_lock(sdev->request_queue->queue_lock);
index 27c48274e8cb11f1b26e2744699bdb4182116dae..0b39081113be08734461ff8f24c230956d6332dd 100644 (file)
@@ -63,7 +63,6 @@ extern int scsi_delete_timer(struct scsi_cmnd *);
 extern void scsi_times_out(struct scsi_cmnd *cmd);
 extern int scsi_error_handler(void *host);
 extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
-extern void scsi_eh_wakeup(struct Scsi_Host *shost);
 extern int scsi_eh_scmd_add(struct scsi_cmnd *, int);
 
 /* scsi_lib.c */
index d160880b2a8798f18d3c0772ef84281e9d0bb6bc..212c983a6a18f8f83cbc63bf03c5e6104c50e8a9 100644 (file)
@@ -35,6 +35,7 @@ static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr)
 }
 
 
+extern void scsi_eh_wakeup(struct Scsi_Host *shost);
 extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
                               struct list_head *done_q);
 extern void scsi_eh_flush_done_q(struct list_head *done_q);
index de6ce541a046c551b065fa6737b949c4bee6fff2..a42efd6e4be88ec79890a4b404f8f02cf4ec99fc 100644 (file)
@@ -472,6 +472,7 @@ struct Scsi_Host {
         */
        unsigned int host_busy;            /* commands actually active on low-level */
        unsigned int host_failed;          /* commands that failed. */
+       unsigned int host_eh_scheduled;    /* EH scheduled without command */
     
        unsigned short host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
        int resetting; /* if set, it means that last_reset is a valid value */