[SCSI] mvsas: fix hot plug handling and IO issues
authorSrinivas <satyasrinivasp@hcl.in>
Mon, 15 Feb 2010 06:00:00 +0000 (00:00 -0600)
committerJames Bottomley <James.Bottomley@suse.de>
Sun, 11 Apr 2010 19:44:01 +0000 (14:44 -0500)
This patch adds a bunch of fixes

1. Reduce sg table size to 64 (SG_MX) instead of default SG_ALL
2. clear task lists on phy down events
3. release all tasks on port deformation
4. release current task for device gone notification
5. Add sata abort handing
6. Add 10ms delay to each port reset (currently done serially and with
   interrupts disabled)

[jejb: whitespace fixes and clean ups plus added description
       added dummy 94xx_clear_srs_irq function just to prevent the
       mismatch in the mvs_dispatch structure killing 94xx cards]
Signed-off-by: Srinivas <satyasrinivasp@hcl.in>
Cc: Andy Yan <ayan@marvell.com>
Cc: qswang@marvell.com
Cc: jfeng@marvell.com
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/mvsas/mv_64xx.c
drivers/scsi/mvsas/mv_94xx.c
drivers/scsi/mvsas/mv_init.c
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/mvsas/mv_sas.h

index 10a5077b6aeda3ae0147db9b31274dd74cbb0757..afc7f6f3a13e77bf7c00b5f87972e8e49965bbef 100644 (file)
@@ -132,9 +132,9 @@ static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
        tmp &= ~PHYEV_RDY_CH;
        mvs_write_port_irq_stat(mvi, phy_id, tmp);
        tmp = mvs_read_phy_ctl(mvi, phy_id);
-       if (hard)
+       if (hard == 1)
                tmp |= PHY_RST_HARD;
-       else
+       else if (hard == 0)
                tmp |= PHY_RST;
        mvs_write_phy_ctl(mvi, phy_id, tmp);
        if (hard) {
@@ -144,6 +144,26 @@ static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
        }
 }
 
