[SCSI] pm8001: Fix bogus interrupt state flag issue.
[pandora-kernel.git] / drivers / scsi / pm8001 / pm8001_hwi.c
index b7b92f7..871d1c3 100644 (file)
@@ -338,26 +338,25 @@ update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha, int number)
 }
 
 /**
- * bar4_shift - function is called to shift BAR base address
- * @pm8001_ha : our hba card information
+ * pm8001_bar4_shift - function is called to shift BAR base address
+ * @pm8001_ha : our hba card infomation
  * @shiftValue : shifting value in memory bar.
  */
-static int bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue)
+int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue)
 {
        u32 regVal;
-       u32 max_wait_count;
+       unsigned long start;
 
        /* program the inbound AXI translation Lower Address */
        pm8001_cw32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW, shiftValue);
 
        /* confirm the setting is written */
-       max_wait_count = 1 * 1000 * 1000;  /* 1 sec */
+       start = jiffies + HZ; /* 1 sec */
        do {
-               udelay(1);
                regVal = pm8001_cr32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW);
-       } while ((regVal != shiftValue) && (--max_wait_count));
+       } while ((regVal != shiftValue) && time_before(jiffies, start));
 
-       if (!max_wait_count) {
+       if (regVal != shiftValue) {
                PM8001_INIT_DBG(pm8001_ha,
                        pm8001_printk("TIMEOUT:SPC_IBW_AXI_TRANSLATION_LOW"
                        " = 0x%x\n", regVal));
@@ -375,6 +374,7 @@ static void __devinit
 mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit)
 {
        u32 value, offset, i;
+       unsigned long flags;
 
 #define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000
 #define SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000
@@ -388,16 +388,23 @@ mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit)
     * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
     * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
     */
-       if (-1 == bar4_shift(pm8001_ha, SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR))
+       spin_lock_irqsave(&pm8001_ha->lock, flags);
+       if (-1 == pm8001_bar4_shift(pm8001_ha,
+                               SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
+               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                return;
+       }
 
        for (i = 0; i < 4; i++) {
                offset = SAS2_SETTINGS_LOCAL_PHY_0_3_OFFSET + 0x4000 * i;
                pm8001_cw32(pm8001_ha, 2, offset, 0x80001501);
        }
        /* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
-       if (-1 == bar4_shift(pm8001_ha, SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR))
+       if (-1 == pm8001_bar4_shift(pm8001_ha,
+                               SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
+               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                return;
+       }
        for (i = 4; i < 8; i++) {
                offset = SAS2_SETTINGS_LOCAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
                pm8001_cw32(pm8001_ha, 2, offset, 0x80001501);
@@ -421,7 +428,8 @@ mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit)
        pm8001_cw32(pm8001_ha, 2, 0xd8, 0x8000C016);
 
        /*set the shifted destination address to 0x0 to avoid error operation */
-       bar4_shift(pm8001_ha, 0x0);
+       pm8001_bar4_shift(pm8001_ha, 0x0);
+       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
        return;
 }
 
@@ -437,6 +445,7 @@ mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
        u32 offset;
        u32 value;
        u32 i;
+       unsigned long flags;
 
 #define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000
 #define OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000
@@ -445,24 +454,30 @@ mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
 #define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
 
        value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
+       spin_lock_irqsave(&pm8001_ha->lock, flags);
        /* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
-       if (-1 == bar4_shift(pm8001_ha,
-                            OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR))
+       if (-1 == pm8001_bar4_shift(pm8001_ha,
+                            OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
+               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                return;
+       }
        for (i = 0; i < 4; i++) {
                offset = OPEN_RETRY_INTERVAL_PHY_0_3_OFFSET + 0x4000 * i;
                pm8001_cw32(pm8001_ha, 2, offset, value);
        }
 
-       if (-1 == bar4_shift(pm8001_ha,
-                            OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR))
+       if (-1 == pm8001_bar4_shift(pm8001_ha,
+                            OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
+               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                return;
+       }
        for (i = 4; i < 8; i++) {
                offset = OPEN_RETRY_INTERVAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
                pm8001_cw32(pm8001_ha, 2, offset, value);
        }
        /*set the shifted destination address to 0x0 to avoid error operation */
-       bar4_shift(pm8001_ha, 0x0);
+       pm8001_bar4_shift(pm8001_ha, 0x0);
+       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
        return;
 }
 
