[SCSI] aic94xx SCSI timeout fix: SMP retry fix.
malahal@us.ibm.com [Thu, 5 Oct 2006 00:34:03 +0000 (17:34 -0700)]
Updating DDB0 inside aic94xx driver itself caused SMP command timeout. I
hit this SMP timeout problem twice but I am not able to reproduce it since
then. Here is a fix that retries an SMP command.

Signed-off-by: Malahal Naineni <malahal@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

drivers/scsi/libsas/sas_expander.c

index 30b8014..e34a934 100644 (file)
@@ -71,55 +71,65 @@ static void smp_task_done(struct sas_task *task)
 static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
                            void *resp, int resp_size)
 {
-       int res;
-       struct sas_task *task = sas_alloc_task(GFP_KERNEL);
+       int res, retry;
+       struct sas_task *task = NULL;
        struct sas_internal *i =
                to_sas_internal(dev->port->ha->core.shost->transportt);
 
-       if (!task)
-               return -ENOMEM;
-
-       task->dev = dev;
-       task->task_proto = dev->tproto;
-       sg_init_one(&task->smp_task.smp_req, req, req_size);
-       sg_init_one(&task->smp_task.smp_resp, resp, resp_size);
+       for (retry = 0; retry < 3; retry++) {
+               task = sas_alloc_task(GFP_KERNEL);
+               if (!task)
+                       return -ENOMEM;
 
-       task->task_done = smp_task_done;
+               task->dev = dev;
+               task->task_proto = dev->tproto;
+               sg_init_one(&task->smp_task.smp_req, req, req_size);
+               sg_init_one(&task->smp_task.smp_resp, resp, resp_size);
 
-       task->timer.data = (unsigned long) task;
-       task->timer.function = smp_task_timedout;
-       task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
-       add_timer(&task->timer);
+               task->task_done = smp_task_done;
 
-       res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
+               task->timer.data = (unsigned long) task;
+               task->timer.function = smp_task_timedout;
+               task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
+               add_timer(&task->timer);
 
-       if (res) {
-               del_timer(&task->timer);
-               SAS_DPRINTK("executing SMP task failed:%d\n", res);
-               goto ex_err;
-       }
+               res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
 
-       wait_for_completion(&task->completion);
-       res = -ETASK;
-       if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-               SAS_DPRINTK("smp task timed out or aborted\n");
-               i->dft->lldd_abort_task(task);
-               if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
-                       SAS_DPRINTK("SMP task aborted and not done\n");
+               if (res) {
+                       del_timer(&task->timer);
+                       SAS_DPRINTK("executing SMP task failed:%d\n", res);
                        goto ex_err;
                }
+
+               wait_for_completion(&task->completion);
+               res = -ETASK;
+               if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+                       SAS_DPRINTK("smp task timed out or aborted\n");
+                       i->dft->lldd_abort_task(task);
+                       if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+                               SAS_DPRINTK("SMP task aborted and not done\n");
+                               goto ex_err;
+                       }
+               }
+               if (task->task_status.resp == SAS_TASK_COMPLETE &&
+                   task->task_status.stat == SAM_GOOD) {
+                       res = 0;
+                       break;
+               } else {
+                       SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
+                                   "status 0x%x\n", __FUNCTION__,
+                                   SAS_ADDR(dev->sas_addr),
+                                   task->task_status.resp,
+                                   task->task_status.stat);
+                       sas_free_task(task);
+                       task = NULL;
+               }
        }
-       if (task->task_status.resp == SAS_TASK_COMPLETE &&
-           task->task_status.stat == SAM_GOOD)
-               res = 0;
-       else
-               SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
-                           "status 0x%x\n", __FUNCTION__,
-                           SAS_ADDR(dev->sas_addr),
-                           task->task_status.resp,
-                           task->task_status.stat);
 ex_err:
-       sas_free_task(task);
+       BUG_ON(retry == 3 && task != NULL);
+       if (task != NULL) {
+               sas_free_task(task);
+       }
        return res;
 }