Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac
[deliverable/linux.git] / drivers / scsi / scsi_error.c
index 386f0c53bea7e17cf2b74fe29af5d1d7176c25b9..4a6381c87253ec4be307eb47dc8d1ff6ebad4dc3 100644 (file)
@@ -664,7 +664,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
 }
 
 /**
- * scsi_eh_prep_cmnd  - Save a scsi command info as part of error recory
+ * scsi_eh_prep_cmnd  - Save a scsi command info as part of error recovery
  * @scmd:       SCSI command structure to hijack
  * @ses:        structure to save restore information
  * @cmnd:       CDB to send. Can be NULL if no new cmnd is needed
@@ -739,7 +739,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
 EXPORT_SYMBOL(scsi_eh_prep_cmnd);
 
 /**
- * scsi_eh_restore_cmnd  - Restore a scsi command info as part of error recory
+ * scsi_eh_restore_cmnd  - Restore a scsi command info as part of error recovery
  * @scmd:       SCSI command structure to restore
  * @ses:        saved information from a coresponding call to scsi_eh_prep_cmnd
  *
@@ -762,7 +762,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
 EXPORT_SYMBOL(scsi_eh_restore_cmnd);
 
 /**
- * scsi_send_eh_cmnd  - submit a scsi command as part of error recory
+ * scsi_send_eh_cmnd  - submit a scsi command as part of error recovery
  * @scmd:       SCSI command structure to hijack
  * @cmnd:       CDB to send
  * @cmnd_size:  size in bytes of @cmnd
@@ -1687,6 +1687,20 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
         * requests are started.
         */
        scsi_run_host_queues(shost);
+
+       /*
+        * if eh is active and host_eh_scheduled is pending we need to re-run
+        * recovery.  we do this check after scsi_run_host_queues() to allow
+        * everything pent up since the last eh run a chance to make forward
+        * progress before we sync again.  Either we'll immediately re-run
+        * recovery or scsi_device_unbusy() will wake us again when these
+        * pending commands complete.
+        */
+       spin_lock_irqsave(shost->host_lock, flags);
+       if (shost->host_eh_scheduled)
+               if (scsi_host_set_state(shost, SHOST_RECOVERY))
+                       WARN_ON(scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY));
+       spin_unlock_irqrestore(shost->host_lock, flags);
 }
 
 /**
@@ -1804,15 +1818,14 @@ int scsi_error_handler(void *data)
         * We never actually get interrupted because kthread_run
         * disables signal delivery for the created thread.
         */
-       set_current_state(TASK_INTERRUPTIBLE);
        while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
                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",
                                        shost->host_no));
                        schedule();
-                       set_current_state(TASK_INTERRUPTIBLE);
                        continue;
                }
 
@@ -1849,7 +1862,6 @@ int scsi_error_handler(void *data)
                scsi_restart_operations(shost);
                if (!shost->eh_noresume)
                        scsi_autopm_put_host(shost);
-               set_current_state(TASK_INTERRUPTIBLE);
        }
        __set_current_state(TASK_RUNNING);
 
This page took 0.02597 seconds and 5 git commands to generate.