+void mvs_64xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+       if (clear_all) {
+               tmp = mr32(MVS_INT_STAT_SRS_0);
+               if (tmp) {
+                       printk(KERN_DEBUG "check SRS 0 %08X.\n", tmp);
+                       mw32(MVS_INT_STAT_SRS_0, tmp);
+               }
+       } else {
+               tmp = mr32(MVS_INT_STAT_SRS_0);
+               if (tmp &  (1 << (reg_set % 32))) {
+                       printk(KERN_DEBUG "register set 0x%x was stopped.\n",
+                              reg_set);
+                       mw32(MVS_INT_STAT_SRS_0, 1 << (reg_set % 32));
+               }
+       }
+}
+
 static int __devinit mvs_64xx_chip_reset(struct mvs_info *mvi)
 {
        void __iomem *regs = mvi->regs;
@@ -761,6 +781,7 @@ const struct mvs_dispatch mvs_64xx_dispatch = {
        mvs_write_port_irq_mask,
        mvs_get_sas_addr,
        mvs_64xx_command_active,
+       mvs_64xx_clear_srs_irq,
        mvs_64xx_issue_stop,
        mvs_start_delivery,
        mvs_rx_update,
index 0940fae19d2093899304b39baeb3fdae2046d035..eed4c5c7201363b0af9fe60bed13d19a3cd6d94f 100644 (file)
@@ -616,6 +616,15 @@ void mvs_94xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
 }
 #endif
 
+/*
+ * FIXME JEJB: temporary nop clear_srs_irq to make 94xx still work
+ * with 64xx fixes
+ */
+static void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set,
+                                  u8 clear_all)
+{
+}
+
 const struct mvs_dispatch mvs_94xx_dispatch = {
        "mv94xx",
        mvs_94xx_init,
@@ -640,6 +649,7 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
        mvs_write_port_irq_mask,
        mvs_get_sas_addr,
        mvs_94xx_command_active,
+       mvs_94xx_clear_srs_irq,
        mvs_94xx_issue_stop,
        mvs_start_delivery,
        mvs_rx_update,
index cae6b2cf492fb099cd2b7b6a2257dd8a768c2105..19ad34f381a59e5b08264eb28398b3d7cf1e4f63 100644 (file)
@@ -37,6 +37,7 @@ static const struct mvs_chip_info mvs_chips[] = {
 };
 
 #define SOC_SAS_NUM 2
+#define SG_MX 64
 
 static struct scsi_host_template mvs_sht = {
        .module                 = THIS_MODULE,
@@ -53,10 +54,10 @@ static struct scsi_host_template mvs_sht = {
        .can_queue              = 1,
        .cmd_per_lun            = 1,
        .this_id                = -1,
-       .sg_tablesize           = SG_ALL,
+       .sg_tablesize           = SG_MX,
        .max_sectors            = SCSI_DEFAULT_MAX_SECTORS,
        .use_clustering         = ENABLE_CLUSTERING,
-       .eh_device_reset_handler        = sas_eh_device_reset_handler,
+       .eh_device_reset_handler = sas_eh_device_reset_handler,
        .eh_bus_reset_handler   = sas_eh_bus_reset_handler,
        .slave_alloc            = mvs_slave_alloc,
        .target_destroy         = sas_target_destroy,
@@ -65,19 +66,17 @@ static struct scsi_host_template mvs_sht = {
 
 static struct sas_domain_function_template mvs_transport_ops = {
        .lldd_dev_found         = mvs_dev_found,
-       .lldd_dev_gone  = mvs_dev_gone,
-
+       .lldd_dev_gone          = mvs_dev_gone,
        .lldd_execute_task      = mvs_queue_command,
        .lldd_control_phy       = mvs_phy_control,
 
        .lldd_abort_task        = mvs_abort_task,
        .lldd_abort_task_set    = mvs_abort_task_set,
        .lldd_clear_aca         = mvs_clear_aca,
-       .lldd_clear_task_set    = mvs_clear_task_set,
+       .lldd_clear_task_set    = mvs_clear_task_set,
        .lldd_I_T_nexus_reset   = mvs_I_T_nexus_reset,
        .lldd_lu_reset          = mvs_lu_reset,
        .lldd_query_task        = mvs_query_task,
-
        .lldd_port_formed       = mvs_port_formed,
        .lldd_port_deformed     = mvs_port_deformed,
 
@@ -213,7 +212,7 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)
 
 static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
 {
-       int i, slot_nr;
+       int i = 0, slot_nr;
 
        if (mvi->flags & MVF_FLAG_SOC)
                slot_nr = MVS_SOC_SLOTS;
@@ -232,6 +231,7 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
                mvi->devices[i].dev_type = NO_DEVICE;
                mvi->devices[i].device_id = i;
                mvi->devices[i].dev_status = MVS_DEV_NORMAL;
+               init_timer(&mvi->devices[i].timer);
        }
 
        /*
@@ -437,6 +437,7 @@ static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost,
 
        sha->sas_phy = arr_phy;
        sha->sas_port = arr_port;
+       sha->core.shost = shost;
 
        sha->lldd_ha = kzalloc(sizeof(struct mvs_prv_info), GFP_KERNEL);
        if (!sha->lldd_ha)
@@ -574,6 +575,10 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
                }
                nhost++;
        } while (nhost < chip->n_host);
+#ifdef MVS_USE_TASKLET
+       tasklet_init(&mv_tasklet, mvs_tasklet,
+                    (unsigned long)SHOST_TO_SAS_HA(shost));
+#endif
 
        mvs_post_sas_ha_init(shost, chip);
 
index 0d2138641214f22f0d3c9431e66ee5b506a63c9c..f5e321791903dabc50ee6f39d74d29f46d5da3e5 100644 (file)
@@ -259,8 +259,6 @@ static inline void mvs_free_reg_set(struct mvs_info *mvi,
                mv_printk("device has been free.\n");
                return;
        }
-       if (dev->runing_req != 0)
-               return;
        if (dev->taskfileset == MVS_ID_NOT_MAPPED)
                return;
        MVS_CHIP_DISP->free_reg_set(mvi, &dev->taskfileset);
@@ -762,8 +760,6 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
        }
        if (is_tmf)
                flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT);
-       else
-               flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT);
        hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT));
        hdr->tags = cpu_to_le32(tag);
        hdr->data_len = cpu_to_le32(task->total_xfer_len);
@@ -878,14 +874,15 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
        struct mvs_slot_info *slot;
        u32 tag = 0xdeadbeef, rc, n_elem = 0;
        u32 n = num, pass = 0;
-       unsigned long flags = 0;
+       unsigned long flags = 0,  flags_libsas = 0;
 
        if (!dev->port) {
                struct task_status_struct *tsm = &t->task_status;
 
                tsm->resp = SAS_TASK_UNDELIVERED;
                tsm->stat = SAS_PHY_DOWN;
-               t->task_done(t);
+               if (dev->dev_type != SATA_DEV)
+                       t->task_done(t);
                return 0;
        }
 
@@ -910,12 +907,25 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
                else
                        tei.port = &mvi->port[dev->port->id];
 
-               if (!tei.port->port_attached) {
+               if (tei.port && !tei.port->port_attached) {
                        if (sas_protocol_ata(t->task_proto)) {
+                               struct task_status_struct *ts = &t->task_status;
+
                                mv_dprintk("port %d does not"
                                        "attached device.\n", dev->port->id);
-                               rc = SAS_PHY_DOWN;
-                               goto out_done;
+                               ts->stat = SAS_PROTO_RESPONSE;
+                               ts->stat = SAS_PHY_DOWN;
+                               spin_unlock_irqrestore(dev->sata_dev.ap->lock,
+                                                      flags_libsas);
+                               spin_unlock_irqrestore(&mvi->lock, flags);
+                               t->task_done(t);
+                               spin_lock_irqsave(&mvi->lock, flags);
+                               spin_lock_irqsave(dev->sata_dev.ap->lock,
+                                                 flags_libsas);
+                               if (n > 1)
+                                       t = list_entry(t->list.next,
+                                                      struct sas_task, list);
+                               continue;
                        } else {
                                struct task_status_struct *ts = &t->task_status;
                                ts->resp = SAS_TASK_UNDELIVERED;
@@ -973,8 +983,8 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
                        break;
                default:
                        dev_printk(KERN_ERR, mvi->dev,
-                               "unknown sas_task proto: 0x%x\n",
-                               t->task_proto);
+                                  "unknown sas_task proto: 0x%x\n",
+                                  t->task_proto);
                        rc = -EINVAL;
                        break;
                }
@@ -993,11 +1003,15 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
                spin_unlock(&t->task_state_lock);
 
                mvs_hba_memory_dump(mvi, tag, t->task_proto);
-               mvi_dev->runing_req++;
+               mvi_dev->running_req++;
                ++pass;
                mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
                if (n > 1)
                        t = list_entry(t->list.next, struct sas_task, list);
+               if (likely(pass))
+                       MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) &
+                                                     (MVS_CHIP_SLOT_SZ - 1));
+
        } while (--n);
        rc = 0;
        goto out_done;
@@ -1012,10 +1026,6 @@ err_out:
                        dma_unmap_sg(mvi->dev, t->scatter, n_elem,
                                     t->data_dir);
 out_done:
-       if (likely(pass)) {
-               MVS_CHIP_DISP->start_delivery(mvi,
-                       (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
-       }
        spin_unlock_irqrestore(&mvi->lock, flags);
        return rc;
 }
@@ -1187,7 +1197,7 @@ void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
                                MVS_CHIP_DISP->phy_reset(mvi, i, 0);
                                goto out_done;
                        }
-               }               else if (phy->phy_type & PORT_TYPE_SAS
+               }       else if (phy->phy_type & PORT_TYPE_SAS
                        || phy->att_dev_info & PORT_SSP_INIT_MASK) {
                        phy->phy_attached = 1;
                        phy->identify.device_type =
@@ -1256,7 +1266,20 @@ static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)
 
 static void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock)
 {
-       /*Nothing*/
+       struct domain_device *dev;
+       struct mvs_phy *phy = sas_phy->lldd_phy;
+       struct mvs_info *mvi = phy->mvi;
+       struct asd_sas_port *port = sas_phy->port;
+       int phy_no = 0;
+
+       while (phy != &mvi->phy[phy_no]) {
+               phy_no++;
+               if (phy_no >= MVS_MAX_PHYS)
+                       return;
+       }
+       list_for_each_entry(dev, &port->dev_list, dev_list_node)
+               mvs_do_release_task(phy->mvi, phy_no, NULL);
+
 }
 
 
@@ -1316,6 +1339,7 @@ int mvs_dev_found_notify(struct domain_device *dev, int lock)
                goto found_out;
        }
        dev->lldd_dev = mvi_device;
+       mvi_device->dev_status = MVS_DEV_NORMAL;
        mvi_device->dev_type = dev->dev_type;
        mvi_device->mvi_info = mvi;
        if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
@@ -1351,18 +1375,18 @@ int mvs_dev_found(struct domain_device *dev)
        return mvs_dev_found_notify(dev, 1);
 }
 
-void mvs_dev_gone_notify(struct domain_device *dev, int lock)
+void mvs_dev_gone_notify(struct domain_device *dev)
 {
        unsigned long flags = 0;
        struct mvs_device *mvi_dev = dev->lldd_dev;
        struct mvs_info *mvi = mvi_dev->mvi_info;
 
-       if (lock)
-               spin_lock_irqsave(&mvi->lock, flags);
+       spin_lock_irqsave(&mvi->lock, flags);
 
        if (mvi_dev) {
                mv_dprintk("found dev[%d:%x] is gone.\n",
                        mvi_dev->device_id, mvi_dev->dev_type);
+               mvs_release_task(mvi, dev);
                mvs_free_reg_set(mvi, mvi_dev);
                mvs_free_dev(mvi_dev);
        } else {
@@ -1370,14 +1394,13 @@ void mvs_dev_gone_notify(struct domain_device *dev, int lock)
        }
        dev->lldd_dev = NULL;
 
-       if (lock)
-               spin_unlock_irqrestore(&mvi->lock, flags);
+       spin_unlock_irqrestore(&mvi->lock, flags);
 }
 
 
 void mvs_dev_gone(struct domain_device *dev)
 {
-       mvs_dev_gone_notify(dev, 1);
+       mvs_dev_gone_notify(dev);
 }
 
 static  struct sas_task *mvs_alloc_task(void)
@@ -1540,7 +1563,7 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun)
                num = mvs_find_dev_phyno(dev, phyno);
                spin_lock_irqsave(&mvi->lock, flags);
                for (i = 0; i < num; i++)
