Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux-2.6-microblaze.git] / drivers / scsi / scsi_error.c
index 36870b4..2371edb 100644 (file)
@@ -50,8 +50,6 @@
 
 #include <asm/unaligned.h>
 
-static void scsi_eh_done(struct scsi_cmnd *scmd);
-
 /*
  * These should *probably* be handled by the host itself.
  * Since it is allowed to sleep, it probably should.
@@ -135,6 +133,23 @@ static bool scsi_eh_should_retry_cmd(struct scsi_cmnd *cmd)
        return true;
 }
 
+static void scsi_eh_complete_abort(struct scsi_cmnd *scmd, struct Scsi_Host *shost)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(shost->host_lock, flags);
+       list_del_init(&scmd->eh_entry);
+       /*
+        * If the abort succeeds, and there is no further
+        * EH action, clear the ->last_reset time.
+        */
+       if (list_empty(&shost->eh_abort_list) &&
+           list_empty(&shost->eh_cmd_q))
+               if (shost->eh_deadline != -1)
+                       shost->last_reset = 0;
+       spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
 /**
  * scmd_eh_abort_handler - Handle command aborts
  * @work:      command to be aborted.
@@ -152,6 +167,7 @@ scmd_eh_abort_handler(struct work_struct *work)
                container_of(work, struct scsi_cmnd, abort_work.work);
        struct scsi_device *sdev = scmd->device;
        enum scsi_disposition rtn;
+       unsigned long flags;
 
        if (scsi_host_eh_past_deadline(sdev->host)) {
                SCSI_LOG_ERROR_RECOVERY(3,
@@ -175,12 +191,14 @@ scmd_eh_abort_handler(struct work_struct *work)
                                SCSI_LOG_ERROR_RECOVERY(3,
                                        scmd_printk(KERN_WARNING, scmd,
                                                    "retry aborted command\n"));
+                               scsi_eh_complete_abort(scmd, sdev->host);
                                scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
                                return;
                        } else {
                                SCSI_LOG_ERROR_RECOVERY(3,
                                        scmd_printk(KERN_WARNING, scmd,
                                                    "finish aborted command\n"));
+                               scsi_eh_complete_abort(scmd, sdev->host);
                                scsi_finish_command(scmd);
                                return;
                        }
@@ -193,6 +211,9 @@ scmd_eh_abort_handler(struct work_struct *work)
                }
        }
 
+       spin_lock_irqsave(sdev->host->host_lock, flags);
+       list_del_init(&scmd->eh_entry);
+       spin_unlock_irqrestore(sdev->host->host_lock, flags);
        scsi_eh_scmd_add(scmd);
 }
 
@@ -223,6 +244,8 @@ scsi_abort_command(struct scsi_cmnd *scmd)
        spin_lock_irqsave(shost->host_lock, flags);
        if (shost->eh_deadline != -1 && !shost->last_reset)
                shost->last_reset = jiffies;
+       BUG_ON(!list_empty(&scmd->eh_entry));
+       list_add_tail(&scmd->eh_entry, &shost->eh_abort_list);
        spin_unlock_irqrestore(shost->host_lock, flags);
 
        scmd->eh_eflags |= SCSI_EH_ABORT_SCHEDULED;
@@ -520,7 +543,8 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
                /* handler does not care. Drop down to default handling */
        }
 
-       if (scmd->cmnd[0] == TEST_UNIT_READY && scmd->scsi_done != scsi_eh_done)
+       if (scmd->cmnd[0] == TEST_UNIT_READY &&
+           scmd->submitter != SUBMITTED_BY_SCSI_ERROR_HANDLER)
                /*
                 * nasty: for mid-layer issued TURs, we need to return the
                 * actual sense data without any recovery attempt.  For eh
@@ -782,7 +806,7 @@ static enum scsi_disposition scsi_eh_completed_normally(struct scsi_cmnd *scmd)
  * scsi_eh_done - Completion function for error handling.
  * @scmd:      Cmd that is done.
  */
-static void scsi_eh_done(struct scsi_cmnd *scmd)
+void scsi_eh_done(struct scsi_cmnd *scmd)
 {
        struct completion *eh_action;
 
@@ -1082,7 +1106,7 @@ retry:
        shost->eh_action = &done;
 
        scsi_log_send(scmd);
-       scmd->scsi_done = scsi_eh_done;
+       scmd->submitter = SUBMITTED_BY_SCSI_ERROR_HANDLER;
 
        /*
         * Lock sdev->state_mutex to avoid that scsi_device_quiesce() can
@@ -1109,6 +1133,7 @@ retry:
        if (rtn) {
                if (timeleft > stall_for) {
                        scsi_eh_restore_cmnd(scmd, &ses);
+
                        timeleft -= stall_for;
                        msleep(jiffies_to_msecs(stall_for));
                        goto retry;
@@ -2338,11 +2363,6 @@ void scsi_report_device_reset(struct Scsi_Host *shost, int channel, int target)
 }
 EXPORT_SYMBOL(scsi_report_device_reset);
 
-static void
-scsi_reset_provider_done_command(struct scsi_cmnd *scmd)
-{
-}
-
 /**
  * scsi_ioctl_reset: explicitly reset a host/bus/target/device
  * @dev:       scsi_device to operate on
@@ -2379,7 +2399,7 @@ scsi_ioctl_reset(struct scsi_device *dev, int __user *arg)
        scsi_init_command(dev, scmd);
        scmd->cmnd = scsi_req(rq)->cmd;
 
-       scmd->scsi_done         = scsi_reset_provider_done_command;
+       scmd->submitter = SUBMITTED_BY_SCSI_RESET_IOCTL;
        memset(&scmd->sdb, 0, sizeof(scmd->sdb));
 
        scmd->cmd_len                   = 0;