@@ -607,7 +622,8 @@ static int __devinit pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)
        update_inbnd_queue_table(pm8001_ha, 0);
        update_outbnd_queue_table(pm8001_ha, 0);
        mpi_set_phys_g3_with_ssc(pm8001_ha, 0);
-       mpi_set_open_retry_interval_reg(pm8001_ha, 7);
+       /* 7->130ms, 34->500ms, 119->1.5s */
+       mpi_set_open_retry_interval_reg(pm8001_ha, 119);
        /* notify firmware update finished and check initialization status */
        if (0 == mpi_init_check(pm8001_ha)) {
                PM8001_INIT_DBG(pm8001_ha,
@@ -688,8 +704,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
                PM8001_INIT_DBG(pm8001_ha,
                        pm8001_printk("Firmware is ready for reset .\n"));
        } else {
-       /* Trigger NMI twice via RB6 */
-               if (-1 == bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
+               unsigned long flags;
+               /* Trigger NMI twice via RB6 */
+               spin_lock_irqsave(&pm8001_ha->lock, flags);
+               if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                        PM8001_FAIL_DBG(pm8001_ha,
                                pm8001_printk("Shift Bar4 to 0x%x failed\n",
                                        RB6_ACCESS_REG));
@@ -715,8 +734,10 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
                        PM8001_FAIL_DBG(pm8001_ha,
                                pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
                                pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                        return -1;
                }
+               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
        }
        return 0;
 }
@@ -733,6 +754,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
        u32     regVal, toggleVal;
        u32     max_wait_count;
        u32     regVal1, regVal2, regVal3;
+       unsigned long flags;
 
        /* step1: Check FW is ready for soft reset */
        if (soft_reset_ready_check(pm8001_ha) != 0) {
@@ -743,7 +765,9 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
        /* step 2: clear NMI status register on AAP1 and IOP, write the same
        value to clear */
        /* map 0x60000 to BAR4(0x20), BAR2(win) */
-       if (-1 == bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
+       spin_lock_irqsave(&pm8001_ha->lock, flags);
+       if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
+               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                PM8001_FAIL_DBG(pm8001_ha,
                        pm8001_printk("Shift Bar4 to 0x%x failed\n",
                        MBIC_AAP1_ADDR_BASE));
@@ -754,7 +778,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
                pm8001_printk("MBIC - NMI Enable VPE0 (IOP)= 0x%x\n", regVal));
        pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
        /* map 0x70000 to BAR4(0x20), BAR2(win) */
-       if (-1 == bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
+       if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
+               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                PM8001_FAIL_DBG(pm8001_ha,
                        pm8001_printk("Shift Bar4 to 0x%x failed\n",
                        MBIC_IOP_ADDR_BASE));
@@ -796,7 +821,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
 
        /* read required registers for confirmming */
        /* map 0x0700000 to BAR4(0x20), BAR2(win) */
-       if (-1 == bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
+       if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
+               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                PM8001_FAIL_DBG(pm8001_ha,
                        pm8001_printk("Shift Bar4 to 0x%x failed\n",
                        GSM_ADDR_BASE));
@@ -862,7 +888,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
        /* step 5: delay 10 usec */
        udelay(10);
        /* step 5-b: set GPIO-0 output control to tristate anyway */
-       if (-1 == bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
+       if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
+               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                PM8001_INIT_DBG(pm8001_ha,
                                pm8001_printk("Shift Bar4 to 0x%x failed\n",
                                GPIO_ADDR_BASE));
@@ -878,7 +905,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
 
        /* Step 6: Reset the IOP and AAP1 */
        /* map 0x00000 to BAR4(0x20), BAR2(win) */
-       if (-1 == bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
+       if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
+               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                PM8001_FAIL_DBG(pm8001_ha,
                        pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
                        SPC_TOP_LEVEL_ADDR_BASE));
@@ -915,7 +943,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
 
        /* step 11: reads and sets the GSM Configuration and Reset Register */
        /* map 0x0700000 to BAR4(0x20), BAR2(win) */
-       if (-1 == bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
+       if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
+               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                PM8001_FAIL_DBG(pm8001_ha,
                        pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
                        GSM_ADDR_BASE));
@@ -968,7 +997,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
 
        /* step 13: bring the IOP and AAP1 out of reset */
        /* map 0x00000 to BAR4(0x20), BAR2(win) */
-       if (-1 == bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
+       if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
+               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                PM8001_FAIL_DBG(pm8001_ha,
                        pm8001_printk("Shift Bar4 to 0x%x failed\n",
                        SPC_TOP_LEVEL_ADDR_BASE));
@@ -1010,6 +1040,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
                                pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
                                pm8001_cr32(pm8001_ha, 0,
                                MSGU_SCRATCH_PAD_3)));
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                        return -1;
                }
 
@@ -1039,9 +1070,12 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
                                pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
                                pm8001_cr32(pm8001_ha, 0,
                                MSGU_SCRATCH_PAD_3)));
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
                        return -1;
                }
        }