-                       mvs_release_task(mvi, phyno[i], dev);
+                       mvs_release_task(mvi, dev);
                spin_unlock_irqrestore(&mvi->lock, flags);
        }
        /* If failed, fall-through I_T_Nexus reset */
@@ -1552,8 +1575,8 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun)
 int mvs_I_T_nexus_reset(struct domain_device *dev)
 {
        unsigned long flags;
-       int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED;
-       struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev;
+       int rc = TMF_RESP_FUNC_FAILED;
+    struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev;
        struct mvs_info *mvi = mvi_dev->mvi_info;
 
        if (mvi_dev->dev_status != MVS_DEV_EH)
@@ -1563,10 +1586,8 @@ int mvs_I_T_nexus_reset(struct domain_device *dev)
                __func__, mvi_dev->device_id, rc);
 
        /* housekeeper */
-       num = mvs_find_dev_phyno(dev, phyno);
        spin_lock_irqsave(&mvi->lock, flags);
-       for (i = 0; i < num; i++)
-               mvs_release_task(mvi, phyno[i], dev);
+       mvs_release_task(mvi, dev);
        spin_unlock_irqrestore(&mvi->lock, flags);
 
        return rc;
@@ -1603,6 +1624,9 @@ int mvs_query_task(struct sas_task *task)
                case TMF_RESP_FUNC_FAILED:
                case TMF_RESP_FUNC_COMPLETE:
                        break;
