From b99b04b12214ff5e4a01575c3c6612ae79bc5e76 Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Wed, 10 Dec 2025 15:45:55 +0530 Subject: [PATCH] scsi: qla2xxx: Add load flash firmware mailbox support for 28xxx For 28xxx adaptor Load flash firmware mailbox load the operational firmware from flash, and also validate the checksum. Driver does not need to load the operational firmware anymore, but it still need to read fwdt from flash to build and allocate firmware dump template. Remove request_firmware() support for 28xxx adapter. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202512031128.XsuvzBv1-lkp@intel.com/ Signed-off-by: Manish Rangankar Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Link: https://patch.msgid.link/20251210101604.431868-4-njavali@marvell.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_gbl.h | 3 + drivers/scsi/qla2xxx/qla_init.c | 188 +++++++++++++++++++++++++++++++- drivers/scsi/qla2xxx/qla_mbx.c | 48 ++++++++ 4 files changed, 236 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index e44b51c5a3eb8..04bc69bb11b11 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1270,6 +1270,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) */ #define MBC_LOAD_RAM 1 /* Load RAM. */ #define MBC_EXECUTE_FIRMWARE 2 /* Execute firmware. */ +#define MBC_LOAD_FLASH_FIRMWARE 3 /* Load flash firmware. */ #define MBC_READ_RAM_WORD 5 /* Read RAM word. */ #define MBC_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */ #define MBC_VERIFY_CHECKSUM 7 /* Verify checksum. */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 55d531c19e6b2..f12b2689163de 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -344,6 +344,9 @@ qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t); extern int qla2x00_execute_fw(scsi_qla_host_t *, uint32_t); +extern int +qla28xx_load_flash_firmware(scsi_qla_host_t *vha); + extern int qla2x00_get_fw_version(scsi_qla_host_t *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 3aba4e86618fa..5183ff8134877 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -8458,6 +8458,148 @@ bool qla24xx_risc_firmware_invalid(uint32_t *dword) !(~dword[4] | ~dword[5] | ~dword[6] | ~dword[7]); } +static int +qla28xx_get_srisc_addr(scsi_qla_host_t *vha, uint32_t *srisc_addr, + uint32_t faddr) +{ + struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; + uint32_t *dcode; + int rval; + + *srisc_addr = 0; + dcode = (uint32_t *)req->ring; + + rval = qla24xx_read_flash_data(vha, dcode, faddr, 10); + if (rval) { + ql_log(ql_log_fatal, vha, 0x01aa, + "-> Failed to read flash addr + size .\n"); + return QLA_FUNCTION_FAILED; + } + + *srisc_addr = be32_to_cpu((__force __be32)dcode[2]); + return QLA_SUCCESS; +} + +static int +qla28xx_load_fw_template(scsi_qla_host_t *vha, uint32_t faddr) +{ + struct qla_hw_data *ha = vha->hw; + struct fwdt *fwdt = ha->fwdt; + struct req_que *req = ha->req_q_map[0]; + uint32_t risc_size, risc_attr = 0; + uint templates, segments, fragment; + uint32_t *dcode; + ulong dlen; + int rval; + uint j; + + dcode = (uint32_t *)req->ring; + segments = FA_RISC_CODE_SEGMENTS; + + for (j = 0; j < segments; j++) { + rval = qla24xx_read_flash_data(vha, dcode, faddr, 10); + if (rval) { + ql_log(ql_log_fatal, vha, 0x01a1, + "-> Failed to read flash addr + size .\n"); + return QLA_FUNCTION_FAILED; + } + + risc_size = be32_to_cpu((__force __be32)dcode[3]); + + if (risc_attr == 0) + risc_attr = be32_to_cpu((__force __be32)dcode[9]); + + dlen = ha->fw_transfer_size >> 2; + for (fragment = 0; fragment < risc_size; fragment++) { + if (dlen > risc_size) + dlen = risc_size; + + faddr += dlen; + risc_size -= dlen; + } + } + + templates = (risc_attr & BIT_9) ? 2 : 1; + + ql_dbg(ql_dbg_init, vha, 0x01a1, "-> templates = %u\n", templates); + + for (j = 0; j < templates; j++, fwdt++) { + vfree(fwdt->template); + fwdt->template = NULL; + fwdt->length = 0; + + dcode = (uint32_t *)req->ring; + + rval = qla24xx_read_flash_data(vha, dcode, faddr, 7); + if (rval) { + ql_log(ql_log_fatal, vha, 0x01a2, + "-> Unable to read template size.\n"); + goto failed; + } + + risc_size = be32_to_cpu((__force __be32)dcode[2]); + ql_dbg(ql_dbg_init, vha, 0x01a3, + "-> fwdt%u template array at %#x (%#x dwords)\n", + j, faddr, risc_size); + if (!risc_size || !~risc_size) { + ql_dbg(ql_dbg_init, vha, 0x01a4, + "-> fwdt%u failed to read array\n", j); + goto failed; + } + + /* skip header and ignore checksum */ + faddr += 7; + risc_size -= 8; + + ql_dbg(ql_dbg_init, vha, 0x01a5, + "-> fwdt%u template allocate template %#x words...\n", + j, risc_size); + fwdt->template = vmalloc(risc_size * sizeof(*dcode)); + if (!fwdt->template) { + ql_log(ql_log_warn, vha, 0x01a6, + "-> fwdt%u failed allocate template.\n", j); + goto failed; + } + + dcode = fwdt->template; + rval = qla24xx_read_flash_data(vha, dcode, faddr, risc_size); + + if (rval || !qla27xx_fwdt_template_valid(dcode)) { + ql_log(ql_log_warn, vha, 0x01a7, + "-> fwdt%u failed template validate (rval %x)\n", + j, rval); + goto failed; + } + + dlen = qla27xx_fwdt_template_size(dcode); + ql_dbg(ql_dbg_init, vha, 0x01a7, + "-> fwdt%u template size %#lx bytes (%#lx words)\n", + j, dlen, dlen / sizeof(*dcode)); + if (dlen > risc_size * sizeof(*dcode)) { + ql_log(ql_log_warn, vha, 0x01a8, + "-> fwdt%u template exceeds array (%-lu bytes)\n", + j, dlen - risc_size * sizeof(*dcode)); + goto failed; + } + + fwdt->length = dlen; + ql_dbg(ql_dbg_init, vha, 0x01a9, + "-> fwdt%u loaded template ok\n", j); + + faddr += risc_size + 1; + } + + return QLA_SUCCESS; + +failed: + vfree(fwdt->template); + fwdt->template = NULL; + fwdt->length = 0; + + return QLA_SUCCESS; +} + static int qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr, uint32_t faddr) @@ -8897,16 +9039,18 @@ int qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) { int rval; + uint32_t f_region = 0; struct qla_hw_data *ha = vha->hw; struct active_regions active_regions = { }; - if (ql2xfwloadbin == 2) + if (ql2xfwloadbin == 2 && !IS_QLA28XX(ha)) goto try_blob_fw; /* FW Load priority: - * 1) Firmware residing in flash. - * 2) Firmware via request-firmware interface (.bin file). - * 3) Golden-Firmware residing in flash -- (limited operation). + * 1) If 28xxx, ROM cmd to load flash firmware. + * 2) Firmware residing in flash. + * 3) Firmware via request-firmware interface (.bin file). + * 4) Golden-Firmware residing in flash -- (limited operation). */ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) @@ -8914,6 +9058,40 @@ qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) qla27xx_get_active_image(vha, &active_regions); + /* For 28XXX, always load the flash firmware using rom mbx */ + if (IS_QLA28XX(ha)) { + rval = qla28xx_load_flash_firmware(vha); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_fatal, vha, 0x019e, + "Failed to load flash firmware.\n"); + goto exit_load_risc; + } + + f_region = + (active_regions.global != QLA27XX_SECONDARY_IMAGE) ? + ha->flt_region_fw : ha->flt_region_fw_sec; + + ql_log(ql_log_info, vha, 0x019f, + "Load flash firmware successful (%s).\n", + ((active_regions.global != QLA27XX_SECONDARY_IMAGE) ? + "Primary" : "Secondary")); + + rval = qla28xx_get_srisc_addr(vha, srisc_addr, f_region); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x019f, + "failed to read srisc address\n"); + goto exit_load_risc; + } + + rval = qla28xx_load_fw_template(vha, f_region); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x01a0, + "failed to read firmware template\n"); + } + + goto exit_load_risc; + } + if (active_regions.global != QLA27XX_SECONDARY_IMAGE) goto try_primary_fw; @@ -8943,6 +9121,8 @@ try_blob_fw: ql_log(ql_log_info, vha, 0x009a, "Need firmware flash update.\n"); ha->flags.running_gold_fw = 1; + +exit_load_risc: return rval; } diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 1f01576f044b8..28bb645ace670 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -43,6 +43,7 @@ static struct rom_cmd { } rom_cmds[] = { { MBC_LOAD_RAM }, { MBC_EXECUTE_FIRMWARE }, + { MBC_LOAD_FLASH_FIRMWARE }, { MBC_READ_RAM_WORD }, { MBC_MAILBOX_REGISTER_TEST }, { MBC_VERIFY_CHECKSUM }, @@ -824,6 +825,53 @@ done: return rval; } +/* + * qla2x00_load_flash_firmware + * Load firmware from flash. + * + * Input: + * vha = adapter block pointer. + * + * Returns: + * qla28xx local function return status code. + * + * Context: + * Kernel context. + */ +int +qla28xx_load_flash_firmware(scsi_qla_host_t *vha) +{ + struct qla_hw_data *ha = vha->hw; + int rval = QLA_COMMAND_ERROR; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA28XX(ha)) + return rval; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x11a6, + "Entered %s.\n", __func__); + + mcp->mb[0] = MBC_LOAD_FLASH_FIRMWARE; + mcp->out_mb = MBX_2 | MBX_1 | MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_log_info, vha, 0x11a7, + "Failed=%x cmd error=%x img error=%x.\n", + rval, mcp->mb[1], mcp->mb[2]); + } else { + ql_dbg(ql_log_info, vha, 0x11a8, + "Done %s.\n", __func__); + } + + return rval; +} + + /* * qla_get_exlogin_status * Get extended login status -- 2.47.3