diff options
author | Tej Parkash <tej.parkash@qlogic.com> | 2012-09-20 07:35:12 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-09-24 12:49:00 +0400 |
commit | 546fef27c3a798fbcece2705c1eda9e249e22226 (patch) | |
tree | 3e10b8a6f7daeff5ecc0fddc8985e5da09ce730f /drivers/scsi/qla4xxx | |
parent | 48a859d29f3d7a855093819633abcc9c877108ef (diff) | |
download | op-kernel-dev-546fef27c3a798fbcece2705c1eda9e249e22226.zip op-kernel-dev-546fef27c3a798fbcece2705c1eda9e249e22226.tar.gz |
[SCSI] qla4xxx: Disable generating pause frames for ISP83XX
In case of FW hung ISP83XX generates continuous pause frames
which causes switch to disable port.
Added fix to disable generating pause frames in case of
FW hung
Signed-off-by: Tej Parkash <tej.parkash@qlogic.com>
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/qla4xxx')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_83xx.c | 144 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_83xx.h | 13 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_glbl.h | 1 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 4 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 15 |
5 files changed, 177 insertions, 0 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c index 8b367ef..6e9af20 100644 --- a/drivers/scsi/qla4xxx/ql4_83xx.c +++ b/drivers/scsi/qla4xxx/ql4_83xx.c @@ -1465,3 +1465,147 @@ exit_isp_reset: return rval; } + +static void qla4_83xx_dump_pause_control_regs(struct scsi_qla_host *ha) +{ + u32 val = 0, val1 = 0; + int i, status = QLA_SUCCESS; + + status = qla4_83xx_rd_reg_indirect(ha, QLA83XX_SRE_SHIM_CONTROL, &val); + DEBUG2(ql4_printk(KERN_INFO, ha, "SRE-Shim Ctrl:0x%x\n", val)); + + /* Port 0 Rx Buffer Pause Threshold Registers. */ + DEBUG2(ql4_printk(KERN_INFO, ha, + "Port 0 Rx Buffer Pause Threshold Registers[TC7..TC0]:")); + for (i = 0; i < 8; i++) { + status = qla4_83xx_rd_reg_indirect(ha, + QLA83XX_PORT0_RXB_PAUSE_THRS + (i * 0x4), &val); + DEBUG2(pr_info("0x%x ", val)); + } + + DEBUG2(pr_info("\n")); + + /* Port 1 Rx Buffer Pause Threshold Registers. */ + DEBUG2(ql4_printk(KERN_INFO, ha, + "Port 1 Rx Buffer Pause Threshold Registers[TC7..TC0]:")); + for (i = 0; i < 8; i++) { + status = qla4_83xx_rd_reg_indirect(ha, + QLA83XX_PORT1_RXB_PAUSE_THRS + (i * 0x4), &val); + DEBUG2(pr_info("0x%x ", val)); + } + + DEBUG2(pr_info("\n")); + + /* Port 0 RxB Traffic Class Max Cell Registers. */ + DEBUG2(ql4_printk(KERN_INFO, ha, + "Port 0 RxB Traffic Class Max Cell Registers[3..0]:")); + for (i = 0; i < 4; i++) { + status = qla4_83xx_rd_reg_indirect(ha, + QLA83XX_PORT0_RXB_TC_MAX_CELL + (i * 0x4), &val); + DEBUG2(pr_info("0x%x ", val)); + } + + DEBUG2(pr_info("\n")); + + /* Port 1 RxB Traffic Class Max Cell Registers. */ + DEBUG2(ql4_printk(KERN_INFO, ha, + "Port 1 RxB Traffic Class Max Cell Registers[3..0]:")); + for (i = 0; i < 4; i++) { + status = qla4_83xx_rd_reg_indirect(ha, + QLA83XX_PORT1_RXB_TC_MAX_CELL + (i * 0x4), &val); + DEBUG2(pr_info("0x%x ", val)); + } + + DEBUG2(pr_info("\n")); + + /* Port 0 RxB Rx Traffic Class Stats. */ + DEBUG2(ql4_printk(KERN_INFO, ha, + "Port 0 RxB Rx Traffic Class Stats [TC7..TC0]")); + for (i = 7; i >= 0; i--) { + status = qla4_83xx_rd_reg_indirect(ha, + QLA83XX_PORT0_RXB_TC_STATS, + &val); + val &= ~(0x7 << 29); /* Reset bits 29 to 31 */ + qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT0_RXB_TC_STATS, + (val | (i << 29))); + status = qla4_83xx_rd_reg_indirect(ha, + QLA83XX_PORT0_RXB_TC_STATS, + &val); + DEBUG2(pr_info("0x%x ", val)); + } + + DEBUG2(pr_info("\n")); + + /* Port 1 RxB Rx Traffic Class Stats. */ + DEBUG2(ql4_printk(KERN_INFO, ha, + "Port 1 RxB Rx Traffic Class Stats [TC7..TC0]")); + for (i = 7; i >= 0; i--) { + status = qla4_83xx_rd_reg_indirect(ha, + QLA83XX_PORT1_RXB_TC_STATS, + &val); + val &= ~(0x7 << 29); /* Reset bits 29 to 31 */ + qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT1_RXB_TC_STATS, + (val | (i << 29))); + status = qla4_83xx_rd_reg_indirect(ha, + QLA83XX_PORT1_RXB_TC_STATS, + &val); + DEBUG2(pr_info("0x%x ", val)); + } + + DEBUG2(pr_info("\n")); + + status = qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT2_IFB_PAUSE_THRS, + &val); + status = qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT3_IFB_PAUSE_THRS, + &val1); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n", + val, val1)); +} + +static void __qla4_83xx_disable_pause(struct scsi_qla_host *ha) +{ + int i; + + /* set SRE-Shim Control Register */ + qla4_83xx_wr_reg_indirect(ha, QLA83XX_SRE_SHIM_CONTROL, + QLA83XX_SET_PAUSE_VAL); + + for (i = 0; i < 8; i++) { + /* Port 0 Rx Buffer Pause Threshold Registers. */ + qla4_83xx_wr_reg_indirect(ha, + QLA83XX_PORT0_RXB_PAUSE_THRS + (i * 0x4), + QLA83XX_SET_PAUSE_VAL); + /* Port 1 Rx Buffer Pause Threshold Registers. */ + qla4_83xx_wr_reg_indirect(ha, + QLA83XX_PORT1_RXB_PAUSE_THRS + (i * 0x4), + QLA83XX_SET_PAUSE_VAL); + } + + for (i = 0; i < 4; i++) { + /* Port 0 RxB Traffic Class Max Cell Registers. */ + qla4_83xx_wr_reg_indirect(ha, + QLA83XX_PORT0_RXB_TC_MAX_CELL + (i * 0x4), + QLA83XX_SET_TC_MAX_CELL_VAL); + /* Port 1 RxB Traffic Class Max Cell Registers. */ + qla4_83xx_wr_reg_indirect(ha, + QLA83XX_PORT1_RXB_TC_MAX_CELL + (i * 0x4), + QLA83XX_SET_TC_MAX_CELL_VAL); + } + + qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT2_IFB_PAUSE_THRS, + QLA83XX_SET_PAUSE_VAL); + qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT3_IFB_PAUSE_THRS, + QLA83XX_SET_PAUSE_VAL); + + ql4_printk(KERN_INFO, ha, "Disabled pause frames successfully.\n"); +} + +void qla4_83xx_disable_pause(struct scsi_qla_host *ha) +{ + ha->isp_ops->idc_lock(ha); + qla4_83xx_dump_pause_control_regs(ha); + __qla4_83xx_disable_pause(ha); + ha->isp_ops->idc_unlock(ha); +} diff --git a/drivers/scsi/qla4xxx/ql4_83xx.h b/drivers/scsi/qla4xxx/ql4_83xx.h index 18d86ab..6a00f90 100644 --- a/drivers/scsi/qla4xxx/ql4_83xx.h +++ b/drivers/scsi/qla4xxx/ql4_83xx.h @@ -41,6 +41,19 @@ #define QLA83XX_CRB_IDC_VER_MINOR 0x3798 #define QLA83XX_IDC_DRV_CTRL 0x3790 #define QLA83XX_IDC_DRV_AUDIT 0x3794 +#define QLA83XX_SRE_SHIM_CONTROL 0x0D200284 +#define QLA83XX_PORT0_RXB_PAUSE_THRS 0x0B2003A4 +#define QLA83XX_PORT1_RXB_PAUSE_THRS 0x0B2013A4 +#define QLA83XX_PORT0_RXB_TC_MAX_CELL 0x0B200388 +#define QLA83XX_PORT1_RXB_TC_MAX_CELL 0x0B201388 +#define QLA83XX_PORT0_RXB_TC_STATS 0x0B20039C +#define QLA83XX_PORT1_RXB_TC_STATS 0x0B20139C +#define QLA83XX_PORT2_IFB_PAUSE_THRS 0x0B200704 +#define QLA83XX_PORT3_IFB_PAUSE_THRS 0x0B201704 + +/* set value to pause threshold value */ +#define QLA83XX_SET_PAUSE_VAL 0x0 +#define QLA83XX_SET_TC_MAX_CELL_VAL 0x03FF03FF /* qla_83xx_reg_tbl registers */ #define QLA83XX_PEG_HALT_STATUS1 0x34A8 diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 3eb5fd9..57a5a3c 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -258,6 +258,7 @@ int qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha); int qla4_8xxx_set_param(struct scsi_qla_host *ha, int param); int qla4_8xxx_update_idc_reg(struct scsi_qla_host *ha); int qla4_83xx_post_idc_ack(struct scsi_qla_host *ha); +void qla4_83xx_disable_pause(struct scsi_qla_host *ha); extern int ql4xextended_error_logging; extern int ql4xdontresethba; diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 0d3d641..3d41034 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -204,6 +204,10 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, CRB_NIU_XG_PAUSE_CTL_P0 | CRB_NIU_XG_PAUSE_CTL_P1); + } else if (is_qla8032(ha)) { + ql4_printk(KERN_INFO, ha, " %s: disabling pause transmit on port 0 & 1.\n", + __func__); + qla4_83xx_disable_pause(ha); } goto mbox_exit; } diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 3554680..ad2da9c 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -2946,6 +2946,14 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); + if (is_qla8032(ha) && + !test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { + ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n", + __func__); + /* disable pause frame for ISP83xx */ + qla4_83xx_disable_pause(ha); + } + iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) @@ -3391,6 +3399,13 @@ static void qla4xxx_do_dpc(struct work_struct *work) if (is_qla80XX(ha)) { if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { + if (is_qla8032(ha)) { + ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n", + __func__); + /* disable pause frame for ISP83xx */ + qla4_83xx_disable_pause(ha); + } + ha->isp_ops->idc_lock(ha); qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, QLA8XXX_DEV_FAILED); |