+       pm8001_bar4_shift(pm8001_ha, 0);
+       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 
        PM8001_INIT_DBG(pm8001_ha,
                pm8001_printk("SPC soft reset Complete\n"));
@@ -1157,8 +1191,8 @@ pm8001_chip_msix_interrupt_disable(struct pm8001_hba_info *pm8001_ha,
        msi_index = int_vec_idx * MSIX_TABLE_ELEMENT_SIZE;
        msi_index += MSIX_TABLE_BASE;
        pm8001_cw32(pm8001_ha, 0,  msi_index, MSIX_INTERRUPT_DISABLE);
-
 }
+
 /**
  * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt
  * @pm8001_ha: our hba card information
@@ -1388,24 +1422,191 @@ static void pm8001_work_fn(struct work_struct *work)
        struct pm8001_device *pm8001_dev;
        struct domain_device *dev;
 
+       /*
+        * So far, all users of this stash an associated structure here.
+        * If we get here, and this pointer is null, then the action
+        * was cancelled. This nullification happens when the device
+        * goes away.
+        */
+       pm8001_dev = pw->data; /* Most stash device structure */
+       if ((pm8001_dev == NULL)
+        || ((pw->handler != IO_XFER_ERROR_BREAK)
+         && (pm8001_dev->dev_type == NO_DEVICE))) {
+               kfree(pw);
+               return;
+       }
+
        switch (pw->handler) {
+       case IO_XFER_ERROR_BREAK:
+       {       /* This one stashes the sas_task instead */
+               struct sas_task *t = (struct sas_task *)pm8001_dev;
+               u32 tag;
+               struct pm8001_ccb_info *ccb;
+               struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
+               unsigned long flags, flags1;
+               struct task_status_struct *ts;
+               int i;
+
+               if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
+                       break; /* Task still on lu */
+               spin_lock_irqsave(&pm8001_ha->lock, flags);
+
+               spin_lock_irqsave(&t->task_state_lock, flags1);
+               if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
+                       spin_unlock_irqrestore(&t->task_state_lock, flags1);
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       break; /* Task got completed by another */
+               }
+               spin_unlock_irqrestore(&t->task_state_lock, flags1);
+
+               /* Search for a possible ccb that matches the task */
+               for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
+                       ccb = &pm8001_ha->ccb_info[i];
+                       tag = ccb->ccb_tag;
+                       if ((tag != 0xFFFFFFFF) && (ccb->task == t))
+                               break;
+               }
+               if (!ccb) {
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       break; /* Task got freed by another */
+               }
+               ts = &t->task_status;
+               ts->resp = SAS_TASK_COMPLETE;
+               /* Force the midlayer to retry */
+               ts->stat = SAS_QUEUE_FULL;
+               pm8001_dev = ccb->device;
+               if (pm8001_dev)
+                       pm8001_dev->running_req--;
+               spin_lock_irqsave(&t->task_state_lock, flags1);
+               t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+               t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+               t->task_state_flags |= SAS_TASK_STATE_DONE;
+               if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
+                       spin_unlock_irqrestore(&t->task_state_lock, flags1);
+                       PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p"
+                               " done with event 0x%x resp 0x%x stat 0x%x but"
+                               " aborted by upper layer!\n",
+                               t, pw->handler, ts->resp, ts->stat));
+                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+               } else {
+                       spin_unlock_irqrestore(&t->task_state_lock, flags1);
+                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+                       mb();/* in order to force CPU ordering */
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       t->task_done(t);
+               }
+       }       break;
+       case IO_XFER_OPEN_RETRY_TIMEOUT:
+       {       /* This one stashes the sas_task instead */
+               struct sas_task *t = (struct sas_task *)pm8001_dev;
+               u32 tag;
+               struct pm8001_ccb_info *ccb;
+               struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
+               unsigned long flags, flags1;
+               int i, ret = 0;
+
+               PM8001_IO_DBG(pm8001_ha,
+                       pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n"));
+
+               ret = pm8001_query_task(t);
+
+               PM8001_IO_DBG(pm8001_ha,
+                       switch (ret) {
+                       case TMF_RESP_FUNC_SUCC:
+                               pm8001_printk("...Task on lu\n");
+                               break;
+
+                       case TMF_RESP_FUNC_COMPLETE:
+                               pm8001_printk("...Task NOT on lu\n");
+                               break;
+
+                       default:
+                               pm8001_printk("...query task failed!!!\n");
+                               break;
+                       });
+
+               spin_lock_irqsave(&pm8001_ha->lock, flags);
+
+               spin_lock_irqsave(&t->task_state_lock, flags1);
+
+               if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
+                       spin_unlock_irqrestore(&t->task_state_lock, flags1);
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
+                               (void)pm8001_abort_task(t);
+                       break; /* Task got completed by another */
+               }
+
+               spin_unlock_irqrestore(&t->task_state_lock, flags1);
+
+               /* Search for a possible ccb that matches the task */
+               for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
+                       ccb = &pm8001_ha->ccb_info[i];
+                       tag = ccb->ccb_tag;
+                       if ((tag != 0xFFFFFFFF) && (ccb->task == t))
+                               break;
+               }
+               if (!ccb) {
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
+                               (void)pm8001_abort_task(t);
+                       break; /* Task got freed by another */
+               }
+
+               pm8001_dev = ccb->device;
+               dev = pm8001_dev->sas_device;
+
+               switch (ret) {
+               case TMF_RESP_FUNC_SUCC: /* task on lu */
+                       ccb->open_retry = 1; /* Snub completion */
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       ret = pm8001_abort_task(t);
+                       ccb->open_retry = 0;
+                       switch (ret) {
+                       case TMF_RESP_FUNC_SUCC:
+                       case TMF_RESP_FUNC_COMPLETE:
+                               break;
+                       default: /* device misbehavior */
+                               ret = TMF_RESP_FUNC_FAILED;
+                               PM8001_IO_DBG(pm8001_ha,
+                                       pm8001_printk("...Reset phy\n"));
+                               pm8001_I_T_nexus_reset(dev);
+                               break;
+                       }
+                       break;
+
+               case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       /* Do we need to abort the task locally? */
+                       break;
+
+               default: /* device misbehavior */
+                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       ret = TMF_RESP_FUNC_FAILED;
+                       PM8001_IO_DBG(pm8001_ha,
+                               pm8001_printk("...Reset phy\n"));
+                       pm8001_I_T_nexus_reset(dev);
+               }
+
+               if (ret == TMF_RESP_FUNC_FAILED)
+                       t = NULL;
+               pm8001_open_reject_retry(pm8001_ha, t, pm8001_dev);
+               PM8001_IO_DBG(pm8001_ha, pm8001_printk("...Complete\n"));
+       }       break;
        case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
