[SCSI] libsas: misc fixes to the eh path
authorJames Bottomley <James.Bottomley@HansenPartnership.com>
Sun, 24 Feb 2008 05:39:59 +0000 (23:39 -0600)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Sun, 24 Feb 2008 05:53:20 +0000 (23:53 -0600)
- Correct one use after free of the sas task
- update the reset required path to move straight to LUN reset
- make the bigger hammer actually reset something instead of just trying
  to clear all the tasks.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
drivers/scsi/libsas/sas_scsi_host.c

index f3706f4..1f82415 100644 (file)
@@ -498,10 +498,10 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
 }
 
 /* Try to reset a device */
-static int try_to_reset_cmd_device(struct Scsi_Host *shost,
-                                  struct scsi_cmnd *cmd)
+static int try_to_reset_cmd_device(struct scsi_cmnd *cmd)
 {
        int res;
+       struct Scsi_Host *shost = cmd->device->host;
 
        if (!shost->hostt->eh_device_reset_handler)
                goto try_bus_reset;
@@ -541,6 +541,12 @@ Again:
                need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET;
                spin_unlock_irqrestore(&task->task_state_lock, flags);
 
+               if (need_reset) {
+                       SAS_DPRINTK("%s: task 0x%p requests reset\n",
+                                   __FUNCTION__, task);
+                       goto reset;
+               }
+
                SAS_DPRINTK("trying to find task 0x%p\n", task);
                res = sas_scsi_find_task(task);
 
@@ -551,18 +557,15 @@ Again:
                        SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
                                    task);
                        sas_eh_finish_cmd(cmd);
-                       if (need_reset)
-                               try_to_reset_cmd_device(shost, cmd);
                        continue;
                case TASK_IS_ABORTED:
                        SAS_DPRINTK("%s: task 0x%p is aborted\n",
                                    __FUNCTION__, task);
                        sas_eh_finish_cmd(cmd);
-                       if (need_reset)
-                               try_to_reset_cmd_device(shost, cmd);
                        continue;
                case TASK_IS_AT_LU:
                        SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
+ reset:
                        tmf_resp = sas_recover_lu(task->dev, cmd);
                        if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
                                SAS_DPRINTK("dev %016llx LU %x is "
@@ -570,8 +573,6 @@ Again:
                                            SAS_ADDR(task->dev),
                                            cmd->device->lun);
                                sas_eh_finish_cmd(cmd);
-                               if (need_reset)
-                                       try_to_reset_cmd_device(shost, cmd);
                                sas_scsi_clear_queue_lu(work_q, cmd);
                                goto Again;
                        }
@@ -582,15 +583,15 @@ Again:
                                    task);
                        tmf_resp = sas_recover_I_T(task->dev);
                        if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
+                               struct domain_device *dev = task->dev;
                                SAS_DPRINTK("I_T %016llx recovered\n",
                                            SAS_ADDR(task->dev->sas_addr));
                                sas_eh_finish_cmd(cmd);
-                               if (need_reset)
-                                       try_to_reset_cmd_device(shost, cmd);
-                               sas_scsi_clear_queue_I_T(work_q, task->dev);
+                               sas_scsi_clear_queue_I_T(work_q, dev);
                                goto Again;
                        }
                        /* Hammer time :-) */
+                       try_to_reset_cmd_device(cmd);
                        if (i->dft->lldd_clear_nexus_port) {
                                struct asd_sas_port *port = task->dev->port;
                                SAS_DPRINTK("clearing nexus for port:%d\n",
@@ -600,8 +601,6 @@ Again:
                                        SAS_DPRINTK("clear nexus port:%d "
                                                    "succeeded\n", port->id);
                                        sas_eh_finish_cmd(cmd);
-                                       if (need_reset)
-                                               try_to_reset_cmd_device(shost, cmd);
                                        sas_scsi_clear_queue_port(work_q,
                                                                  port);
                                        goto Again;
@@ -614,8 +613,6 @@ Again:
                                        SAS_DPRINTK("clear nexus ha "
                                                    "succeeded\n");
                                        sas_eh_finish_cmd(cmd);
-                                       if (need_reset)
-                                               try_to_reset_cmd_device(shost, cmd);
                                        goto clear_q;
                                }
                        }
@@ -629,8 +626,6 @@ Again:
                                    cmd->device->lun);
 
                        sas_eh_finish_cmd(cmd);
-                       if (need_reset)
-                               try_to_reset_cmd_device(shost, cmd);
                        goto clear_q;
                }
        }