[PATCH 02/33] scsi: qla2xxx: Improve firmware dump data capture
Nilesh Javali <[email protected]> Thu, 30 Jul 2026 21:28:07 +0530
| Newsgroups | org.kernel.vger.linux-scsi |
|---|---|
| Message-ID | <[email protected]> |
From: Quinn Tran <[email protected]> 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 <[email protected]> Signed-off-by: Nilesh Javali <[email protected]> --- drivers/scsi/qla2xxx/qla_dbg.c | 4 +- drivers/scsi/qla2xxx/qla_def.h | 3 + drivers/scsi/qla2xxx/qla_init.c | 120 +++++++++++++++++--------------- drivers/scsi/qla2xxx/qla_os.c | 8 +++ drivers/scsi/qla2xxx/qla_tmpl.c | 48 ++++++++++--- 5 files changed, 116 insertions(+), 67 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index acb58daacf35..4f756468ea64 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/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/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c10414453c2d..2684d785ecbf 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -4176,6 +4176,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; @@ -4246,6 +4247,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/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 5f7bc68aab3c..fb417364fa75 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3275,47 +3275,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; - - if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) - return rc; + u16 *mb = ha->mbregs; - /* this check is only valid after RISC reset */ - mb[0] = rd_reg_word(mbptr); - mbptr++; - if (mb[0] == 0xf) { - rc = QLA_FUNCTION_FAILED; + if ((!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha)) || + vha->flags.init_done) + return; - 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]); } /** @@ -3334,7 +3324,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); @@ -3431,9 +3420,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; @@ -3453,6 +3439,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"); @@ -3813,18 +3801,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; @@ -3907,13 +3888,11 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) ha->exlogin_size; } - 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); + 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) { fw_dump = vmalloc(dump_size); if (!fw_dump) { ql_log(ql_log_warn, vha, 0x00c4, @@ -3921,9 +3900,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, @@ -3942,7 +3938,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; } @@ -4339,6 +4335,16 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) 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"); @@ -4935,6 +4941,8 @@ qla2x00_init_rings(scsi_qla_host_t *vha) 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/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5209dda45459..62c9bd0fe06d 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3721,6 +3721,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) 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/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index b0a74b036cf4..fd3984127497 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/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); } -- 2.47.3