-               pm8001_dev = pw->data;
                dev = pm8001_dev->sas_device;
                pm8001_I_T_nexus_reset(dev);
                break;
        case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
-               pm8001_dev = pw->data;
                dev = pm8001_dev->sas_device;
                pm8001_I_T_nexus_reset(dev);
                break;
        case IO_DS_IN_ERROR:
-               pm8001_dev = pw->data;
                dev = pm8001_dev->sas_device;
                pm8001_I_T_nexus_reset(dev);
                break;
        case IO_DS_NON_OPERATIONAL:
-               pm8001_dev = pw->data;
                dev = pm8001_dev->sas_device;
                pm8001_I_T_nexus_reset(dev);
                break;
@@ -1460,6 +1661,11 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb)
        status = le32_to_cpu(psspPayload->status);
        tag = le32_to_cpu(psspPayload->tag);
        ccb = &pm8001_ha->ccb_info[tag];
+       if ((status == IO_ABORTED) && ccb->open_retry) {
+               /* Being completed by another */
+               ccb->open_retry = 0;
+               return;
+       }
        pm8001_dev = ccb->device;
        param = le32_to_cpu(psspPayload->param);
 
@@ -1515,6 +1721,8 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb)
                        pm8001_printk("IO_XFER_ERROR_BREAK\n"));
                ts->resp = SAS_TASK_COMPLETE;
                ts->stat = SAS_OPEN_REJECT;
