From 2a6d205eeae222243b8414316ccdab29e1fd6ac5 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Thu, 30 Jul 2026 21:28:07 +0530 Subject: [PATCH] qla2x00t-32gbit: Improve firmware dump data capture Capture as much firmware dump data as possible. Save the mailbox registers at start-of-day, before firmware execution, so they are available in the dump, and allocate a guestimate dump buffer early during driver load to capture failures that happen before the final dump buffer is sized. Make template entry processing more robust: skip over any entry that fails to capture and continue with the next one, and skip entries that time out instead of aborting the whole dump. Notify udev once sysfs nodes are available in case a dump was captured before they existed. Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Link: https://patch.msgid.link/20260730155838.2119230-3-njavali@marvell.com Signed-off-by: Martin K. Petersen (Oracle) [ commit ce4f9a383d0af66c8aeaa53b8cb57b5acc531f7a upstream ] --- qla2x00t-32gbit/qla_dbg.c | 4 +- qla2x00t-32gbit/qla_def.h | 3 + qla2x00t-32gbit/qla_init.c | 120 ++++++++++++++++++++----------------- qla2x00t-32gbit/qla_os.c | 8 +++ qla2x00t-32gbit/qla_tmpl.c | 48 ++++++++++++--- 5 files changed, 116 insertions(+), 67 deletions(-) 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); }