+               default:
+                       rc = TMF_RESP_FUNC_COMPLETE;
+                       break;
                }
        }
        mv_printk("%s:rc= %d\n", __func__, rc);
@@ -1621,8 +1645,11 @@ int mvs_abort_task(struct sas_task *task)
        unsigned long flags;
        u32 tag;
 
-       if (mvi->exp_req)
-               mvi->exp_req--;
+       if (!mvi_dev) {
+               mv_printk("%s:%d TMF_RESP_FUNC_FAILED\n", __func__, __LINE__);
+               rc = 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);
@@ -1630,6 +1657,7 @@ int mvs_abort_task(struct sas_task *task)
                goto out;
        }
        spin_unlock_irqrestore(&task->task_state_lock, flags);
+       mvi_dev->dev_status = MVS_DEV_EH;
        if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
                struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task;
 
@@ -1654,12 +1682,31 @@ int mvs_abort_task(struct sas_task *task)
                        if (task->lldd_task) {
                                slot = task->lldd_task;
                                slot_no = (u32) (slot - mvi->slot_info);
+                               spin_lock_irqsave(&mvi->lock, flags);
                                mvs_slot_complete(mvi, slot_no, 1);
+                               spin_unlock_irqrestore(&mvi->lock, flags);
                        }
                }