+               /* Force the midlayer to retry */
+               ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
                break;
        case IO_XFER_ERROR_PHY_NOT_READY:
                PM8001_IO_DBG(pm8001_ha,
@@ -1719,9 +1927,8 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
        case IO_XFER_ERROR_BREAK:
                PM8001_IO_DBG(pm8001_ha,
                        pm8001_printk("IO_XFER_ERROR_BREAK\n"));
-               ts->resp = SAS_TASK_COMPLETE;
-               ts->stat = SAS_INTERRUPTED;
-               break;
+               pm8001_handle_event(pm8001_ha, t, IO_XFER_ERROR_BREAK);
+               return;
        case IO_XFER_ERROR_PHY_NOT_READY:
                PM8001_IO_DBG(pm8001_ha,
                        pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n"));
@@ -1800,10 +2007,8 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
        case IO_XFER_OPEN_RETRY_TIMEOUT:
                PM8001_IO_DBG(pm8001_ha,
                        pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n"));
-               ts->resp = SAS_TASK_COMPLETE;
-               ts->stat = SAS_OPEN_REJECT;
-               ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
-               break;
+               pm8001_handle_event(pm8001_ha, t, IO_XFER_OPEN_RETRY_TIMEOUT);
+               return;
        case IO_XFER_ERROR_UNEXPECTED_PHASE:
                PM8001_IO_DBG(pm8001_ha,
                        pm8001_printk("IO_XFER_ERROR_UNEXPECTED_PHASE\n"));
@@ -1877,7 +2082,6 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 {
        struct sas_task *t;
        struct pm8001_ccb_info *ccb;
-       unsigned long flags = 0;
        u32 param;
        u32 status;
        u32 tag;
@@ -2016,9 +2220,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                        ts->stat = SAS_QUEUE_FULL;
                        pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                        mb();/*in order to force CPU ordering*/
-                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       spin_unlock_irq(&pm8001_ha->lock);
                        t->task_done(t);
-                       spin_lock_irqsave(&pm8001_ha->lock, flags);
+                       spin_lock_irq(&pm8001_ha->lock);
                        return;
                }
                break;
@@ -2036,9 +2240,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                        ts->stat = SAS_QUEUE_FULL;
                        pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                        mb();/*ditto*/
-                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       spin_unlock_irq(&pm8001_ha->lock);
                        t->task_done(t);
-                       spin_lock_irqsave(&pm8001_ha->lock, flags);
+                       spin_lock_irq(&pm8001_ha->lock);
                        return;
                }
                break;
@@ -2064,9 +2268,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                        ts->stat = SAS_QUEUE_FULL;
                        pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                        mb();/* ditto*/
-                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       spin_unlock_irq(&pm8001_ha->lock);
                        t->task_done(t);
-                       spin_lock_irqsave(&pm8001_ha->lock, flags);
+                       spin_lock_irq(&pm8001_ha->lock);
                        return;
                }
                break;
@@ -2131,9 +2335,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                        ts->stat = SAS_QUEUE_FULL;
                        pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                        mb();/*ditto*/
-                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       spin_unlock_irq(&pm8001_ha->lock);
                        t->task_done(t);
-                       spin_lock_irqsave(&pm8001_ha->lock, flags);
+                       spin_lock_irq(&pm8001_ha->lock);
                        return;
                }
                break;
