From b1d46989c12ec4d93f274ca8378bb1a6014d244a Mon Sep 17 00:00:00 2001 From: Madhuranath Iyengar Date: Fri, 3 Sep 2010 15:20:54 -0700 Subject: [PATCH] [SCSI] qla2xxx: Handle MPI timeout indicated by AE8002 In case the MPI times out, the FW issues an async event AE8002 to indicate this to every FCoE function. The FC/FCoE driver is required to handle this, by doing a soft reset and issuing a Write MPI register mailbox command to reset the MPI. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 6 ++++ drivers/scsi/qla2xxx/qla_gbl.h | 2 ++ drivers/scsi/qla2xxx/qla_init.c | 31 +++++++++++++++++ drivers/scsi/qla2xxx/qla_isr.c | 8 ++++- drivers/scsi/qla2xxx/qla_mbx.c | 61 +++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 3a432ea0c7a3..ee15f4f10fec 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -706,6 +706,11 @@ typedef struct { #define MBC_SET_PORT_CONFIG 0x122 /* Set port configuration */ #define MBC_GET_PORT_CONFIG 0x123 /* Get port configuration */ +/* + * ISP81xx mailbox commands + */ +#define MBC_WRITE_MPI_REGISTER 0x01 /* Write MPI Register. */ + /* Firmware return data sizes */ #define FCAL_MAP_SIZE 128 @@ -2858,6 +2863,7 @@ typedef struct scsi_qla_host { #define NPIV_CONFIG_NEEDED 16 #define ISP_UNRECOVERABLE 17 #define FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */ +#define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */ uint32_t device_flags; #define SWITCH_FOUND BIT_0 diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 967bc9278bf7..c33dec827e1e 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -352,6 +352,8 @@ qla2x00_read_ram_word(scsi_qla_host_t *, uint32_t, uint32_t *); extern int qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t); +extern int +qla81xx_write_mpi_register(scsi_qla_host_t *, uint16_t *); extern int qla2x00_get_data_rate(scsi_qla_host_t *); extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f2da5c5dacdd..c2d7bb8cd53f 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -943,6 +943,19 @@ qla2x00_reset_chip(scsi_qla_host_t *vha) spin_unlock_irqrestore(&ha->hardware_lock, flags); } +/** + * qla81xx_reset_mpi() - Reset's MPI FW via Write MPI Register MBC. + * + * Returns 0 on success. + */ +int +qla81xx_reset_mpi(scsi_qla_host_t *vha) +{ + uint16_t mb[4] = {0x1010, 0, 1, 0}; + + return qla81xx_write_mpi_register(vha, mb); +} + /** * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC. * @ha: HA context @@ -957,6 +970,7 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t cnt, d2; uint16_t wd; + static int abts_cnt; /* ISP abort retry counts */ spin_lock_irqsave(&ha->hardware_lock, flags); @@ -990,6 +1004,23 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) barrier(); } + /* If required, do an MPI FW reset now */ + if (test_and_clear_bit(MPI_RESET_NEEDED, &vha->dpc_flags)) { + if (qla81xx_reset_mpi(vha) != QLA_SUCCESS) { + if (++abts_cnt < 5) { + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + set_bit(MPI_RESET_NEEDED, &vha->dpc_flags); + } else { + /* + * We exhausted the ISP abort retries. We have to + * set the board offline. + */ + abts_cnt = 0; + vha->flags.online = 0; + } + } + } + WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); RD_REG_DWORD(®->hccr); diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 6982ba70e12a..bb4d63a792aa 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -412,8 +412,14 @@ skip_rio: "Unrecoverable Hardware Error: adapter " "marked OFFLINE!\n"); vha->flags.online = 0; - } else + } else { + /* Check to see if MPI timeout occured */ + if ((mbx & MBX_3) && (ha->flags.port0)) + set_bit(MPI_RESET_NEEDED, + &vha->dpc_flags); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + } } else if (mb[1] == 0) { qla_printk(KERN_INFO, ha, "Unrecoverable Hardware Error: adapter marked " diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index d0413d56887c..52024080c393 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -3948,6 +3948,67 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data) return rval; } +int +qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb) +{ + int rval; + uint32_t stat, timer; + uint16_t mb0 = 0; + struct qla_hw_data *ha = vha->hw; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + rval = QLA_SUCCESS; + + DEBUG11(qla_printk(KERN_INFO, ha, + "%s(%ld): entered.\n", __func__, vha->host_no)); + + clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + + /* Write the MBC data to the registers */ + WRT_REG_WORD(®->mailbox0, MBC_WRITE_MPI_REGISTER); + WRT_REG_WORD(®->mailbox1, mb[0]); + WRT_REG_WORD(®->mailbox2, mb[1]); + WRT_REG_WORD(®->mailbox3, mb[2]); + WRT_REG_WORD(®->mailbox4, mb[3]); + + WRT_REG_DWORD(®->hccr, HCCRX_SET_HOST_INT); + + /* Poll for MBC interrupt */ + for (timer = 6000000; timer; timer--) { + /* Check for pending interrupts. */ + stat = RD_REG_DWORD(®->host_status); + if (stat & HSRX_RISC_INT) { + stat &= 0xff; + + if (stat == 0x1 || stat == 0x2 || + stat == 0x10 || stat == 0x11) { + set_bit(MBX_INTERRUPT, + &ha->mbx_cmd_flags); + mb0 = RD_REG_WORD(®->mailbox0); + WRT_REG_DWORD(®->hccr, + HCCRX_CLR_RISC_INT); + RD_REG_DWORD(®->hccr); + break; + } + } + udelay(5); + } + + if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) + rval = mb0 & MBS_MASK; + else + rval = QLA_FUNCTION_FAILED; + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk(KERN_INFO "%s(%ld): failed=%x mb[0]=%x.\n", + __func__, vha->host_no, rval, mb[0])); + } else { + DEBUG11(printk(KERN_INFO + "%s(%ld): done.\n", __func__, vha->host_no)); + } + + return rval; +} int qla2x00_get_data_rate(scsi_qla_host_t *vha) {