+
        } else if (task->task_proto & SAS_PROTOCOL_SATA ||
                task->task_proto & SAS_PROTOCOL_STP) {
                /* to do free register_set */
+               if (SATA_DEV == dev->dev_type) {
+                       struct mvs_slot_info *slot = task->lldd_task;
+                       struct task_status_struct *tstat;
+                       u32 slot_idx = (u32)(slot - mvi->slot_info);
+                       tstat = &task->task_status;
+                       mv_dprintk(KERN_DEBUG "mv_abort_task() mvi=%p task=%p "
+                                  "slot=%p slot_idx=x%x\n",
+                                  mvi, task, slot, slot_idx);
+                       tstat->stat = SAS_ABORTED_TASK;
+                       if (mvi_dev && mvi_dev->running_req)
+                               mvi_dev->running_req--;
+                       if (sas_protocol_ata(task->task_proto))
+                               mvs_free_reg_set(mvi, mvi_dev);
+                       mvs_slot_task_free(mvi, task, slot, slot_idx);
+                       return -1;
+               }
        } else {
                /* SMP */
 
@@ -1717,8 +1764,13 @@ static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
               SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset),
               sizeof(struct dev_to_host_fis));
        tstat->buf_valid_size = sizeof(*resp);
-       if (unlikely(err))
-               stat = SAS_PROTO_RESPONSE;
+       if (unlikely(err)) {
+               if (unlikely(err & CMD_ISS_STPD))
+                       stat = SAS_OPEN_REJECT;
+               else
+                       stat = SAS_PROTO_RESPONSE;
+       }
+
        return stat;
 }
 
@@ -1753,9 +1805,7 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
                        mv_printk("find reserved error, why?\n");
 
                task->ata_task.use_ncq = 0;
-               stat = SAS_PROTO_RESPONSE;
-               mvs_sata_done(mvi, task, slot_idx, 1);
-
+               mvs_sata_done(mvi, task, slot_idx, err_dw0);
        }
                break;
        default:
@@ -1772,18 +1822,20 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
        struct sas_task *task = slot->task;
        struct mvs_device *mvi_dev = NULL;
        struct task_status_struct *tstat;
+       struct domain_device *dev;
+       u32 aborted;
 
-       bool aborted;
        void *to;
        enum exec_status sts;
 
        if (mvi->exp_req)
                mvi->exp_req--;
-       if (unlikely(!task || !task->lldd_task))
+       if (unlikely(!task || !task->lldd_task || !task->dev))
                return -1;
 
        tstat = &task->task_status;
-       mvi_dev = task->dev->lldd_dev;
+       dev = task->dev;
+       mvi_dev = dev->lldd_dev;
 
        mvs_hba_cq_dump(mvi);
 
