aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-05-15 07:57:20 -0400
committerTejun Heo <htejun@gmail.com>2006-05-15 07:57:20 -0400
commitee7863bc68fa6ad6fe7cfcc0e5ebe9efe0c0664e (patch)
tree2ca442445403be0101abf0592df3c625633dd49d
parent89f48c4d67dd875cf2216d4402bf77eda41fbdd9 (diff)
[PATCH] SCSI: implement shost->host_eh_scheduled
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>
-rw-r--r--drivers/scsi/scsi_error.c3
-rw-r--r--drivers/scsi/scsi_lib.c2
-rw-r--r--drivers/scsi/scsi_priv.h1
-rw-r--r--include/scsi/scsi_eh.h1
-rw-r--r--include/scsi/scsi_host.h1
5 files changed, 5 insertions, 3 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 1c75646f9689..9ca71cbefce0 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -56,6 +56,7 @@ void scsi_eh_wakeup(struct Scsi_Host *shost)
56 printk("Waking error handler thread\n")); 56 printk("Waking error handler thread\n"));
57 } 57 }
58} 58}
59EXPORT_SYMBOL_GPL(scsi_eh_wakeup);
59 60
60/** 61/**
61 * scsi_eh_scmd_add - add scsi cmd to error handling. 62 * scsi_eh_scmd_add - add scsi cmd to error handling.
@@ -1517,7 +1518,7 @@ int scsi_error_handler(void *data)
1517 */ 1518 */
1518 set_current_state(TASK_INTERRUPTIBLE); 1519 set_current_state(TASK_INTERRUPTIBLE);
1519 while (!kthread_should_stop()) { 1520 while (!kthread_should_stop()) {
1520 if (shost->host_failed == 0 || 1521 if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
1521 shost->host_failed != shost->host_busy) { 1522 shost->host_failed != shost->host_busy) {
1522 SCSI_LOG_ERROR_RECOVERY(1, 1523 SCSI_LOG_ERROR_RECOVERY(1,
1523 printk("Error handler scsi_eh_%d sleeping\n", 1524 printk("Error handler scsi_eh_%d sleeping\n",
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 7b0f9a3810d2..c55d195b6f4f 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -566,7 +566,7 @@ void scsi_device_unbusy(struct scsi_device *sdev)
566 spin_lock_irqsave(shost->host_lock, flags); 566 spin_lock_irqsave(shost->host_lock, flags);
567 shost->host_busy--; 567 shost->host_busy--;
568 if (unlikely(scsi_host_in_recovery(shost) && 568 if (unlikely(scsi_host_in_recovery(shost) &&
569 shost->host_failed)) 569 (shost->host_failed || shost->host_eh_scheduled)))
570 scsi_eh_wakeup(shost); 570 scsi_eh_wakeup(shost);
571 spin_unlock(shost->host_lock); 571 spin_unlock(shost->host_lock);
572 spin_lock(sdev->request_queue->queue_lock); 572 spin_lock(sdev->request_queue->queue_lock);
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 27c48274e8cb..0b39081113be 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -63,7 +63,6 @@ extern int scsi_delete_timer(struct scsi_cmnd *);
63extern void scsi_times_out(struct scsi_cmnd *cmd); 63extern void scsi_times_out(struct scsi_cmnd *cmd);
64extern int scsi_error_handler(void *host); 64extern int scsi_error_handler(void *host);
65extern int scsi_decide_disposition(struct scsi_cmnd *cmd); 65extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
66extern void scsi_eh_wakeup(struct Scsi_Host *shost);
67extern int scsi_eh_scmd_add(struct scsi_cmnd *, int); 66extern int scsi_eh_scmd_add(struct scsi_cmnd *, int);
68 67
69/* scsi_lib.c */ 68/* scsi_lib.c */
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index d160880b2a87..212c983a6a18 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -35,6 +35,7 @@ static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr)
35} 35}
36 36
37 37
38extern void scsi_eh_wakeup(struct Scsi_Host *shost);
38extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, 39extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
39 struct list_head *done_q); 40 struct list_head *done_q);
40extern void scsi_eh_flush_done_q(struct list_head *done_q); 41extern void scsi_eh_flush_done_q(struct list_head *done_q);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index de6ce541a046..a42efd6e4be8 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -472,6 +472,7 @@ struct Scsi_Host {
472 */ 472 */
473 unsigned int host_busy; /* commands actually active on low-level */ 473 unsigned int host_busy; /* commands actually active on low-level */
474 unsigned int host_failed; /* commands that failed. */ 474 unsigned int host_failed; /* commands that failed. */
475 unsigned int host_eh_scheduled; /* EH scheduled without command */
475 476
476 unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ 477 unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
477 int resetting; /* if set, it means that last_reset is a valid value */ 478 int resetting; /* if set, it means that last_reset is a valid value */