Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux-2.6-microblaze.git] / drivers / scsi / pm8001 / pm8001_sas.c
index 7b2f92a..0e294e8 100644 (file)
@@ -1158,40 +1158,42 @@ int pm8001_query_task(struct sas_task *task)
 int pm8001_abort_task(struct sas_task *task)
 {
        unsigned long flags;
-       u32 tag = 0xdeadbeef;
+       u32 tag;
        u32 device_id;
        struct domain_device *dev ;
-       struct pm8001_hba_info *pm8001_ha = NULL;
-       struct pm8001_ccb_info *ccb;
+       struct pm8001_hba_info *pm8001_ha;
        struct scsi_lun lun;
        struct pm8001_device *pm8001_dev;
        struct pm8001_tmf_task tmf_task;
-       int rc = TMF_RESP_FUNC_FAILED;
+       int rc = TMF_RESP_FUNC_FAILED, ret;
+       u32 phy_id;
+       struct sas_task_slow slow_task;
        if (unlikely(!task || !task->lldd_task || !task->dev))
-               return rc;
+               return TMF_RESP_FUNC_FAILED;
+       dev = task->dev;
+       pm8001_dev = dev->lldd_dev;
+       pm8001_ha = pm8001_find_ha_by_dev(dev);
+       device_id = pm8001_dev->device_id;
+       phy_id = pm8001_dev->attached_phy;
+       rc = pm8001_find_tag(task, &tag);
+       if (rc == 0) {
+               pm8001_printk("no tag for task:%p\n", task);
+               return TMF_RESP_FUNC_FAILED;
+       }
        spin_lock_irqsave(&task->task_state_lock, flags);
        if (task->task_state_flags & SAS_TASK_STATE_DONE) {
                spin_unlock_irqrestore(&task->task_state_lock, flags);
-               rc = TMF_RESP_FUNC_COMPLETE;
-               goto out;
+               return TMF_RESP_FUNC_COMPLETE;
+       }
+       task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+       if (task->slow_task == NULL) {
+               init_completion(&slow_task.completion);
+               task->slow_task = &slow_task;
        }
        spin_unlock_irqrestore(&task->task_state_lock, flags);
        if (task->task_proto & SAS_PROTOCOL_SSP) {
                struct scsi_cmnd *cmnd = task->uldd_task;
-               dev = task->dev;
-               ccb = task->lldd_task;
-               pm8001_dev = dev->lldd_dev;
-               pm8001_ha = pm8001_find_ha_by_dev(dev);
                int_to_scsilun(cmnd->device->lun, &lun);
-               rc = pm8001_find_tag(task, &tag);
-               if (rc == 0) {
-                       printk(KERN_INFO "No such tag in %s\n", __func__);
-                       rc = TMF_RESP_FUNC_FAILED;
-                       return rc;
-               }
-               device_id = pm8001_dev->device_id;
-               PM8001_EH_DBG(pm8001_ha,
-                       pm8001_printk("abort io to deviceid= %d\n", device_id));
                tmf_task.tmf = TMF_ABORT_TASK;
                tmf_task.tag_of_task_to_be_managed = tag;
                rc = pm8001_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task);
@@ -1199,33 +1201,77 @@ int pm8001_abort_task(struct sas_task *task)
                        pm8001_dev->sas_device, 0, tag);
        } else if (task->task_proto & SAS_PROTOCOL_SATA ||
                task->task_proto & SAS_PROTOCOL_STP) {
-               dev = task->dev;
-               pm8001_dev = dev->lldd_dev;
-               pm8001_ha = pm8001_find_ha_by_dev(dev);
-               rc = pm8001_find_tag(task, &tag);
-               if (rc == 0) {
-                       printk(KERN_INFO "No such tag in %s\n", __func__);
-                       rc = TMF_RESP_FUNC_FAILED;
-                       return rc;
+               if (pm8001_ha->chip_id == chip_8006) {
+                       DECLARE_COMPLETION_ONSTACK(completion_reset);
+                       DECLARE_COMPLETION_ONSTACK(completion);
+                       struct pm8001_phy *phy = pm8001_ha->phy + phy_id;
+
+                       /* 1. Set Device state as Recovery */
+                       pm8001_dev->setds_completion = &completion;
+                       PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
+                               pm8001_dev, 0x03);
+                       wait_for_completion(&completion);
+
+                       /* 2. Send Phy Control Hard Reset */
+                       reinit_completion(&completion);
+                       phy->reset_success = false;
+                       phy->enable_completion = &completion;
+                       phy->reset_completion = &completion_reset;
+                       ret = PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id,
+                               PHY_HARD_RESET);
+                       if (ret)
+                               goto out;
+                       PM8001_MSG_DBG(pm8001_ha,
+                               pm8001_printk("Waiting for local phy ctl\n"));
+                       wait_for_completion(&completion);
+                       if (!phy->reset_success)
+                               goto out;
+
+                       /* 3. Wait for Port Reset complete / Port reset TMO */
+                       PM8001_MSG_DBG(pm8001_ha,
+                               pm8001_printk("Waiting for Port reset\n"));
+                       wait_for_completion(&completion_reset);
+                       if (phy->port_reset_status)
+                               goto out;
+
+                       /*
+                        * 4. SATA Abort ALL
+                        * we wait for the task to be aborted so that the task
+                        * is removed from the ccb. on success the caller is
+                        * going to free the task.
+                        */
+                       ret = pm8001_exec_internal_task_abort(pm8001_ha,
+                               pm8001_dev, pm8001_dev->sas_device, 1, tag);
+                       if (ret)
+                               goto out;
+                       ret = wait_for_completion_timeout(
+                               &task->slow_task->completion,
+                               PM8001_TASK_TIMEOUT * HZ);
+                       if (!ret)
+                               goto out;
+
+                       /* 5. Set Device State as Operational */
+                       reinit_completion(&completion);
+                       pm8001_dev->setds_completion = &completion;
+                       PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
+                               pm8001_dev, 0x01);
+                       wait_for_completion(&completion);
+               } else {
+                       rc = pm8001_exec_internal_task_abort(pm8001_ha,
+                               pm8001_dev, pm8001_dev->sas_device, 0, tag);
                }
-               rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev,
-                       pm8001_dev->sas_device, 0, tag);
+               rc = TMF_RESP_FUNC_COMPLETE;
        } else if (task->task_proto & SAS_PROTOCOL_SMP) {
                /* SMP */
-               dev = task->dev;
-               pm8001_dev = dev->lldd_dev;
-               pm8001_ha = pm8001_find_ha_by_dev(dev);
-               rc = pm8001_find_tag(task, &tag);
-               if (rc == 0) {
-                       printk(KERN_INFO "No such tag in %s\n", __func__);
-                       rc = TMF_RESP_FUNC_FAILED;
-                       return rc;
-               }
                rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev,
                        pm8001_dev->sas_device, 0, tag);
 
        }
 out:
+       spin_lock_irqsave(&task->task_state_lock, flags);
+       if (task->slow_task == &slow_task)
+               task->slow_task = NULL;
+       spin_unlock_irqrestore(&task->task_state_lock, flags);
        if (rc != TMF_RESP_FUNC_COMPLETE)
                pm8001_printk("rc= %d\n", rc);
        return rc;