@@ -1800,8 +1852,8 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
 
        if (unlikely(aborted)) {
                tstat->stat = SAS_ABORTED_TASK;
-               if (mvi_dev)
-                       mvi_dev->runing_req--;
+               if (mvi_dev && mvi_dev->running_req)
+                       mvi_dev->running_req--;
                if (sas_protocol_ata(task->task_proto))
                        mvs_free_reg_set(mvi, mvi_dev);
 
@@ -1809,24 +1861,17 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
                return -1;
        }
 
-       if (unlikely(!mvi_dev || !slot->port->port_attached || flags)) {
-               mv_dprintk("port has not device.\n");
+       if (unlikely(!mvi_dev || flags)) {
+               if (!mvi_dev)
+                       mv_dprintk("port has not device.\n");
                tstat->stat = SAS_PHY_DOWN;
                goto out;
        }
 
-       /*
-       if (unlikely((rx_desc & RXQ_ERR) || (*(u64 *) slot->response))) {
-                mv_dprintk("Find device[%016llx] RXQ_ERR %X,
-                err info:%016llx\n",
-                SAS_ADDR(task->dev->sas_addr),
-                rx_desc, (u64)(*(u64 *) slot->response));
-       }
-       */
-
        /* error info record present */
        if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
                tstat->stat = mvs_slot_err(mvi, task, slot_idx);
+               tstat->resp = SAS_TASK_COMPLETE;
                goto out;
        }
 
@@ -1868,11 +1913,16 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
                tstat->stat = SAM_CHECK_COND;
                break;
        }
+       if (!slot->port->port_attached) {
+               mv_dprintk("port %d has removed.\n", slot->port->sas_port.id);
+               tstat->stat = SAS_PHY_DOWN;
+       }
+
 
 out:
-       if (mvi_dev) {
-               mvi_dev->runing_req--;
-               if (sas_protocol_ata(task->task_proto))
+       if (mvi_dev && mvi_dev->running_req) {
+               mvi_dev->running_req--;
+               if (sas_protocol_ata(task->task_proto) && !mvi_dev->running_req)
                        mvs_free_reg_set(mvi, mvi_dev);
        }
        mvs_slot_task_free(mvi, task, slot, slot_idx);
@@ -1888,10 +1938,10 @@ out:
        return sts;
 }
 
