[SCSI] libsas: prevent double completion of scmds from eh
authorDan Williams <dan.j.williams@intel.com>
Wed, 7 Dec 2011 07:24:42 +0000 (23:24 -0800)
committerJames Bottomley <JBottomley@Parallels.com>
Sun, 19 Feb 2012 20:04:52 +0000 (14:04 -0600)
We invoke task->task_done() to free the task in the eh case, but at this
point we are prepared for scsi_eh_flush_done_q() to finish off the scmd.

Introduce sas_end_task() to capture the final response status from the
lldd and free the task.

Also take the opportunity to kill this warning.
drivers/scsi/libsas/sas_scsi_host.c: In function ‘sas_end_task’:
drivers/scsi/libsas/sas_scsi_host.c:102:3: warning: case value ‘2’ not in enumerated type ‘enum exec_status’ [-Wswitch]

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/libsas/sas_scsi_host.c
include/scsi/libsas.h

index ba5876ccd29a13d4faccef93dc4db4af340fb449..50db8f971a06644532681bf0aabdd6636e98adbd 100644 (file)
 #include <linux/scatterlist.h>
 #include <linux/libata.h>
 
-/* ---------- SCSI Host glue ---------- */
-
-static void sas_scsi_task_done(struct sas_task *task)
+/* record final status and free the task */
+static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task)
 {
        struct task_status_struct *ts = &task->task_status;
-       struct scsi_cmnd *sc = task->uldd_task;
        int hs = 0, stat = 0;
 
-       if (unlikely(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-               /* Aborted tasks will be completed by the error handler */
-               SAS_DPRINTK("task done but aborted\n");
-               return;
-       }
-
-       if (unlikely(!sc)) {
-               SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
-               list_del_init(&task->list);
-               sas_free_task(task);
-               return;
-       }
-
        if (ts->resp == SAS_TASK_UNDELIVERED) {
                /* transport error */
                hs = DID_NO_CONNECT;
@@ -124,10 +109,32 @@ static void sas_scsi_task_done(struct sas_task *task)
                        break;
                }
        }
-       ASSIGN_SAS_TASK(sc, NULL);
+
        sc->result = (hs << 16) | stat;
+       ASSIGN_SAS_TASK(sc, NULL);
        list_del_init(&task->list);
        sas_free_task(task);
+}
+
+static void sas_scsi_task_done(struct sas_task *task)
+{
+       struct scsi_cmnd *sc = task->uldd_task;
+
+       if (unlikely(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+               /* Aborted tasks will be completed by the error handler */
+               SAS_DPRINTK("task done but aborted\n");
+               return;
+       }
+
+       if (unlikely(!sc)) {
+               SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
+               list_del_init(&task->list);
+               sas_free_task(task);
+               return;
+       }
+
+       ASSIGN_SAS_TASK(sc, NULL);
+       sas_end_task(sc, task);
        sc->scsi_done(sc);
 }
 
@@ -236,18 +243,16 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
        struct sas_task *task = TO_SAS_TASK(cmd);
        struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host);
 
-       /* remove the aborted task flag to allow the task to be
-        * completed now. At this point, we only get called following
-        * an actual abort of the task, so we should be guaranteed not
-        * to be racing with any completions from the LLD (hence we
-        * don't need the task state lock to clear the flag) */
-       task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
-       /* Now call task_done.  However, task will be free'd after
-        * this */
-       task->task_done(task);
+       /* At this point, we only get called following an actual abort
+        * of the task, so we should be guaranteed not to be racing with
+        * any completions from the LLD.  Task is freed after this.
+        */
+       sas_end_task(cmd, task);
+
        /* now finish the command and move it on to the error
         * handler done list, this also takes it off the
-        * error handler pending list */
+        * error handler pending list.
+        */
        scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q);
 }
 
index 10eb2ea74431e7d3a37750d17ba43c9a9a78a7ab..071041b290d66446a4e3414d44ac60e0754eeeba 100644 (file)
@@ -452,7 +452,10 @@ enum service_response {
 };
 
 enum exec_status {
-       /* The SAM_STAT_.. codes fit in the lower 6 bits */
+       /* The SAM_STAT_.. codes fit in the lower 6 bits, alias some of
+        * them here to silence 'case value not in enumerated type' warnings
+        */
+       __SAM_STAT_CHECK_CONDITION = SAM_STAT_CHECK_CONDITION,
 
        SAS_DEV_NO_RESPONSE = 0x80,
        SAS_DATA_UNDERRUN,