diff --git a/qla2x00t-32gbit/qla_dbg.c b/qla2x00t-32gbit/qla_dbg.c index 9cf2fb642..cc1ebf755 100644 --- a/qla2x00t-32gbit/qla_dbg.c +++ b/qla2x00t-32gbit/qla_dbg.c @@ -172,7 +172,7 @@ qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram, if (!test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { /* no interrupt, timed out*/ - return rval; + return QLA_FUNCTION_TIMEOUT; } if (rval) { /* error completion status */ @@ -255,7 +255,7 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, __be32 *ram, if (!test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { /* no interrupt, timed out*/ - return rval; + return QLA_FUNCTION_TIMEOUT; } if (rval) { /* error completion status */ diff --git a/qla2x00t-32gbit/qla_def.h b/qla2x00t-32gbit/qla_def.h index 29b383d53..5a58845cb 100644 --- a/qla2x00t-32gbit/qla_def.h +++ b/qla2x00t-32gbit/qla_def.h @@ -4237,6 +4237,7 @@ struct qla_hw_data { #define SRB_MIN_REQ 128 mempool_t *srb_mempool; u8 port_name[WWN_SIZE]; + u16 mbregs[32]; volatile struct { uint32_t mbox_int :1; @@ -4307,6 +4308,8 @@ struct qla_hw_data { uint32_t eeh_flush:2; #define EEH_FLUSH_RDY 1 #define EEH_FLUSH_DONE 2 + uint32_t t262_fail:1; + uint32_t t272_fail:1; uint32_t secure_mcu:1; uint32_t valid_flt:1; } flags; diff --git a/qla2x00t-32gbit/qla_init.c b/qla2x00t-32gbit/qla_init.c index f59acdfbd..00ba86c89 100644 --- a/qla2x00t-32gbit/qla_init.c +++ b/qla2x00t-32gbit/qla_init.c @@ -3278,47 +3278,37 @@ qla81xx_reset_mpi(scsi_qla_host_t *vha) return qla81xx_write_mpi_register(vha, mb); } -static int -qla_chk_risc_recovery(scsi_qla_host_t *vha) +/* save MB regs at start of day for fw dump */ +static void +qla_save_mbregs(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; __le16 __iomem *mbptr = ®->mailbox0; int i; - u16 mb[32]; - int rc = QLA_SUCCESS; + u16 *mb = ha->mbregs; - if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) - return rc; + if ((!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha)) || + vha->flags.init_done) + return; - /* this check is only valid after RISC reset */ - mb[0] = rd_reg_word(mbptr); - mbptr++; - if (mb[0] == 0xf) { - rc = QLA_FUNCTION_FAILED; - - for (i = 1; i < 32; i++) { - mb[i] = rd_reg_word(mbptr); - mbptr++; - } - - ql_log(ql_log_warn, vha, 0x1015, - "RISC reset failed. mb[0-7] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", - mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6], mb[7]); - ql_log(ql_log_warn, vha, 0x1015, - "RISC reset failed. mb[8-15] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", - mb[8], mb[9], mb[10], mb[11], mb[12], mb[13], mb[14], - mb[15]); - ql_log(ql_log_warn, vha, 0x1015, - "RISC reset failed. mb[16-23] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", - mb[16], mb[17], mb[18], mb[19], mb[20], mb[21], mb[22], - mb[23]); - ql_log(ql_log_warn, vha, 0x1015, - "RISC reset failed. mb[24-31] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", - mb[24], mb[25], mb[26], mb[27], mb[28], mb[29], mb[30], - mb[31]); + for (i = 0; i < 32; i++) { + mb[i] = rd_reg_word(mbptr); + mbptr++; } - return rc; + + ql_log(ql_log_info, vha, 0x1015, + "mb[0-7] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", + mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6], mb[7]); + ql_log(ql_log_info, vha, 0x1015, + "mb[8-15] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", + mb[8], mb[9], mb[10], mb[11], mb[12], mb[13], mb[14], mb[15]); + ql_log(ql_log_info, vha, 0x1015, + "mb[16-23] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", + mb[16], mb[17], mb[18], mb[19], mb[20], mb[21], mb[22], mb[23]); + ql_log(ql_log_info, vha, 0x1015, + "mb[24-31] %04xh %04xh %04xh %04xh %04xh %04xh %04xh %04xh\n", + mb[24], mb[25], mb[26], mb[27], mb[28], mb[29], mb[30], mb[31]); } /** @@ -3337,7 +3327,6 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) uint16_t wd; static int abts_cnt; /* ISP abort retry counts */ int rval = QLA_SUCCESS; - int print = 1; spin_lock_irqsave(&ha->hardware_lock, flags); @@ -3434,9 +3423,6 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) barrier(); if (cnt) { mdelay(1); - if (print && qla_chk_risc_recovery(vha)) - print = 0; - wd = rd_reg_word(®->mailbox0); } else { rval = QLA_FUNCTION_TIMEOUT; @@ -3456,6 +3442,8 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) spin_unlock_irqrestore(&ha->hardware_lock, flags); + qla_save_mbregs(vha); + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x015f, "Driver in %s mode\n", IS_NOPOLLING_TYPE(ha) ? "Interrupt" : "Polling"); @@ -3816,18 +3804,11 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; struct rsp_que *rsp = ha->rsp_q_map[0]; - struct qla2xxx_fw_dump *fw_dump; + struct qla2xxx_fw_dump *fw_dump, *prev_fw_dump; + void *prev_mpi_fw_dump; size_t req_entry_size = qla_req_entry_size(ha); size_t rsp_entry_size = qla_rsp_entry_size(ha); - if (ha->fw_dump) { - ql_dbg(ql_dbg_init, vha, 0x00bd, - "Firmware dump already allocated.\n"); - return; - } - - ha->fw_dumped = 0; - ha->fw_dump_cap_flags = 0; dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0; req_q_size = rsp_q_size = 0; @@ -3910,13 +3891,11 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) ha->exlogin_size; } + ql_dbg(ql_dbg_init, vha, 0x00c5, + "%s dump_size %d fw_dump_len %d fw_dump_alloc_len %d\n", + __func__, dump_size, ha->fw_dump_len, ha->fw_dump_alloc_len); + if (!ha->fw_dump_len || dump_size > ha->fw_dump_alloc_len) { - - ql_dbg(ql_dbg_init, vha, 0x00c5, - "%s dump_size %d fw_dump_len %d fw_dump_alloc_len %d\n", - __func__, dump_size, ha->fw_dump_len, - ha->fw_dump_alloc_len); - fw_dump = vmalloc(dump_size); if (!fw_dump) { ql_log(ql_log_warn, vha, 0x00c4, @@ -3924,9 +3903,26 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) dump_size / 1024); } else { mutex_lock(&ha->optrom_mutex); - if (ha->fw_dumped) { - memcpy(fw_dump, ha->fw_dump, ha->fw_dump_len); - vfree(ha->fw_dump); + + if (ha->fw_dumped || ha->mpi_fw_dumped) { + prev_fw_dump = ha->fw_dump; + + if (ha->fw_dumped) + memcpy(fw_dump, prev_fw_dump, + ha->fw_dump_len); + + if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || + IS_QLA29XX(ha)) { + prev_mpi_fw_dump = ha->mpi_fw_dump; + ha->mpi_fw_dump = (char *)fw_dump + + ha->fwdt[0].dump_size; + + if (ha->mpi_fw_dumped) + memcpy(ha->mpi_fw_dump, + prev_mpi_fw_dump, + ha->mpi_fw_dump_len); + } + vfree(prev_fw_dump); ha->fw_dump = fw_dump; ha->fw_dump_alloc_len = dump_size; ql_dbg(ql_dbg_init, vha, 0x00c5, @@ -3945,7 +3941,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) { ha->mpi_fw_dump = (char *)fw_dump + - ha->fwdt[1].dump_size; + ha->fwdt[0].dump_size; mutex_unlock(&ha->optrom_mutex); return; } @@ -4343,6 +4339,16 @@ execute_fw_with_lr: rval = qla2x00_verify_checksum(vha, srisc_address); if (rval == QLA_SUCCESS) { + /* + * Alloc a guestimate dump buffer to capture any failure + * during early phase of driver load. + */ + if (ql2xallocfwdump && + (IS_QLA27XX(ha) || IS_QLA28XX(ha) || + IS_QLA29XX(ha)) && + !vha->flags.init_done) + qla2x00_alloc_fw_dump(vha); + /* Start firmware execution. */ ql_dbg(ql_dbg_init, vha, 0x00ca, "Starting firmware.\n"); @@ -4939,6 +4945,8 @@ next_check: ql_dbg(ql_dbg_init, vha, 0x00d3, "Init Firmware -- success.\n"); vha->u_ql2xexchoffld = vha->u_ql2xiniexchg = 0; + vha->hw->flags.t262_fail = 0; + vha->hw->flags.t272_fail = 0; } return (rval); diff --git a/qla2x00t-32gbit/qla_os.c b/qla2x00t-32gbit/qla_os.c index 45a7154c4..5ffffbf5f 100644 --- a/qla2x00t-32gbit/qla_os.c +++ b/qla2x00t-32gbit/qla_os.c @@ -3851,6 +3851,14 @@ skip_dpc: if (test_bit(UNLOADING, &base_vha->dpc_flags)) return -ENODEV; + /* + * FW dump can happens before sysfs nodes are created. If sysfs nodes + * are unavailable then udev script will not be able to read the fw dump. + * Notify udev to read again, now that sysfs nodes are available. + */ + if (ha->fw_dumped || ha->mpi_fw_dumped) + qla2x00_post_uevent_work(base_vha, QLA_UEVENT_CODE_FW_DUMP); + return 0; probe_failed: diff --git a/qla2x00t-32gbit/qla_tmpl.c b/qla2x00t-32gbit/qla_tmpl.c index b0a74b036..fd3984127 100644 --- a/qla2x00t-32gbit/qla_tmpl.c +++ b/qla2x00t-32gbit/qla_tmpl.c @@ -306,6 +306,12 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha, goto done; } + if (vha->hw->flags.t262_fail) { + ql_dbg(ql_dbg_misc, vha, 0xd045, + "%s: failed previously\n", __func__); + qla27xx_skip_entry(ent, buf); + goto done; + } dwords = end - start + 1; if (buf) { buf += *len; @@ -314,7 +320,12 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha, ql_dbg(ql_dbg_async, vha, 0xffff, "%s: dump ram MB failed. Area %xh start %lxh end %lxh\n", __func__, area, start, end); - return INVALID_ENTRY; + + if (rc == QLA_FUNCTION_TIMEOUT) + vha->hw->flags.t262_fail = 1; + + qla27xx_skip_entry(ent, buf); + goto done; } } *len += dwords * sizeof(uint32_t); @@ -536,13 +547,12 @@ qla27xx_fwdt_entry_t269(struct scsi_qla_host *vha, { ql_dbg(ql_dbg_misc, vha, 0xd20d, "%s: scratch [%lx]\n", __func__, *len); - qla27xx_insert32(0xaaaaaaaa, buf, len); - qla27xx_insert32(0xbbbbbbbb, buf, len); - qla27xx_insert32(0xcccccccc, buf, len); - qla27xx_insert32(0xdddddddd, buf, len); - qla27xx_insert32(*len + sizeof(uint32_t), buf, len); + + /* The data format is based on entry type t260. */ + qla27xx_insert32(offsetof(struct device_reg_24xx, mailbox0), buf, len); + qla27xx_insertbuf(vha->hw->mbregs, sizeof(vha->hw->mbregs), buf, len); if (buf) - ent->t269.scratch_size = 5 * sizeof(uint32_t); + ent->t269.scratch_size = sizeof(uint32_t) + sizeof(vha->hw->mbregs); return qla27xx_next_entry(ent); } @@ -589,17 +599,37 @@ qla27xx_fwdt_entry_t272(struct scsi_qla_host *vha, { ulong dwords = le32_to_cpu(ent->t272.count); ulong start = le32_to_cpu(ent->t272.addr); + int rc; ql_dbg(ql_dbg_misc, vha, 0xd210, "%s: rdremram [%lx]\n", __func__, *len); + + if (vha->hw->flags.t272_fail) { + ql_dbg(ql_dbg_misc, vha, 0xd04f, + "%s: failed previously\n", __func__); + qla27xx_skip_entry(ent, buf); + goto done; + } + if (buf) { ql_dbg(ql_dbg_misc, vha, 0xd02c, "%s: @%lx -> (%lx dwords)\n", __func__, start, dwords); buf += *len; - qla27xx_dump_mpi_ram(vha->hw, start, buf, dwords, &buf); + rc = qla27xx_dump_mpi_ram(vha->hw, start, buf, dwords, &buf); + if (rc != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xd01b, + "%s: dump mpi MB failed. Start %lxh dwords %lxh\n", + __func__, start, dwords); + + if (rc == QLA_FUNCTION_TIMEOUT) + vha->hw->flags.t272_fail = 1; + + qla27xx_skip_entry(ent, buf); + goto done; + } } *len += dwords * sizeof(uint32_t); - +done: return qla27xx_next_entry(ent); }