From: Tej Parkash <tej.park...@qlogic.com>

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.park...@qlogic.com>
Signed-off-by: Vikas Chaudhary <vikas.chaudh...@qlogic.com>
---
 drivers/scsi/qla4xxx/ql4_83xx.c |  144 +++++++++++++++++++++++++++++++++++++++
 drivers/scsi/qla4xxx/ql4_83xx.h |   13 ++++
 drivers/scsi/qla4xxx/ql4_glbl.h |    1 +
 drivers/scsi/qla4xxx/ql4_mbx.c  |    4 +
 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);
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to