Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux...
[pandora-kernel.git] / drivers / scsi / scsi_error.c
index 1c7d993..6683d59 100644 (file)
@@ -57,6 +57,28 @@ void scsi_eh_wakeup(struct Scsi_Host *shost)
        }
 }
 
+/**
+ * scsi_schedule_eh - schedule EH for SCSI host
+ * @shost:     SCSI host to invoke error handling on.
+ *
+ * Schedule SCSI EH without scmd.
+ **/
+void scsi_schedule_eh(struct Scsi_Host *shost)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(shost->host_lock, flags);
+
+       if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 ||
+           scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) {
+               shost->host_eh_scheduled++;
+               scsi_eh_wakeup(shost);
+       }
+
+       spin_unlock_irqrestore(shost->host_lock, flags);
+}
+EXPORT_SYMBOL_GPL(scsi_schedule_eh);
+
 /**
  * scsi_eh_scmd_add - add scsi cmd to error handling.
  * @scmd:      scmd to run eh on.
@@ -1515,7 +1537,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",
@@ -1650,7 +1672,9 @@ int
 scsi_reset_provider(struct scsi_device *dev, int flag)
 {
        struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL);
+       struct Scsi_Host *shost = dev->host;
        struct request req;
+       unsigned long flags;
        int rtn;
 
        scmd->request = &req;
@@ -1677,6 +1701,10 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
         */
        scmd->pid                       = 0;
 
+       spin_lock_irqsave(shost->host_lock, flags);
+       shost->tmf_in_progress = 1;
+       spin_unlock_irqrestore(shost->host_lock, flags);
+
        switch (flag) {
        case SCSI_TRY_RESET_DEVICE:
                rtn = scsi_try_bus_device_reset(scmd);
@@ -1695,6 +1723,22 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
                rtn = FAILED;
        }
 
+       spin_lock_irqsave(shost->host_lock, flags);
+       shost->tmf_in_progress = 0;
+       spin_unlock_irqrestore(shost->host_lock, flags);
+
+       /*
+        * be sure to wake up anyone who was sleeping or had their queue
+        * suspended while we performed the TMF.
+        */
+       SCSI_LOG_ERROR_RECOVERY(3,
+               printk("%s: waking up host to restart after TMF\n",
+               __FUNCTION__));
+
+       wake_up(&shost->host_wait);
+
+       scsi_run_host_queues(shost);
+
        scsi_next_command(scmd);
        return rtn;
 }