[SCSI] mvsas: Add support for Non specific NCQ error interrupt
authorXiangliang Yu <yuxiangl@marvell.com>
Tue, 24 May 2011 14:26:50 +0000 (22:26 +0800)
committerJames Bottomley <JBottomley@Parallels.com>
Tue, 26 Jul 2011 06:25:02 +0000 (10:25 +0400)
Signed-off-by: Xiangliang Yu <yuxiangl@marvell.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/mvsas/mv_64xx.c
drivers/scsi/mvsas/mv_94xx.c
drivers/scsi/mvsas/mv_chips.h
drivers/scsi/mvsas/mv_defs.h
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/mvsas/mv_sas.h

index 13c960481391e8590d0b7b2e3163f58022ca424f..0e13e6441da7e283fc0ba8752e9b95a0fc443dd7 100644 (file)
@@ -811,5 +811,6 @@ const struct mvs_dispatch mvs_64xx_dispatch = {
 #ifndef DISABLE_HOTPLUG_DMA_FIX
        mvs_64xx_fix_dma,
 #endif
+       NULL,
 };
 
index 78162c3c36e611ea2e5a2ecb2d1951f10a0ef284..9d60c7c19b32977c3968c539b2ec5f0bf5d72087 100644 (file)
@@ -249,7 +249,7 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
 
        /* enable completion queue interrupt */
        tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP |
-               CINT_DMA_PCIE);
+               CINT_DMA_PCIE | CINT_NON_SPEC_NCQ_ERROR);
        tmp |= CINT_PHY_MASK;
        mw32(MVS_INT_MASK, tmp);
 
@@ -367,6 +367,35 @@ static void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type,
        mw32(MVS_PCS, tmp);
 }
 
+static void mvs_94xx_non_spec_ncq_error(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       u32 err_0, err_1;
+       u8 i;
+       struct mvs_device *device;
+
+       err_0 = mr32(MVS_NON_NCQ_ERR_0);
+       err_1 = mr32(MVS_NON_NCQ_ERR_1);
+
+       mv_dprintk("non specific ncq error err_0:%x,err_1:%x.\n",
+                       err_0, err_1);
+       for (i = 0; i < 32; i++) {
+               if (err_0 & bit(i)) {
+                       device = mvs_find_dev_by_reg_set(mvi, i);
+                       if (device)
+                               mvs_release_task(mvi, device->sas_device);
+               }
+               if (err_1 & bit(i)) {
+                       device = mvs_find_dev_by_reg_set(mvi, i+32);
+                       if (device)
+                               mvs_release_task(mvi, device->sas_device);
+               }
+       }
+
+       mw32(MVS_NON_NCQ_ERR_0, err_0);
+       mw32(MVS_NON_NCQ_ERR_1, err_1);
+}
+
 static void mvs_94xx_free_reg_set(struct mvs_info *mvi, u8 *tfs)
 {
        void __iomem *regs = mvi->regs;
@@ -679,5 +708,6 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
 #ifndef DISABLE_HOTPLUG_DMA_FIX
        mvs_94xx_fix_dma,
 #endif
+       mvs_94xx_non_spec_ncq_error,
 };
 
index 1753a6fc42d02851c74449bceffbe6944b59d211..4519f809a8df128145b4d0bc44f9d46b51d06062 100644 (file)
@@ -223,6 +223,9 @@ static inline void mvs_int_full(struct mvs_info *mvi)
                        mvs_int_port(mvi, i, tmp);
        }
 
+       if (stat & CINT_NON_SPEC_NCQ_ERROR)
+               MVS_CHIP_DISP->non_spec_ncq_error(mvi);
+
        if (stat & CINT_SRS)
                mvs_int_sata(mvi);
 
index bc00c940743c0394812aebcd91df07590e86beac..9202bc68801dc053b94e33c702122e0081e82def 100644 (file)
@@ -144,6 +144,7 @@ enum hw_register_bits {
        CINT_DMA_PCIE           = (1U << 27),   /* DMA to PCIE timeout */
        CINT_MEM                = (1U << 26),   /* int mem parity err */
        CINT_I2C_SLAVE          = (1U << 25),   /* slave I2C event */
+       CINT_NON_SPEC_NCQ_ERROR = (1U << 25),   /* Non specific NCQ error */
        CINT_SRS                = (1U << 3),    /* SRS event */
        CINT_CI_STOP            = (1U << 1),    /* cmd issue stopped */
        CINT_DONE               = (1U << 0),    /* cmd completion */
index 0ef27425c4471bdeeccdae6f62691c8e8a1887e9..aaa475a3eda6a8e23ad84c2ad95386199ae17b39 100644 (file)
@@ -253,6 +253,20 @@ int mvs_find_dev_phyno(struct domain_device *dev, int *phyno)
        return num;
 }
 
+struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi,
+                                               u8 reg_set)
+{
+       u32 dev_no;
+       for (dev_no = 0; dev_no < MVS_MAX_DEVICES; dev_no++) {
+               if (mvi->devices[dev_no].taskfileset == MVS_ID_NOT_MAPPED)
+                       continue;
+
+               if (mvi->devices[dev_no].taskfileset == reg_set)
+                       return &mvi->devices[dev_no];
+       }
+       return NULL;
+}
+
 static inline void mvs_free_reg_set(struct mvs_info *mvi,
                                struct mvs_device *dev)
 {
index 1367d8b9350de4580f32b64f9b4d8dc9520a2575..f96100d7aee18d70440643c997c0cd672e68c13a 100644 (file)
@@ -170,6 +170,7 @@ struct mvs_dispatch {
 #ifndef DISABLE_HOTPLUG_DMA_FIX
        void (*dma_fix)(dma_addr_t buf_dma, int buf_len, int from, void *prd);
 #endif
+       void (*non_spec_ncq_error)(struct mvs_info *mvi);
 
 };
 
@@ -416,5 +417,6 @@ 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);
 int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
 void mvs_hexdump(u32 size, u8 *data, u32 baseaddr);
+struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, u8 reg_set);
 #endif