From 5b5a8cc2a74e34a79141c1d60324d5312298c9f7 Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Thu, 23 Jul 2026 10:33:20 +0530 Subject: [PATCH] scsi: qla2xxx: Add NVRAM config support for 29xx adapters Extend the NVRAM read and configuration-apply paths to handle the 29xx series. The 29xx NVRAM layout is similar to the 81xx family, so reuse the existing nvram_81xx parsing while adding 29xx-specific fields and init-sequence integration. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202607141733.w1IF5m43-lkp@intel.com/ Signed-off-by: Manish Rangankar Signed-off-by: Nilesh Javali Reviewed-by: Hannes Reinecke Link: https://patch.msgid.link/20260723050413.3897522-4-njavali@marvell.com Signed-off-by: Martin K. Petersen (Oracle) --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_fw.h | 42 ++++++++++- drivers/scsi/qla2xxx/qla_init.c | 123 +++++++++++++++++++++++++------- drivers/scsi/qla2xxx/qla_os.c | 2 + 4 files changed, 141 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index b5ad6ed3d5d1..89ddf332cdbd 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -4469,6 +4469,7 @@ struct qla_hw_data { uint16_t vpd_size; uint16_t vpd_base; void *vpd; + struct qla_flash_memo_block *fiv; uint16_t loop_reset_delay; uint8_t retry_count; diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index d27d09964a24..42f6125b3cfb 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1676,6 +1676,8 @@ struct qla_flt_location { #define FLT_REG_VPD_SEC_27XX_2 0xD8 #define FLT_REG_VPD_SEC_27XX_3 0xDA #define FLT_REG_NVME_PARAMS_27XX 0x21 +#define FLT_REG_FMB_PRI 0xDF +#define FLT_REG_FMB_SEC 0x124 /* 28xx */ #define FLT_REG_AUX_IMG_PRI_28XX 0x125 @@ -2110,7 +2112,7 @@ struct nvram_81xx { * BIT 7 = SCM Disabled if BIT is set (1) * BIT 8-15 = Unused */ - uint16_t enhanced_features; + __le16 enhanced_features; uint16_t reserved_24[4]; @@ -2338,4 +2340,42 @@ struct qla_fcp_prio_cfg { #define NVRAM_DUAL_FCP_NVME_FLAG_OFFSET 0x196 +struct qla_fmb_version { + uint8_t major; + uint8_t minor; + uint8_t sub; + uint8_t build; +}; + +struct qla_fmb_upd_time { + __le16 year; + uint8_t month; + uint8_t day; + + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t reserved; +}; + +struct qla_flash_memo_block { + __le32 signature; /* "FMBS" */ +#define QLFC_FMB_SIG cpu_to_le32(0x53424D46) + __le32 length; + __le32 version; +#define QLFC_FMB_VERSION 3 + __le32 checksum; + struct qla_fmb_version ffv_ver; + struct qla_fmb_version mbi_ver; + struct { + __le16 year; + uint8_t month; + uint8_t day; + uint8_t reserve[4]; + } bld_time; + uint8_t tool_id[4]; + struct qla_fmb_upd_time upd_time; + struct qla_fmb_version tool_version; +}; + #endif diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index e23e7ac48ae2..c6e928f11758 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -4194,11 +4194,11 @@ qla24xx_detect_sfp(scsi_qla_host_t *vha) used_nvram = 0; ha->flags.lr_detected = 0; if (IS_BPM_RANGE_CAPABLE(ha) && - (nv->enhanced_features & NEF_LR_DIST_ENABLE)) { + (le16_to_cpu(nv->enhanced_features) & NEF_LR_DIST_ENABLE)) { used_nvram = 1; ha->flags.lr_detected = 1; ha->lr_distance = - (nv->enhanced_features >> LR_DIST_NV_POS) + (le16_to_cpu(nv->enhanced_features) >> LR_DIST_NV_POS) & LR_DIST_NV_MASK; } @@ -9306,35 +9306,98 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) if (IS_P3P_TYPE(ha) || IS_QLA8031(ha)) ha->vpd_size = FA_VPD_SIZE_82XX; - if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) - qla28xx_get_aux_images(vha, &active_regions); - /* Get VPD data into cache */ ha->vpd = ha->nvram + VPD_OFFSET; - faddr = ha->flt_region_vpd; - if (IS_QLA28XX(ha)) { - if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE) - faddr = ha->flt_region_vpd_sec; + if (IS_QLA29XX(ha)) { + uint16_t fw_options = 0, r_code; + uint32_t vpd_r[] = {FLT_REG_VPD_0, FLT_REG_VPD_1, + FLT_REG_VPD_2, FLT_REG_VPD_3}; + uint32_t nvram_r[] = {FLT_REG_NVRAM_0, FLT_REG_NVRAM_1, + FLT_REG_NVRAM_2, FLT_REG_NVRAM_3}; + void *buf; + + BUILD_BUG_ON((VPD_OFFSET + FA_NVRAM_VPD_SIZE + + sizeof(struct qla_flash_memo_block)) > + MAX_NVRAM_SIZE); + + ha->fiv = (struct qla_flash_memo_block *) + ((char *)ha->vpd + ha->vpd_size); + + buf = qla29xx_read_optrom_data(vha, FLT_REG_FMB_PRI, + fw_options, ha->fiv, 0, + sizeof(struct qla_flash_memo_block)); + if (!buf) { + ql_log(ql_log_info, vha, 0x01be, + "Unable to read Flash Image Version.\n"); + } else if (ha->fiv->signature != QLFC_FMB_SIG) { + ql_log(ql_log_warn, vha, 0x01bf, + "Invalid FMB signature %#x, expected %#x.\n", + le32_to_cpu(ha->fiv->signature), + le32_to_cpu(QLFC_FMB_SIG)); + ha->fiv = NULL; + } else { + ql_log(ql_log_info, vha, 0x0024, + "Flash Image Version %u.%02u.%02u\n", + ha->fiv->mbi_ver.major, + ha->fiv->mbi_ver.minor, + ha->fiv->mbi_ver.sub); + } + + if (ha->port_no >= ARRAY_SIZE(vpd_r)) { + ql_log(ql_log_warn, vha, 0x002e, + "Invalid port number %u, skipping VPD/NVRAM read.\n", + ha->port_no); + goto out_29xx; + } + + r_code = vpd_r[ha->port_no]; + buf = qla29xx_read_optrom_data(vha, r_code, fw_options, + ha->vpd, 0, ha->vpd_size); + if (!buf) + ql_log(ql_log_info, vha, 0x002d, + "Unable to read VPD info.\n"); + + r_code = nvram_r[ha->port_no]; + buf = qla29xx_read_optrom_data(vha, r_code, fw_options, + ha->nvram, 0, ha->nvram_size); + if (!buf) + ql_log(ql_log_info, vha, 0x0013, + "Unable to read nvram config info.\n"); + } else { + if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) + qla28xx_get_aux_images(vha, &active_regions); + + faddr = ha->flt_region_vpd; + if (IS_QLA28XX(ha)) { + if (active_regions.aux.vpd_nvram == + QLA27XX_SECONDARY_IMAGE) + faddr = ha->flt_region_vpd_sec; + ql_dbg(ql_dbg_init, vha, 0x0110, + "Loading %s nvram image.\n", + active_regions.aux.vpd_nvram == + QLA27XX_PRIMARY_IMAGE ? + "primary" : "secondary"); + } + ha->isp_ops->read_optrom(vha, ha->vpd, faddr << 2, + ha->vpd_size); + + /* Get NVRAM data into cache and calculate checksum. */ + faddr = ha->flt_region_nvram; + if (IS_QLA28XX(ha)) { + if (active_regions.aux.vpd_nvram == + QLA27XX_SECONDARY_IMAGE) + faddr = ha->flt_region_nvram_sec; + } ql_dbg(ql_dbg_init, vha, 0x0110, "Loading %s nvram image.\n", active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ? "primary" : "secondary"); + ha->isp_ops->read_optrom(vha, ha->nvram, faddr << 2, + ha->nvram_size); } - ha->isp_ops->read_optrom(vha, ha->vpd, faddr << 2, ha->vpd_size); - - /* Get NVRAM data into cache and calculate checksum. */ - faddr = ha->flt_region_nvram; - if (IS_QLA28XX(ha)) { - if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE) - faddr = ha->flt_region_nvram_sec; - } - ql_dbg(ql_dbg_init, vha, 0x0110, - "Loading %s nvram image.\n", - active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ? - "primary" : "secondary"); - ha->isp_ops->read_optrom(vha, ha->nvram, faddr << 2, ha->nvram_size); +out_29xx: dptr = (__force __le32 *)nv; for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++) chksum += le32_to_cpu(*dptr); @@ -9386,7 +9449,10 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) nv->login_timeout = cpu_to_le16(0); nv->firmware_options_1 = cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); - nv->firmware_options_2 = cpu_to_le32(2 << 4); + if (IS_QLA29XX(ha)) + nv->firmware_options_2 = cpu_to_le32(BIT_4); + else + nv->firmware_options_2 = cpu_to_le32(BIT_5); nv->firmware_options_2 |= cpu_to_le32(BIT_12); nv->firmware_options_3 = cpu_to_le32(2 << 13); nv->host_p = cpu_to_le32(BIT_11|BIT_10); @@ -9468,9 +9534,13 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) icb->node_name[0] &= 0xF0; } - if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) { - if ((nv->enhanced_features & BIT_7) == 0) + /* SCM Enabled in NVRAM */ + if (IS_QLA29XX(ha) || IS_QLA28XX(ha) || IS_QLA27XX(ha)) { + if ((le16_to_cpu(nv->enhanced_features) & BIT_7) == 0) { + ql_log(ql_log_info, vha, 0x0062, + "USCM enabled in NVRAM\n"); ha->flags.scm_supported_a = 1; + } } /* Set host adapter parameters. */ @@ -9546,7 +9616,8 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) /* if not running MSI-X we need handshaking on interrupts */ if (!vha->hw->flags.msix_enabled && - (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))) + (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || + IS_QLA29XX(ha))) icb->firmware_options_2 |= cpu_to_le32(BIT_22); /* Enable ZIO. */ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index ebb97329e6ea..c3eb941f71ad 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -4620,6 +4620,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, fail_free_nvram: kfree(ha->nvram); ha->nvram = NULL; + ha->fiv = NULL; fail_free_ctx_mempool: mempool_destroy(ha->ctx_mempool); ha->ctx_mempool = NULL; @@ -5085,6 +5086,7 @@ qla2x00_mem_free(struct qla_hw_data *ha) ha->optrom_buffer = NULL; kfree(ha->nvram); ha->nvram = NULL; + ha->fiv = NULL; kfree(ha->npiv_info); ha->npiv_info = NULL; kfree(ha->swl);