From 534ff10104427ccad071ef87ae7017d47d08e50b Mon Sep 17 00:00:00 2001 From: Xiangliang Yu Date: Tue, 24 May 2011 22:26:50 +0800 Subject: [SCSI] mvsas: Add support for Non specific NCQ error interrupt Signed-off-by: Xiangliang Yu Signed-off-by: James Bottomley --- drivers/scsi/mvsas/mv_64xx.c | 1 + drivers/scsi/mvsas/mv_94xx.c | 32 +++++++++++++++++++++++++++++++- drivers/scsi/mvsas/mv_chips.h | 3 +++ drivers/scsi/mvsas/mv_defs.h | 1 + drivers/scsi/mvsas/mv_sas.c | 14 ++++++++++++++ drivers/scsi/mvsas/mv_sas.h | 2 ++ 6 files changed, 52 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/mvsas') diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c index 13c960481391..0e13e6441da7 100644 --- a/drivers/scsi/mvsas/mv_64xx.c +++ b/drivers/scsi/mvsas/mv_64xx.c @@ -811,5 +811,6 @@ const struct mvs_dispatch mvs_64xx_dispatch = { #ifndef DISABLE_HOTPLUG_DMA_FIX mvs_64xx_fix_dma, #endif + NULL, }; diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c index 78162c3c36e6..9d60c7c19b32 100644 --- a/drivers/scsi/mvsas/mv_94xx.c +++ b/drivers/scsi/mvsas/mv_94xx.c @@ -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, }; diff --git a/drivers/scsi/mvsas/mv_chips.h b/drivers/scsi/mvsas/mv_chips.h index 1753a6fc42d0..4519f809a8df 100644 --- a/drivers/scsi/mvsas/mv_chips.h +++ b/drivers/scsi/mvsas/mv_chips.h @@ -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); diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h index bc00c940743c..9202bc68801d 100644 --- a/drivers/scsi/mvsas/mv_defs.h +++ b/drivers/scsi/mvsas/mv_defs.h @@ -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 */ diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 0ef27425c447..aaa475a3eda6 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -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) { diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index 1367d8b9350d..f96100d7aee1 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -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 -- cgit v1.2.3