]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: qla2xxx: Add load flash firmware mailbox support for 28xxx
authorManish Rangankar <mrangankar@marvell.com>
Wed, 10 Dec 2025 10:15:55 +0000 (15:45 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 17 Dec 2025 03:34:21 +0000 (22:34 -0500)
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 <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202512031128.XsuvzBv1-lkp@intel.com/
Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Reviewed-by: Himanshu Madhani <hmadhani2024@gmail.com>
Link: https://patch.msgid.link/20251210101604.431868-4-njavali@marvell.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_mbx.c

index e44b51c5a3eb865bd1533a29c649a4696b1baac2..04bc69bb11b11b09fbeca521ebe0a76645f0e1a7 100644 (file)
@@ -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. */
index 55d531c19e6b227fc1052b53d34386b190068266..f12b2689163ded77a57d9de811d89a5f60d33804 100644 (file)
@@ -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 *);
 
index 3aba4e86618fa7ae5b7d6dbf0423050b6efea6aa..5183ff8134877e806f68d6987036ae78032b67a9 100644 (file)
@@ -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;
 }
 
index 1f01576f044b8e801fb6b5a99e41e434c9d51cc3..28bb645ace670534d204f36b3d81312a4ef364a4 100644 (file)
@@ -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