@@ -2155,9 +2359,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                        ts->stat = SAS_QUEUE_FULL;
                        pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                        mb();/*ditto*/
-                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       spin_unlock_irq(&pm8001_ha->lock);
                        t->task_done(t);
-                       spin_lock_irqsave(&pm8001_ha->lock, flags);
+                       spin_lock_irq(&pm8001_ha->lock);
                        return;
                }
                break;
@@ -2175,31 +2379,31 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
                ts->stat = SAS_DEV_NO_RESPONSE;
                break;
        }
-       spin_lock_irqsave(&t->task_state_lock, flags);
+       spin_lock_irq(&t->task_state_lock);
        t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
        t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
        t->task_state_flags |= SAS_TASK_STATE_DONE;
        if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
+               spin_unlock_irq(&t->task_state_lock);
                PM8001_FAIL_DBG(pm8001_ha,
                        pm8001_printk("task 0x%p done with io_status 0x%x"
                        " resp 0x%x stat 0x%x but aborted by upper layer!\n",
                        t, status, ts->resp, ts->stat));
                pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
        } else if (t->uldd_task) {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
+               spin_unlock_irq(&t->task_state_lock);
                pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                mb();/* ditto */
-               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+               spin_unlock_irq(&pm8001_ha->lock);
                t->task_done(t);
-               spin_lock_irqsave(&pm8001_ha->lock, flags);
+               spin_lock_irq(&pm8001_ha->lock);
        } else if (!t->uldd_task) {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
+               spin_unlock_irq(&t->task_state_lock);
                pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                mb();/*ditto*/
-               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+               spin_unlock_irq(&pm8001_ha->lock);
                t->task_done(t);
-               spin_lock_irqsave(&pm8001_ha->lock, flags);
+               spin_lock_irq(&pm8001_ha->lock);
        }
 }
 
@@ -2207,7 +2411,6 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
 {
        struct sas_task *t;
-       unsigned long flags = 0;
        struct task_status_struct *ts;
        struct pm8001_ccb_info *ccb;
        struct pm8001_device *pm8001_dev;
@@ -2287,9 +2490,9 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
                        ts->stat = SAS_QUEUE_FULL;
                        pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                        mb();/*ditto*/
-                       spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+                       spin_unlock_irq(&pm8001_ha->lock);
                        t->task_done(t);
-                       spin_lock_irqsave(&pm8001_ha->lock, flags);
+                       spin_lock_irq(&pm8001_ha->lock);
                        return;
                }
                break;
@@ -2387,31 +2590,31 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
                ts->stat = SAS_OPEN_TO;
                break;
        }
-       spin_lock_irqsave(&t->task_state_lock, flags);
+       spin_lock_irq(&t->task_state_lock);
        t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
        t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
        t->task_state_flags |= SAS_TASK_STATE_DONE;
        if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
+               spin_unlock_irq(&t->task_state_lock);
                PM8001_FAIL_DBG(pm8001_ha,
                        pm8001_printk("task 0x%p done with io_status 0x%x"
                        " resp 0x%x stat 0x%x but aborted by upper layer!\n",
                        t, event, ts->resp, ts->stat));
                pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
        } else if (t->uldd_task) {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
+               spin_unlock_irq(&t->task_state_lock);
                pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                mb();/* ditto */
-               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+               spin_unlock_irq(&pm8001_ha->lock);
                t->task_done(t);
-               spin_lock_irqsave(&pm8001_ha->lock, flags);
+               spin_lock_irq(&pm8001_ha->lock);
        } else if (!t->uldd_task) {
-               spin_unlock_irqrestore(&t->task_state_lock, flags);
+               spin_unlock_irq(&t->task_state_lock);
                pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
                mb();/*ditto*/
-               spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+               spin_unlock_irq(&pm8001_ha->lock);
                t->task_done(t);
-               spin_lock_irqsave(&pm8001_ha->lock, flags);
+               spin_lock_irq(&pm8001_ha->lock);
        }
 }