-void mvs_release_task(struct mvs_info *mvi,
+void mvs_do_release_task(struct mvs_info *mvi,
                int phy_no, struct domain_device *dev)
 {
-       int i = 0; u32 slot_idx;
+       u32 slot_idx;
        struct mvs_phy *phy;
        struct mvs_port *port;
        struct mvs_slot_info *slot, *slot2;
@@ -1900,6 +1950,10 @@ void mvs_release_task(struct mvs_info *mvi,
        port = phy->port;
        if (!port)
                return;
+       /* clean cmpl queue in case request is already finished */
+       mvs_int_rx(mvi, false);
+
+
 
        list_for_each_entry_safe(slot, slot2, &port->list, entry) {
                struct sas_task *task;
@@ -1911,18 +1965,22 @@ void mvs_release_task(struct mvs_info *mvi,
 
                mv_printk("Release slot [%x] tag[%x], task [%p]:\n",
                        slot_idx, slot->slot_tag, task);
-
-               if (task->task_proto & SAS_PROTOCOL_SSP) {
-                       mv_printk("attached with SSP task CDB[");
-                       for (i = 0; i < 16; i++)
-                               mv_printk(" %02x", task->ssp_task.cdb[i]);
-                       mv_printk(" ]\n");
-               }
+               MVS_CHIP_DISP->command_active(mvi, slot_idx);
 
                mvs_slot_complete(mvi, slot_idx, 1);
        }
 }
 
+void mvs_release_task(struct mvs_info *mvi,
+                     struct domain_device *dev)
+{
+       int i, phyno[WIDE_PORT_MAX_PHY], num;
+       /* housekeeper */
+       num = mvs_find_dev_phyno(dev, phyno);
+       for (i = 0; i < num; i++)
+               mvs_do_release_task(mvi, phyno[i], dev);
+}
+
 static void mvs_phy_disconnected(struct mvs_phy *phy)
 {
        phy->phy_attached = 0;
@@ -2029,16 +2087,18 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
        * we need check the interrupt status which belongs to per port.
        */
 
-       if (phy->irq_status & PHYEV_DCDR_ERR)
+       if (phy->irq_status & PHYEV_DCDR_ERR) {
                mv_dprintk("port %d STP decoding error.\n",
-               phy_no+mvi->id*mvi->chip->n_phy);
+               phy_no + mvi->id*mvi->chip->n_phy);
+       }
 
        if (phy->irq_status & PHYEV_POOF) {
                if (!(phy->phy_event & PHY_PLUG_OUT)) {
                        int dev_sata = phy->phy_type & PORT_TYPE_SATA;
                        int ready;
-                       mvs_release_task(mvi, phy_no, NULL);
+                       mvs_do_release_task(mvi, phy_no, NULL);
                        phy->phy_event |= PHY_PLUG_OUT;
+                       MVS_CHIP_DISP->clear_srs_irq(mvi, 0, 1);
                        mvs_handle_event(mvi,
                                (void *)(unsigned long)phy_no,
                                PHY_PLUG_EVENT);
@@ -2085,6 +2145,11 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                                                        phy_no, tmp);
                        }
                        mvs_update_phyinfo(mvi, phy_no, 0);
+                       if (phy->phy_type & PORT_TYPE_SAS) {
+                               MVS_CHIP_DISP->phy_reset(mvi, phy_no, 2);
+                               mdelay(10);
+                       }
+
                        mvs_bytes_dmaed(mvi, phy_no);
                        /* whether driver is going to handle hot plug */
                        if (phy->phy_event & PHY_PLUG_OUT) {
index 885858bcc403b56e906a30bc5883d21d2b4e761c..77ddc7c1e5f2ea140c2b44a174e2b5646003e5cb 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <scsi/libsas.h>
+#include <scsi/scsi.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/sas_ata.h>
 #include <linux/version.h>
@@ -49,7 +50,7 @@
 #define _MV_DUMP               0
 #define MVS_ID_NOT_MAPPED      0x7f
 /* #define DISABLE_HOTPLUG_DMA_FIX */
-#define MAX_EXP_RUNNING_REQ    2
+// #define MAX_EXP_RUNNING_REQ 2
 #define WIDE_PORT_MAX_PHY              4
 #define        MV_DISABLE_NCQ  0
 #define mv_printk(fmt, arg ...)        \
@@ -129,6 +130,7 @@ struct mvs_dispatch {
 
        void (*get_sas_addr)(void *buf, u32 buflen);
        void (*command_active)(struct mvs_info *mvi, u32 slot_idx);
+       void (*clear_srs_irq)(struct mvs_info *mvi, u8 reg_set, u8 clear_all);
        void (*issue_stop)(struct mvs_info *mvi, enum mvs_port_type type,
                                u32 tfs);
        void (*start_delivery)(struct mvs_info *mvi, u32 tx);
@@ -236,9 +238,10 @@ struct mvs_device {
        enum sas_dev_type dev_type;
        struct mvs_info *mvi_info;
        struct domain_device *sas_device;
+       struct timer_list timer;
        u32 attached_phy;
        u32 device_id;
-       u32 runing_req;
+       u32 running_req;
        u8 taskfileset;
        u8 dev_status;
        u16 reserved;
@@ -397,7 +400,9 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun);
 int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags);
 int mvs_I_T_nexus_reset(struct domain_device *dev);
 int mvs_query_task(struct sas_task *task);
-void mvs_release_task(struct mvs_info *mvi, int phy_no,
+void mvs_release_task(struct mvs_info *mvi,
+                       struct domain_device *dev);
+void mvs_do_release_task(struct mvs_info *mvi, int phy_no,
                        struct domain_device *dev);
 void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
 void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);