From 10ed63fc06cb9902cc783ce8d0086c9aa97ed1e1 Mon Sep 17 00:00:00 2001 From: Joerg Pulz Date: Fri, 27 Oct 2023 17:27:37 +0200 Subject: [PATCH] isp(4): Rework firmware handling/loading Correctly identify the active firmware in flash on adapters with primary and secondary firmware region in flash. Correctly identify the active NVRAM on adapters with primary and secondary NVRAM region in flash. Loading ispfw(4) moved from isp_pci_attach() to isp_reset(). Drop the reference to ispfw(4) after using it so one can kldunload(8) it. New isp_load_ram() function to load either ispfw(4) or flash firmware into RISC's RAM. New functions to read data from flash. The old ones will be removed later. A bunch of new helper functions to identify and validate active flash regions for firmware, auxiliary and NVRAM. Overhaul ISP_FW_* macros and make use of it when comparing firmware versions. We can handle firmware versions up to 255.255.255. Firmware load priority slightly changed: For 27xx and newer adapters: - load ispfw(4) firmware - request (active) flash firmware information - compare version numbers of ispfw(4) and flash firmware - load firmware with highest version into RISC's RAM - if loading ispfw(4) is disabled or failed - load firmware from flash - if everything else fails use MBOX_LOAD_FLASH_FIRMWARE as fallback For 26xx and older adapters nothing changed: - load ispfw(4) firmware and load it into RISC's RAM - if loading ispfw(4) is disabled or failed use MBOX_EXEC_FIRMWARE - for 26xx a preceding MBOX_LOAD_FLASH_FIRMWARE is used New read only sysctl(8)'s: dev.isp.N.fw_version_run: the firmware version actually running dev.isp.N.fw_version_ispfw: the firmware version provided by ispfw(4) dev.isp.N.fw_version_flash: the (active) firmware version in flash While here: - firmware attribute handling/parsing reworked + renamed defines from ISP2400_FW_ATTR_* to ISP_FW_ATTR_* + changed values to match new handling/parsing + added some more attributes - enable FLT support on 26xx based adapters - log level adjustments - new function return status codes (some for now, some for later use) - some minor style changes Tested and approved to work on real hardware with: - Qlogic ISP 2532 (QLogic QLE2560 8Gb FC Adapter) - Qlogic ISP 2031 (QLogic QLE2662 16Gbit 2Port FC Adapter) - Qlogic ISP 2722 (QLogic QLE2690 16Gb FC Adapter) - Qlogic ISP 2812 (QLogic QLE2772 32Gbit 2Port FC Adapter) PR: 273263 Reviewed by: mav Pull Request: https://github.com/freebsd/freebsd-src/pull/877 MFC after: 1 month Sponsored by: Technical University of Munich --- share/man/man4/isp.4 | 21 +- sys/dev/isp/isp.c | 985 +++++++++++++++++++++++++++++++------- sys/dev/isp/isp_freebsd.c | 21 +- sys/dev/isp/isp_freebsd.h | 2 +- sys/dev/isp/isp_pci.c | 35 +- sys/dev/isp/ispmbox.h | 62 +-- sys/dev/isp/ispreg.h | 11 + sys/dev/isp/ispvar.h | 129 ++++- 8 files changed, 1005 insertions(+), 261 deletions(-) diff --git a/share/man/man4/isp.4 b/share/man/man4/isp.4 index 277e7775dde..350a0ea59a6 100644 --- a/share/man/man4/isp.4 +++ b/share/man/man4/isp.4 @@ -24,7 +24,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd April 25, 2023 +.Dd October 27, 2023 .Dt ISP 4 .Os .Sh NAME @@ -80,12 +80,15 @@ FC-Tape is automatically enabled when connecting controller that supports it to a target that supports it. It may be disabled using configuration and hint options described below. .Sh FIRMWARE -Firmware loading is supported if the +Firmware loading is supported and handled by +.Xr firmware 9 . +The correct firmware is either loaded automatically, if available for this +type of adapter, or by manually loading the .Xr ispfw 4 -module is loaded. +module. It is strongly recommended that you use the firmware available from .Xr ispfw 4 -as it is the most likely to have been tested with this driver. +as it is the one that most likely has been tested with this driver. .Sh HARDWARE Cards supported by the .Nm @@ -136,7 +139,7 @@ Limit on number of Message Signaled Interrupts (MSI) to be used. .It Va hint.isp. Ns Ar N Ns Va .msix Limit on number of Extended Message Signaled Interrupts (MSI-X) to be used. .It Va hint.isp. Ns Ar N Ns Va .fwload_disable -A hint value to disable loading of firmware +A hint value to disable loading of firmware provided by .Xr ispfw 4 . .It Va hint.isp. Ns Ar N Ns Va .ignore_nvram A hint value to ignore board NVRAM settings for. @@ -210,6 +213,14 @@ The default is 1 (enabled). This is the readonly World Wide Node Name value for this port. .It Va dev.isp. Ns Ar N Ns Va .wwpn This is the readonly World Wide Port Name value for this port. +.It Va dev.isp. Ns Ar N Ns Va .fw_version_flash +The readonly flash firmware version value in the active region of the +controller. +.It Va dev.isp. Ns Ar N Ns Va .fw_version_ispfw +The readonly firmware version value provided by +.Xr ispfw 4 . +.It Va dev.isp. Ns Ar N Ns Va .fw_version_run +The readonly firmware version value currently executed on the controller. .El .Sh SEE ALSO .Xr da 4 , diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index 74f90b64441..aa2f1fb74c5 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -49,7 +49,9 @@ __KERNEL_RCSID(0, "$NetBSD$"); #include #endif #ifdef __FreeBSD__ +#include #include +#include #include #endif #ifdef __OpenBSD__ @@ -116,16 +118,31 @@ static uint16_t isp_next_handle(ispsoftc_t *, uint16_t *); static int isp_fw_state(ispsoftc_t *, int); static void isp_mboxcmd(ispsoftc_t *, mbreg_t *); +static void isp_get_flash_addrs(ispsoftc_t *); static void isp_setdfltfcparm(ispsoftc_t *, int); -static int isp_read_nvram(ispsoftc_t *, int); +static int isp_read_flash_dword(ispsoftc_t *, uint32_t, uint32_t *); +static int isp_read_flash_data(ispsoftc_t *, uint32_t *, uint32_t, uint32_t); static void isp_rd_2xxx_flash(ispsoftc_t *, uint32_t, uint32_t *); static int isp_read_flthdr_2xxx(ispsoftc_t *); static void isp_parse_flthdr_2xxx(ispsoftc_t *, uint8_t *); static int isp_read_flt_2xxx(ispsoftc_t *); static int isp_parse_flt_2xxx(ispsoftc_t *, uint8_t *); -static int isp_read_nvram_2400(ispsoftc_t *); +static int isp_read_nvram(ispsoftc_t *); static void isp_parse_nvram_2400(ispsoftc_t *, uint8_t *); +static void isp_print_image(ispsoftc_t *, char *, struct isp_image_status *); +static bool isp_check_aux_image_status_signature(struct isp_image_status *); +static bool isp_check_image_status_signature(struct isp_image_status *); +static unsigned long isp_image_status_checksum(struct isp_image_status *); +static void isp_component_status(struct active_regions *, struct isp_image_status *); +static int isp_compare_image_generation(ispsoftc_t *, struct isp_image_status *, struct isp_image_status *); +static void isp_get_aux_images(ispsoftc_t *, struct active_regions *); +static void isp_get_active_image(ispsoftc_t *, struct active_regions *); +static bool isp_risc_firmware_invalid(ispsoftc_t *, uint32_t *); +static int isp_load_ram(ispsoftc_t *, uint32_t *, uint32_t, uint32_t); +static int isp_load_risc_flash(ispsoftc_t *, uint32_t *, uint32_t); +static int isp_load_risc(ispsoftc_t *, uint32_t *); + static void isp_change_fw_state(ispsoftc_t *isp, int chan, int state) { @@ -139,6 +156,45 @@ isp_change_fw_state(ispsoftc_t *isp, int chan, int state) fcp->isp_fwstate = state; } +static void +isp_get_flash_addrs(ispsoftc_t *isp) +{ + fcparam *fcp = FCPARAM(isp, 0); + int r = 0; + + if (IS_28XX(isp)) { + fcp->flash_data_addr = ISP28XX_BASE_ADDR; + fcp->flt_region_flt = ISP28XX_FLT_ADDR; + } else if (IS_26XX(isp)) { /* 26xx and 27xx are identical */ + fcp->flash_data_addr = ISP27XX_BASE_ADDR; + fcp->flt_region_flt = ISP27XX_FLT_ADDR; + } else if (IS_25XX(isp)) { + fcp->flash_data_addr = ISP25XX_BASE_ADDR; + fcp->flt_region_flt = ISP25XX_FLT_ADDR; + } else { + fcp->flash_data_addr = ISP24XX_BASE_ADDR; + fcp->flt_region_flt = ISP24XX_FLT_ADDR; + } + fcp->flt_length = 0; + r = isp_read_flthdr_2xxx(isp); + if (r == 0) { + isp_read_flt_2xxx(isp); + } else { /* fallback to hardcoded NVRAM address */ + if (IS_28XX(isp)) { + fcp->flt_region_nvram = 0x300000; + } else if (IS_26XX(isp)) { + fcp->flash_data_addr = 0x7fe7c000; + fcp->flt_region_nvram = 0; + } else if (IS_25XX(isp)) { + fcp->flt_region_nvram = 0x48000; + } else { + fcp->flash_data_addr = 0x7ffe0000; + fcp->flt_region_nvram = 0; + } + fcp->flt_region_nvram += ISP2400_NVRAM_PORT_ADDR(isp->isp_port); + } +} + /* * Reset Hardware. * @@ -152,7 +208,7 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults) { mbreg_t mbs; char *buf; - uint64_t fwt; + uint16_t fwt; uint32_t code_org, val; int loaded_fw, loops, i, dodnld = 1; const char *btype = "????"; @@ -321,41 +377,119 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults) } /* - * Download new Firmware, unless requested not to do so. - * This is made slightly trickier in some cases where the - * firmware of the ROM revision is newer than the revision - * compiled into the driver. So, where we used to compare - * versions of our f/w and the ROM f/w, now we just see - * whether we have f/w at all and whether a config flag - * has disabled our download. + * Early setup DMA for the request and response queues. + * We do this now so we can use the request queue + * for dma to load firmware from. */ - if ((isp->isp_mdvec->dv_ispfw == NULL) || (isp->isp_confopts & ISP_CFG_NORELOAD)) { - dodnld = 0; - } else { - /* - * Set up DMA for the request and response queues. - * We do this now so we can use the request queue - * for dma to load firmware from. - */ - if (ISP_MBOXDMASETUP(isp) != 0) { - isp_prt(isp, ISP_LOGERR, "Cannot setup DMA"); - return; + if (ISP_MBOXDMASETUP(isp) != 0) { + isp_prt(isp, ISP_LOGERR, "Cannot setup DMA"); + return; + } + + /* + * FW load priority + * For 27xx and newer: + * Load ispfw(4) firmware unless requested not to do so. + * Request (active) flash firmware information. Compare + * version numbers of ispfw(4) and flash firmware. Load + * the highest version into RAM of the adapter. + * If loading ispfw(4) is disabled or loading it failed + * (eg. no firmware available) we just load firmware from + * flash. If this fails for whatever reason we fallback + * to let the adapter MBOX_LOAD_FLASH_FIRMWARE by itself + * followed by MBOX_EXEC_FIRMWARE and hope the best to + * get it up and running. + * + * For 26xx and older: + * Load ispfw(4) firmware unless requested not to do so + * and load it into RAM of the adapter. If loading + * ispfw(4) is disabled or loading it failed (eg. no + * firmware available) we just let the adapter + * MBOX_EXEC_FIRMWARE to start the flash firmware. + * For the 26xx a preceding MBOX_LOAD_FLASH_FIRMWARE + * is required. + */ + + fcparam *fcp = FCPARAM(isp, 0); + + /* read FLT to get flash region addresses */ + isp_get_flash_addrs(isp); + + /* set informational sysctl(8) to sane value */ + snprintf(fcp->fw_version_ispfw, sizeof(fcp->fw_version_ispfw), + "not loaded"); + snprintf(fcp->fw_version_flash, sizeof(fcp->fw_version_flash), + "not loaded"); + snprintf(fcp->fw_version_run, sizeof(fcp->fw_version_run), + "not loaded"); + + + /* Try to load ispfw(4) first */ + if (!(isp->isp_confopts & ISP_CFG_NORELOAD)) { + char fwname[32]; + snprintf(fwname, sizeof(fwname), "isp_%04x", isp->isp_did); + isp->isp_osinfo.ispfw = firmware_get(fwname); + if (isp->isp_osinfo.ispfw != NULL) { + isp->isp_mdvec->dv_ispfw = isp->isp_osinfo.ispfw->data; + const uint32_t *ispfwptr = isp->isp_mdvec->dv_ispfw; + for (i = 0; i < 4; i++) + fcp->fw_ispfwrev[i] = ispfwptr[4 + i]; + isp_prt(isp, ISP_LOGCONFIG, + "Loaded ispfw(4) firmware %s", fwname); + snprintf(fcp->fw_version_ispfw, + sizeof(fcp->fw_version_ispfw), + "%u.%u.%u", fcp->fw_ispfwrev[0], + fcp->fw_ispfwrev[1], fcp->fw_ispfwrev[2]); + isp_prt(isp, ISP_LOGCONFIG, + "Firmware revision (ispfw) %u.%u.%u (%x).", + fcp->fw_ispfwrev[0], fcp->fw_ispfwrev[1], + fcp->fw_ispfwrev[2], fcp->fw_ispfwrev[3]); + } else { + isp_prt(isp, ISP_LOGDEBUG0, + "Unable to load ispfw(4) firmware %s", fwname); } } - code_org = ISP_CODE_ORG_2400; loaded_fw = 0; + dodnld = 0; + + if (IS_27XX(isp)) { + switch (isp_load_risc(isp, 0)) { + case ISP_ABORTED: + /* download ispfw(4) as it's newer than flash */ + dodnld = 1; + break; + case ISP_SUCCESS: + /* We've loaded flash firmware */ + loaded_fw = 1; + break; + default: + /* + * Fall through to use ispfw(4) if available or + * just fall back to use MBOX_LOAD_FLASH_FIRMWARE + */ + if (isp->isp_osinfo.ispfw != NULL) + dodnld = 1; + break; + } + } else { + /* Fall through to load ispfw(4) or simply MBOX_EXEC_FIRMWARE */ + if (isp->isp_osinfo.ispfw != NULL) + dodnld = 1; + } + + code_org = ISP_CODE_ORG_2400; if (dodnld) { const uint32_t *ptr = isp->isp_mdvec->dv_ispfw; uint32_t la, wi, wl; - /* - * Keep loading until we run out of f/w. - */ + /* Keep loading until we run out of f/w. */ code_org = ptr[2]; /* 1st load address is our start addr */ for (;;) { - isp_prt(isp, ISP_LOGDEBUG0, "load 0x%x words of code at load address 0x%x", ptr[3], ptr[2]); + isp_prt(isp, ISP_LOGDEBUG2, + "Load 0x%x words of code at load address 0x%x", + ptr[3], ptr[2]); wi = 0; la = ptr[2]; @@ -368,20 +502,9 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults) cp = isp->isp_rquest; for (i = 0; i < nw; i++) ISP_IOXPUT_32(isp, ptr[wi + i], &cp[i]); - MEMORYBARRIER(isp, SYNC_REQUEST, 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)), -1); - MBSINIT(&mbs, MBOX_LOAD_RISC_RAM, MBLOGALL, 0); - mbs.param[1] = la; - mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); - mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); - mbs.param[4] = nw >> 16; - mbs.param[5] = nw; - mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); - mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); - mbs.param[8] = la >> 16; - isp_prt(isp, ISP_LOGDEBUG0, "LOAD RISC RAM %u words at load address 0x%x", nw, la); - isp_mboxcmd(isp, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, "F/W download failed"); + if (isp_load_ram(isp, cp, la, nw) != 0) { + isp_prt(isp, ISP_LOGERR, + "Failed to load firmware fragment."); return; } la += nw; @@ -395,30 +518,32 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults) ptr += ptr[3]; } loaded_fw = 1; - } else if (IS_26XX(isp)) { - isp_prt(isp, ISP_LOGDEBUG1, "loading firmware from flash"); - MBSINIT(&mbs, MBOX_LOAD_FLASH_FIRMWARE, MBLOGALL, 5000000); - mbs.ibitm = 0x01; - mbs.obitm = 0x07; - isp_mboxcmd(isp, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, "Flash F/W load failed"); - return; - } + /* Drop reference to ispfw(4) firmware */ + if (isp->isp_osinfo.ispfw != NULL) + firmware_put(isp->isp_osinfo.ispfw, FIRMWARE_UNLOAD); } else { - isp_prt(isp, ISP_LOGDEBUG2, "skipping f/w download"); + isp_prt(isp, ISP_LOGCONFIG, + "Skipping ispfw(4) firmware download"); } - /* - * If we loaded firmware, verify its checksum - */ + /* If we loaded firmware, verify its checksum. */ if (loaded_fw) { MBSINIT(&mbs, MBOX_VERIFY_CHECKSUM, MBLOGNONE, 0); mbs.param[1] = code_org >> 16; mbs.param[2] = code_org; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, dcrc); + isp_prt(isp, ISP_LOGERR, "%s: 0x%x", dcrc, + (mbs.param[2] << 16 | mbs.param[1])); + return; + } + } else if (IS_26XX(isp)) { + isp_prt(isp, ISP_LOGCONFIG, + "Instruct RISC to load firmware from flash by itself"); + MBSINIT(&mbs, MBOX_LOAD_FLASH_FIRMWARE, MBLOGALL, 5000000); + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, "Flash F/W load failed"); return; } } @@ -434,9 +559,27 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults) mbs.param[2] = code_org; if (!IS_26XX(isp)) mbs.param[3] = loaded_fw ? 0 : 1; + mbs.param[4] = 0; + if (IS_27XX(isp)) + mbs.param[4] |= 0x08; /* NVME_ENABLE_FLAG */ + mbs.param[11] = 0; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) return; + fcp->fw_ability_mask = (mbs.param[3] << 16) | mbs.param[2]; + isp_prt(isp, ISP_LOGDEBUG0, "Firmware ability mask: 0x%x", + fcp->fw_ability_mask); + if (IS_26XX(isp)) { + fcp->max_supported_speed = mbs.param[2] & (0x1 | 0x2); + isp_prt(isp, ISP_LOGINFO, "Maximum supported speed: %s", + fcp->max_supported_speed == 0 ? "16Gbit/s" : + fcp->max_supported_speed == 1 ? "32Gbit/s" : + fcp->max_supported_speed == 2 ? "64Gbit/s" : "unknown"); + } + if (IS_28XX(isp) && (mbs.param[5] & 0x400)) { + isp_prt(isp, ISP_LOGINFO, + "HW supports EDIF (Encryption of data in flight)"); + } /* * Ask the chip for the current firmware version. @@ -452,103 +595,160 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults) isp->isp_fwrev[1] = mbs.param[2]; isp->isp_fwrev[2] = mbs.param[3]; isp->isp_fwattr = mbs.param[6]; - isp->isp_fwattr |= ((uint64_t) mbs.param[15]) << 16; - if (isp->isp_fwattr & ISP2400_FW_ATTR_EXTNDED) { - isp->isp_fwattr |= - (((uint64_t) mbs.param[16]) << 32) | - (((uint64_t) mbs.param[17]) << 48); + isp->isp_fwattr_h = mbs.param[15]; + if (isp->isp_fwattr & ISP_FW_ATTR_EXTNDED) { + isp->isp_fwattr_ext[0] = mbs.param[16]; + isp->isp_fwattr_ext[1] = mbs.param[17]; } isp_prt(isp, ISP_LOGCONFIG, "Board Type %s, Chip Revision 0x%x, %s F/W Revision %d.%d.%d", - btype, isp->isp_revision, dodnld? "loaded" : "resident", isp->isp_fwrev[0], isp->isp_fwrev[1], isp->isp_fwrev[2]); + btype, isp->isp_revision, dodnld ? "loaded" : "resident", + isp->isp_fwrev[0], isp->isp_fwrev[1], isp->isp_fwrev[2]); + snprintf(fcp->fw_version_run, sizeof(fcp->fw_version_run), + "%u.%u.%u", isp->isp_fwrev[0], isp->isp_fwrev[1], + isp->isp_fwrev[2]); + if (!dodnld && !IS_26XX(isp)) + snprintf(fcp->fw_version_flash, sizeof(fcp->fw_version_flash), + "%s", fcp->fw_version_run); fwt = isp->isp_fwattr; buf = FCPARAM(isp, 0)->isp_scanscratch; - ISP_SNPRINTF(buf, ISP_FC_SCRLEN, "Attributes:"); - if (fwt & ISP2400_FW_ATTR_CLASS2) { - fwt ^=ISP2400_FW_ATTR_CLASS2; + ISP_SNPRINTF(buf, ISP_FC_SCRLEN, "FW Attributes Lower:"); + if (fwt & ISP_FW_ATTR_CLASS2) { + fwt ^= ISP_FW_ATTR_CLASS2; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s Class2", buf); } - if (fwt & ISP2400_FW_ATTR_IP) { - fwt ^=ISP2400_FW_ATTR_IP; + if (fwt & ISP_FW_ATTR_IP) { + fwt ^= ISP_FW_ATTR_IP; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s IP", buf); } - if (fwt & ISP2400_FW_ATTR_MULTIID) { - fwt ^=ISP2400_FW_ATTR_MULTIID; + if (fwt & ISP_FW_ATTR_MULTIID) { + fwt ^= ISP_FW_ATTR_MULTIID; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s MultiID", buf); } - if (fwt & ISP2400_FW_ATTR_SB2) { - fwt ^=ISP2400_FW_ATTR_SB2; + if (fwt & ISP_FW_ATTR_SB2) { + fwt ^= ISP_FW_ATTR_SB2; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s SB2", buf); } - if (fwt & ISP2400_FW_ATTR_T10CRC) { - fwt ^=ISP2400_FW_ATTR_T10CRC; + if (fwt & ISP_FW_ATTR_T10CRC) { + fwt ^= ISP_FW_ATTR_T10CRC; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s T10CRC", buf); } - if (fwt & ISP2400_FW_ATTR_VI) { - fwt ^=ISP2400_FW_ATTR_VI; + if (fwt & ISP_FW_ATTR_VI) { + fwt ^= ISP_FW_ATTR_VI; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s VI", buf); } - if (fwt & ISP2400_FW_ATTR_MQ) { - fwt ^=ISP2400_FW_ATTR_MQ; + if (fwt & ISP_FW_ATTR_MQ) { + fwt ^= ISP_FW_ATTR_MQ; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s MQ", buf); } - if (fwt & ISP2400_FW_ATTR_MSIX) { - fwt ^=ISP2400_FW_ATTR_MSIX; + if (fwt & ISP_FW_ATTR_MSIX) { + fwt ^= ISP_FW_ATTR_MSIX; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s MSIX", buf); } - if (fwt & ISP2400_FW_ATTR_FCOE) { - fwt ^=ISP2400_FW_ATTR_FCOE; + if (fwt & ISP_FW_ATTR_FCOE) { + fwt ^= ISP_FW_ATTR_FCOE; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s FCOE", buf); } - if (fwt & ISP2400_FW_ATTR_VP0) { - fwt ^= ISP2400_FW_ATTR_VP0; + if (fwt & ISP_FW_ATTR_VP0) { + fwt ^= ISP_FW_ATTR_VP0; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s VP0_Decoupling", buf); } - if (fwt & ISP2400_FW_ATTR_EXPFW) { - fwt ^= ISP2400_FW_ATTR_EXPFW; + if (fwt & ISP_FW_ATTR_EXPFW) { + fwt ^= ISP_FW_ATTR_EXPFW; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s (Experimental)", buf); } - if (fwt & ISP2400_FW_ATTR_HOTFW) { - fwt ^= ISP2400_FW_ATTR_HOTFW; + if (fwt & ISP_FW_ATTR_HOTFW) { + fwt ^= ISP_FW_ATTR_HOTFW; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s HotFW", buf); } - fwt &= ~ISP2400_FW_ATTR_EXTNDED; - if (fwt & ISP2400_FW_ATTR_EXTVP) { - fwt ^= ISP2400_FW_ATTR_EXTVP; + fwt &= ~ISP_FW_ATTR_EXTNDED; + if (fwt) { + ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), + "%s (unknown 0x%04x)", buf, fwt); + } + isp_prt(isp, ISP_LOGCONFIG, "%s", buf); + + fwt = isp->isp_fwattr_h; + buf = FCPARAM(isp, 0)->isp_scanscratch; + ISP_SNPRINTF(buf, ISP_FC_SCRLEN, "FW Attributes Upper:"); + if (fwt & ISP_FW_ATTR_H_EXTVP) { + fwt ^= ISP_FW_ATTR_H_EXTVP; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s ExtVP", buf); } - if (fwt & ISP2400_FW_ATTR_VN2VN) { - fwt ^= ISP2400_FW_ATTR_VN2VN; + if (fwt & ISP_FW_ATTR_H_VN2VN) { + fwt ^= ISP_FW_ATTR_H_VN2VN; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s VN2VN", buf); } - if (fwt & ISP2400_FW_ATTR_EXMOFF) { - fwt ^= ISP2400_FW_ATTR_EXMOFF; + if (fwt & ISP_FW_ATTR_H_EXMOFF) { + fwt ^= ISP_FW_ATTR_H_EXMOFF; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s EXMOFF", buf); } - if (fwt & ISP2400_FW_ATTR_NPMOFF) { - fwt ^= ISP2400_FW_ATTR_NPMOFF; + if (fwt & ISP_FW_ATTR_H_NPMOFF) { + fwt ^= ISP_FW_ATTR_H_NPMOFF; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s NPMOFF", buf); } - if (fwt & ISP2400_FW_ATTR_DIFCHOP) { - fwt ^= ISP2400_FW_ATTR_DIFCHOP; + if (fwt & ISP_FW_ATTR_H_DIFCHOP) { + fwt ^= ISP_FW_ATTR_H_DIFCHOP; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s DIFCHOP", buf); } - if (fwt & ISP2400_FW_ATTR_SRIOV) { - fwt ^= ISP2400_FW_ATTR_SRIOV; + if (fwt & ISP_FW_ATTR_H_SRIOV) { + fwt ^= ISP_FW_ATTR_H_SRIOV; ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s SRIOV", buf); } - if (fwt & ISP2400_FW_ATTR_ASICTMP) { - fwt ^= ISP2400_FW_ATTR_ASICTMP; - ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s ASICTMP", buf); + if (fwt & ISP_FW_ATTR_H_NVME) { + fwt ^= ISP_FW_ATTR_H_NVME; + ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s NVMe", buf); } - if (fwt & ISP2400_FW_ATTR_ATIOMQ) { - fwt ^= ISP2400_FW_ATTR_ATIOMQ; - ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s ATIOMQ", buf); + if (fwt & ISP_FW_ATTR_H_NVME_UP) { + fwt ^= ISP_FW_ATTR_H_NVME_UP; + ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s NVMe(updated)", buf); + } + if (fwt & (ISP_FW_ATTR_H_NVME_FB)) { + fwt ^= (ISP_FW_ATTR_H_NVME_FB); + ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s NVMe(first burst)", buf); } if (fwt) { - ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s (unknown 0x%08x%08x)", buf, - (uint32_t) (fwt >> 32), (uint32_t) fwt); + ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), + "%s (unknown 0x%04x)", buf, fwt); + } + isp_prt(isp, ISP_LOGCONFIG, "%s", buf); + + fwt = isp->isp_fwattr_ext[0]; + buf = FCPARAM(isp, 0)->isp_scanscratch; + ISP_SNPRINTF(buf, ISP_FC_SCRLEN, "FW Ext. Attributes Lower:"); + if (fwt & ISP_FW_ATTR_E0_ASICTMP) { + fwt ^= ISP_FW_ATTR_E0_ASICTMP; + ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s ASICTMP", buf); + } + if (fwt & ISP_FW_ATTR_E0_ATIOMQ) { + fwt ^= ISP_FW_ATTR_E0_ATIOMQ; + ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s ATIOMQ", buf); + } + if (fwt & ISP_FW_ATTR_E0_EDIF) { + fwt ^= ISP_FW_ATTR_E0_EDIF; + ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s EDIF", buf); + } + if (fwt & ISP_FW_ATTR_E0_SCM) { + fwt ^= ISP_FW_ATTR_E0_SCM; + ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s SCM", buf); + } + if (fwt & ISP_FW_ATTR_E0_NVME2) { + fwt ^= ISP_FW_ATTR_E0_NVME2; + ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), "%s NVMe-2", buf); + } + if (fwt) { + ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), + "%s (unknown 0x%04x)", buf, fwt); + } + isp_prt(isp, ISP_LOGCONFIG, "%s", buf); + + fwt = isp->isp_fwattr_ext[1]; + buf = FCPARAM(isp, 0)->isp_scanscratch; + ISP_SNPRINTF(buf, ISP_FC_SCRLEN, "FW Ext. Attributes Upper:"); + if (fwt) { + ISP_SNPRINTF(buf, ISP_FC_SCRLEN - strlen(buf), + "%s (unknown 0x%04x)", buf, fwt); } isp_prt(isp, ISP_LOGCONFIG, "%s", buf); @@ -3801,14 +4001,14 @@ static const uint32_t mbpfc[] = { ISP_FC_OPMAP(0x01, 0x01), /* 0x00: MBOX_NO_OP */ ISP_FC_OPMAP(0x1f, 0x01), /* 0x01: MBOX_LOAD_RAM */ ISP_FC_OPMAP_HALF(0x07, 0xff, 0x00, 0x1f), /* 0x02: MBOX_EXEC_FIRMWARE */ - ISP_FC_OPMAP(0xdf, 0x01), /* 0x03: MBOX_DUMP_RAM */ + ISP_FC_OPMAP(0x01, 0x07), /* 0x03: MBOX_LOAD_FLASH_FIRMWARE */ ISP_FC_OPMAP(0x07, 0x07), /* 0x04: MBOX_WRITE_RAM_WORD */ ISP_FC_OPMAP(0x03, 0x07), /* 0x05: MBOX_READ_RAM_WORD */ ISP_FC_OPMAP_FULL(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff), /* 0x06: MBOX_MAILBOX_REG_TEST */ ISP_FC_OPMAP(0x07, 0x07), /* 0x07: MBOX_VERIFY_CHECKSUM */ ISP_FC_OPMAP_FULL(0x0, 0x0, 0x0, 0x01, 0x0, 0x3, 0x80, 0x7f), /* 0x08: MBOX_ABOUT_FIRMWARE */ ISP_FC_OPMAP(0xdf, 0x01), /* 0x09: MBOX_LOAD_RISC_RAM_2100 */ - ISP_FC_OPMAP(0xdf, 0x01), /* 0x0a: DUMP RAM */ + ISP_FC_OPMAP(0xdf, 0x01), /* 0x0a: MBOX_DUMP_RISC_RAM_2100 */ ISP_FC_OPMAP_HALF(0x1, 0xff, 0x0, 0x01), /* 0x0b: MBOX_LOAD_RISC_RAM */ ISP_FC_OPMAP(0x00, 0x00), /* 0x0c: */ ISP_FC_OPMAP_HALF(0x1, 0x0f, 0x0, 0x01), /* 0x0d: MBOX_WRITE_RAM_WORD_EXTENDED */ @@ -3940,14 +4140,14 @@ static const char *fc_mbcmd_names[] = { "NO-OP", /* 00h */ "LOAD RAM", "EXEC FIRMWARE", - "DUMP RAM", + "LOAD FLASH FIRMWARE", "WRITE RAM WORD", "READ RAM WORD", "MAILBOX REG TEST", "VERIFY CHECKSUM", "ABOUT FIRMWARE", "LOAD RAM (2100)", - "DUMP RAM", + "DUMP RAM (2100)", "LOAD RISC RAM", "DUMP RISC RAM", "WRITE RAM WORD EXTENDED", @@ -4084,7 +4284,7 @@ isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp) obits = ISP_FC_OBITS(opcode); if (cname == NULL) { cname = tname; - ISP_SNPRINTF(tname, sizeof tname, "opcode %x", opcode); + ISP_SNPRINTF(tname, sizeof(tname), "opcode %x", opcode); } isp_prt(isp, ISP_LOGDEBUG3, "Mailbox Command '%s'", cname); @@ -4219,7 +4419,7 @@ out: xname = "TIMEOUT"; break; default: - ISP_SNPRINTF(mname, sizeof mname, "error 0x%x", mbp->param[0]); + ISP_SNPRINTF(mname, sizeof(mname), "error 0x%x", mbp->param[0]); xname = mname; break; } @@ -4279,7 +4479,7 @@ isp_setdfltfcparm(ispsoftc_t *isp, int chan) * Give a couple of tries at reading NVRAM. */ for (i = 0; i < 2; i++) { - j = isp_read_nvram(isp, chan); + j = isp_read_nvram(isp); if (j == 0) { break; } @@ -4336,50 +4536,49 @@ cleanup: /* * NVRAM Routines */ -static int -isp_read_nvram(ispsoftc_t *isp, int bus) +static inline uint32_t +flash_data_addr(ispsoftc_t *isp, uint32_t faddr) { fcparam *fcp = FCPARAM(isp, 0); - int r = 0; - if (isp->isp_type != ISP_HA_FC_2600) { - if (IS_28XX(isp)) { - fcp->flash_data_addr = ISP28XX_BASE_ADDR; - fcp->flt_region_flt = ISP28XX_FLT_ADDR; - } else if (IS_27XX(isp)) { - fcp->flash_data_addr = ISP27XX_BASE_ADDR; - fcp->flt_region_flt = ISP27XX_FLT_ADDR; - } else if (IS_25XX(isp)) { - fcp->flash_data_addr = ISP25XX_BASE_ADDR; - fcp->flt_region_flt = ISP25XX_FLT_ADDR; - } else { - fcp->flash_data_addr = ISP24XX_BASE_ADDR; - fcp->flt_region_flt = ISP24XX_FLT_ADDR; + return (fcp->flash_data_addr + faddr); +} + +static int +isp_read_flash_dword(ispsoftc_t *isp, uint32_t addr, uint32_t *data) +{ + int loops = 0; + + ISP_WRITE(isp, BIU2400_FLASH_ADDR, addr & ~0x80000000); + for (loops = 0; loops < 30000; loops++) { + if (ISP_READ(isp, BIU2400_FLASH_ADDR & 0x80000000)) { + *data = ISP_READ(isp, BIU2400_FLASH_DATA); + return (ISP_SUCCESS); } - fcp->flt_length = 0; - r = isp_read_flthdr_2xxx(isp); - if (r == 0) { - isp_read_flt_2xxx(isp); - } else { /* fallback to hardcoded NVRAM address */ - if (IS_28XX(isp)) { - fcp->flt_region_nvram = 0x300000; - } else if (IS_27XX(isp)) { - fcp->flash_data_addr = 0x7fe7c000; - fcp->flt_region_nvram = 0; - } else if (IS_25XX(isp)) { - fcp->flt_region_nvram = 0x48000; - } else { - fcp->flash_data_addr = 0x7ffe0000; - fcp->flt_region_nvram = 0; - } - fcp->flt_region_nvram += ISP2400_NVRAM_PORT_ADDR(isp->isp_port); - } - } else { - fcp->flash_data_addr = 0x7fe7c000; - fcp->flt_region_nvram = 0; - fcp->flt_region_nvram += ISP2400_NVRAM_PORT_ADDR(isp->isp_port); + ISP_DELAY(10); } - return (isp_read_nvram_2400(isp)); + isp_prt(isp, ISP_LOGERR, + "Flash read dword at 0x%x timeout.", addr); + *data = 0xffffffff; + return (ISP_FUNCTION_TIMEOUT); +} + +static int +isp_read_flash_data(ispsoftc_t *isp, uint32_t *dwptr, uint32_t faddr, uint32_t dwords) +{ + int loops = 0; + int rval = ISP_SUCCESS; + + /* Dword reads to flash. */ + faddr = flash_data_addr(isp, faddr); + for (loops = 0; loops < dwords; loops++, faddr++, dwptr++) { + rval = isp_read_flash_dword(isp, faddr, dwptr); + if (rval != ISP_SUCCESS) + break; + htole32(*((uint32_t *)(dwptr))); + } + + return (rval); } static void @@ -4388,22 +4587,19 @@ isp_rd_2xxx_flash(ispsoftc_t *isp, uint32_t addr, uint32_t *rp) fcparam *fcp = FCPARAM(isp, 0); int loops = 0; uint32_t base = fcp->flash_data_addr; - uint32_t tmp = 0; - ISP_WRITE(isp, BIU2400_FLASH_ADDR, base + addr); - for (loops = 0; loops < 5000; loops++) { + ISP_WRITE(isp, BIU2400_FLASH_ADDR, (base + addr) & ~0x80000000); + for (loops = 0; loops < 30000; loops++) { ISP_DELAY(10); - tmp = ISP_READ(isp, BIU2400_FLASH_ADDR); - if ((tmp & (1U << 31)) != 0) { - break; + if (ISP_READ(isp, BIU2400_FLASH_ADDR & 0x80000000)) { + *rp = ISP_READ(isp, BIU2400_FLASH_DATA); + ISP_SWIZZLE_NVRAM_LONG(isp, rp); + return; } } - if (tmp & (1U << 31)) { - *rp = ISP_READ(isp, BIU2400_FLASH_DATA); - ISP_SWIZZLE_NVRAM_LONG(isp, rp); - } else { - *rp = 0xffffffff; - } + isp_prt(isp, ISP_LOGERR, + "Flash read dword at 0x%x timeout.", (base + addr)); + *rp = 0xffffffff; } static int @@ -4418,8 +4614,7 @@ isp_read_flthdr_2xxx(ispsoftc_t *isp) addr = fcp->flt_region_flt; dptr = (uint32_t *) flthdr_data; - isp_prt(isp, ISP_LOGDEBUG0, - "FLTL[DEF]: 0x%x", addr); + isp_prt(isp, ISP_LOGDEBUG0, "FLTL[DEF]: 0x%x", addr); for (lwrds = 0; lwrds < FLT_HEADER_SIZE >> 2; lwrds++) { isp_rd_2xxx_flash(isp, addr++, dptr++); } @@ -4651,8 +4846,8 @@ isp_parse_flt_2xxx(ispsoftc_t *isp, uint8_t *flt_data) break; } } - isp_prt(isp, ISP_LOGDEBUG0, - "FLT[FLT]: boot=0x%x fw=0x%x vpd_nvram=0x%x vpd=0x%x nvram 0x%x " + isp_prt(isp, ISP_LOGCONFIG, + "FLT[FLT]: boot=0x%x fw=0x%x vpd_nvram=0x%x vpd=0x%x nvram=0x%x " "fdt=0x%x flt=0x%x npiv=0x%x fcp_prif_cfg=0x%x", fcp->flt_region_boot, fcp->flt_region_fw, fcp->flt_region_vpd_nvram, fcp->flt_region_vpd, fcp->flt_region_nvram, fcp->flt_region_fdt, @@ -4662,15 +4857,465 @@ isp_parse_flt_2xxx(ispsoftc_t *isp, uint8_t *flt_data) return (0); } +static void +isp_print_image(ispsoftc_t *isp, char *name, struct isp_image_status *image_status) +{ + isp_prt(isp, ISP_LOGDEBUG0, + "%s %s: mask=0x%02x gen=0x%04x ver=%u.%u map=0x%01x sum=0x%08x sig=0x%08x", + name, "status", + image_status->image_status_mask, + le16toh(image_status->generation), + image_status->ver_major, + image_status->ver_minor, + image_status->bitmap, + le32toh(image_status->checksum), + le32toh(image_status->signature)); +} + +static bool +isp_check_aux_image_status_signature(struct isp_image_status *image_status) +{ + unsigned long signature = le32toh(image_status->signature); + + return (signature != ISP28XX_AUX_IMG_STATUS_SIGN); +} + +static bool +isp_check_image_status_signature(struct isp_image_status *image_status) +{ + unsigned long signature = le32toh(image_status->signature); + + return ((signature != ISP27XX_IMG_STATUS_SIGN) && + (signature != ISP28XX_IMG_STATUS_SIGN)); +} + +static unsigned long +isp_image_status_checksum(struct isp_image_status *image_status) +{ + uint32_t *p = (uint32_t *)image_status; + unsigned int n = sizeof(*image_status) / sizeof(*p); + uint32_t sum = 0; + + for ( ; n--; p++) + sum += le32toh(*((uint32_t *)(p))); + + return (sum); +} + +static inline unsigned int +isp_component_bitmask(struct isp_image_status *aux, unsigned int bitmask) +{ + return (aux->bitmap & bitmask ? + ISP27XX_SECONDARY_IMAGE : ISP27XX_PRIMARY_IMAGE); +} + +static void +isp_component_status(struct active_regions *active_regions, struct isp_image_status *aux) +{ + active_regions->aux.board_config = + isp_component_bitmask(aux, ISP28XX_AUX_IMG_BOARD_CONFIG); + + active_regions->aux.vpd_nvram = + isp_component_bitmask(aux, ISP28XX_AUX_IMG_VPD_NVRAM); + + active_regions->aux.npiv_config_0_1 = + isp_component_bitmask(aux, ISP28XX_AUX_IMG_NPIV_CONFIG_0_1); + + active_regions->aux.npiv_config_2_3 = + isp_component_bitmask(aux, ISP28XX_AUX_IMG_NPIV_CONFIG_2_3); + + active_regions->aux.nvme_params = + isp_component_bitmask(aux, ISP28XX_AUX_IMG_NVME_PARAMS); +} + static int -isp_read_nvram_2400(ispsoftc_t *isp) +isp_compare_image_generation(ispsoftc_t *isp, + struct isp_image_status *pri_image_status, + struct isp_image_status *sec_image_status) +{ + /* calculate generation delta as uint16 (this accounts for wrap) */ + int16_t delta = + le16toh(pri_image_status->generation) - + le16toh(sec_image_status->generation); + + isp_prt(isp, ISP_LOGDEBUG0, "generation delta = %d", delta); + + return (delta); +} + +static void +isp_get_aux_images(ispsoftc_t *isp, struct active_regions *active_regions) +{ + fcparam *fcp = FCPARAM(isp, 0); + struct isp_image_status pri_aux_image_status, sec_aux_image_status; + bool valid_pri_image = false, valid_sec_image = false; + bool active_pri_image = false, active_sec_image = false; + + if (!fcp->flt_region_aux_img_status_pri) { + isp_prt(isp, ISP_LOGWARN, + "Primary aux image not addressed"); + goto check_sec_image; + } + + isp_read_flash_data(isp, (uint32_t *)&pri_aux_image_status, + fcp->flt_region_aux_img_status_pri, + sizeof(pri_aux_image_status) >> 2); + isp_print_image(isp, "Primary aux image", &pri_aux_image_status); + + if (isp_check_aux_image_status_signature(&pri_aux_image_status)) { + isp_prt(isp, ISP_LOGERR, + "Primary aux image signature (0x%x) not valid", + le32toh(pri_aux_image_status.signature)); + goto check_sec_image; + } + + if (isp_image_status_checksum(&pri_aux_image_status)) { + isp_prt(isp, ISP_LOGERR, + "Primary aux image checksum failed"); + goto check_sec_image; + } + + valid_pri_image = true; + + if (pri_aux_image_status.image_status_mask & 1) { + isp_prt(isp, ISP_LOGCONFIG, + "Primary aux image is active"); + active_pri_image = true; + } + +check_sec_image: + if (!fcp->flt_region_aux_img_status_sec) { + isp_prt(isp, ISP_LOGWARN, + "Secondary aux image not addressed"); + goto check_valid_image; + } + + isp_read_flash_data(isp, (uint32_t *)&sec_aux_image_status, + fcp->flt_region_aux_img_status_sec, + sizeof(sec_aux_image_status) >> 2); + isp_print_image(isp, "Secondary aux image", &sec_aux_image_status); + + if (isp_check_aux_image_status_signature(&sec_aux_image_status)) { + isp_prt(isp, ISP_LOGERR, + "Secondary aux image signature (0x%x) not valid", + le32toh(sec_aux_image_status.signature)); + goto check_valid_image; + } + + if (isp_image_status_checksum(&sec_aux_image_status)) { + isp_prt(isp, ISP_LOGERR, + "Secondary aux image checksum failed"); + goto check_valid_image; + } + + valid_sec_image = true; + + if (sec_aux_image_status.image_status_mask & 1) { + isp_prt(isp, ISP_LOGCONFIG, + "Secondary aux image is active"); + active_sec_image = true; + } + +check_valid_image: + if (valid_pri_image && active_pri_image && + valid_sec_image && active_sec_image) { + if (isp_compare_image_generation(isp, &pri_aux_image_status, + &sec_aux_image_status) >= 0) { + isp_component_status(active_regions, + &pri_aux_image_status); + } else { + isp_component_status(active_regions, + &sec_aux_image_status); + } + } else if (valid_pri_image && active_pri_image) { + isp_component_status(active_regions, &pri_aux_image_status); + } else if (valid_sec_image && active_sec_image) { + isp_component_status(active_regions, &sec_aux_image_status); + } + + isp_prt(isp, ISP_LOGDEBUG0, + "aux images active: BCFG=%u VPD/NVR=%u NPIV0/1=%u NPIV2/3=%u, NVME=%u", + active_regions->aux.board_config, + active_regions->aux.vpd_nvram, + active_regions->aux.npiv_config_0_1, + active_regions->aux.npiv_config_2_3, + active_regions->aux.nvme_params); +} + +static void +isp_get_active_image(ispsoftc_t *isp, struct active_regions * active_regions) +{ + fcparam *fcp = FCPARAM(isp, 0); + struct isp_image_status pri_image_status, sec_image_status; + bool valid_pri_image = false, valid_sec_image = false; + bool active_pri_image = false, active_sec_image = false; + + if (!fcp->flt_region_img_status_pri) { + isp_prt(isp, ISP_LOGWARN, + "Primary image not addressed"); + goto check_sec_image; + } + + if (isp_read_flash_data(isp, (uint32_t *) &pri_image_status, + fcp->flt_region_img_status_pri, sizeof(pri_image_status) >> 2) != + ISP_SUCCESS) + goto check_sec_image; + + isp_print_image(isp, "Primary image", &pri_image_status); + + if (isp_check_image_status_signature(&pri_image_status)) { + isp_prt(isp, ISP_LOGERR, + "Primary image signature (0x%x) not valid", + le32toh(pri_image_status.signature)); + goto check_sec_image; + } + + if (isp_image_status_checksum(&pri_image_status)) { + isp_prt(isp, ISP_LOGERR, + "Primary image checksum failed"); + goto check_sec_image; + } + + valid_pri_image = true; + + if (pri_image_status.image_status_mask & 1) { + isp_prt(isp, ISP_LOGCONFIG, + "Primary image is active"); + active_pri_image = true; + } + +check_sec_image: + if (!fcp->flt_region_img_status_sec) { + isp_prt(isp, ISP_LOGWARN, + "Secondary image not addressed"); + return; + } + + if (isp_read_flash_data(isp, (uint32_t *) &sec_image_status, + fcp->flt_region_img_status_sec, sizeof(sec_image_status) >> 2) != + ISP_SUCCESS) + return; + + isp_print_image(isp, "Secondary image", &sec_image_status); + + if (isp_check_image_status_signature(&sec_image_status)) { + isp_prt(isp, ISP_LOGERR, + "Secondary image signature (0x%x) not valid", + le32toh(sec_image_status.signature)); + } + + if (isp_image_status_checksum(&sec_image_status)) { + isp_prt(isp, ISP_LOGERR, + "Secondary image checksum failed"); + goto check_valid_image; + } + + valid_sec_image = true; + + if (sec_image_status.image_status_mask & 1) { + isp_prt(isp, ISP_LOGCONFIG, + "Secondary image is active"); + active_sec_image = true; + } + +check_valid_image: + if (valid_pri_image && active_pri_image) + active_regions->global = ISP27XX_PRIMARY_IMAGE; + + if (valid_sec_image && active_sec_image) { + if (!active_regions->global || + isp_compare_image_generation(isp, + &pri_image_status, &sec_image_status) < 0) { + active_regions->global = ISP27XX_SECONDARY_IMAGE; + } + } + + isp_prt(isp, ISP_LOGDEBUG0, "active image %s (%u)", + active_regions->global == ISP27XX_DEFAULT_IMAGE ? + "default (boot/fw)" : + active_regions->global == ISP27XX_PRIMARY_IMAGE ? + "primary" : + active_regions->global == ISP27XX_SECONDARY_IMAGE ? + "secondary" : "invalid", + active_regions->global); +} + +static bool isp_risc_firmware_invalid(ispsoftc_t *isp, uint32_t *dword) +{ + return ((dword[4] | dword[5] | dword[6] | dword[7]) == 0 || + (~dword[4] | ~dword[5] | ~dword[6] | ~dword[7]) == 0); +} + +static int +isp_load_ram(ispsoftc_t *isp, uint32_t *data, uint32_t risc_addr, + uint32_t risc_code_size) +{ + mbreg_t mbs; + int rval = ISP_SUCCESS; + + MEMORYBARRIER(isp, SYNC_REQUEST, 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)), -1); + MBSINIT(&mbs, MBOX_LOAD_RISC_RAM, MBLOGALL, 0); + mbs.param[1] = risc_addr; + mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); + mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); + mbs.param[4] = risc_code_size >> 16; + mbs.param[5] = risc_code_size; + mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); + mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); + mbs.param[8] = risc_addr >> 16; + isp_prt(isp, ISP_LOGDEBUG0, + "LOAD RISC RAM %u (0x%x) words at load address 0x%x", + risc_code_size, risc_code_size, risc_addr); + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, "F/W download failed"); + rval = ISP_FUNCTION_FAILED; + } + + return (rval); +} + +static int +isp_load_risc_flash(ispsoftc_t *isp, uint32_t *srisc_addr, uint32_t faddr) +{ + fcparam *fcp = FCPARAM(isp, 0); + int rval = ISP_SUCCESS; + unsigned int segments, fragment; + unsigned long i; + unsigned int j; + unsigned long dlen; + uint32_t *dcode; + uint32_t risc_addr, risc_size = 0; + + isp_prt(isp, ISP_LOGDEBUG0, + "Accessing flash firmware at 0x%x.", faddr); + + dcode = isp->isp_rquest; + isp_read_flash_data(isp, dcode, faddr, 8); + if (isp_risc_firmware_invalid(isp, dcode)) { + snprintf(fcp->fw_version_flash, sizeof(fcp->fw_version_flash), + "invalid"); + isp_prt(isp, ISP_LOGERR, + "Unable to verify the integrity of flash firmware image."); + isp_prt(isp, ISP_LOGERR, + "Firmware data: 0x%08x 0x%08x 0x%08x 0x%08x.", + dcode[0], dcode[1], dcode[2], dcode[3]); + return (ISP_FUNCTION_FAILED); + } else { + for (i = 0; i < 4; i++) + fcp->fw_flashrev[i] = be32toh(dcode[4 + i]); + snprintf(fcp->fw_version_flash, sizeof(fcp->fw_version_flash), + "%u.%u.%u", fcp->fw_flashrev[0], fcp->fw_flashrev[1], + fcp->fw_flashrev[2]); + isp_prt(isp, ISP_LOGCONFIG, + "Firmware revision (flash) %u.%u.%u (%x).", + fcp->fw_flashrev[0], fcp->fw_flashrev[1], + fcp->fw_flashrev[2], fcp->fw_flashrev[3]); + + /* If ispfw(4) is loaded compare versions and use the newest */ + if (isp->isp_osinfo.ispfw != NULL) { + if (ISP_FW_NEWER_THANX(fcp->fw_ispfwrev, fcp->fw_flashrev)) { + isp_prt(isp, ISP_LOGCONFIG, + "Loading RISC with newer ispfw(4) firmware"); + return (ISP_ABORTED); + } + isp_prt(isp, ISP_LOGCONFIG, + "Loading RISC with newer flash firmware"); + } + } + + dcode = isp->isp_rquest; + segments = ISP_RISC_CODE_SEGMENTS; + for (j = 0; j < segments; j++) { + isp_prt(isp, ISP_LOGDEBUG0, "Loading segment %u", j); + isp_read_flash_data(isp, dcode, faddr, 10); + risc_addr = be32toh(dcode[2]); + risc_size = be32toh(dcode[3]); + + dlen = min(risc_size, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) / 4); + for (fragment = 0; risc_size; fragment++) { + if (dlen > risc_size) + dlen = risc_size; + + isp_prt(isp, ISP_LOGDEBUG0, + "Loading fragment %u: 0x%x <- 0x%x (0x%lx dwords)", + fragment, risc_addr, faddr, dlen); + isp_read_flash_data(isp, dcode, faddr, dlen); + for (i = 0; i < dlen; i++) { + dcode[i] = bswap32(dcode[i]); + } + + rval = isp_load_ram(isp, dcode, risc_addr, dlen); + if (rval) { + isp_prt(isp, ISP_LOGERR, + "Failed to load firmware fragment %u.", + fragment); + return (ISP_FUNCTION_FAILED); + } + + faddr += dlen; + risc_addr += dlen; + risc_size -= dlen; + } + } + + return (rval); +} + +static int +isp_load_risc(ispsoftc_t *isp, uint32_t *srisc_addr) +{ + fcparam *fcp = FCPARAM(isp, 0); + int rval = ISP_SUCCESS; + struct active_regions active_regions = { }; + + /* + * Starting with 27xx there is a primary and secondary firmware region + * in flash. All older controllers just have one firmware region. + */ + if (!IS_27XX(isp)) + goto try_primary_fw; + + isp_get_active_image(isp, &active_regions); + + if (active_regions.global != ISP27XX_SECONDARY_IMAGE) + goto try_primary_fw; + + isp_prt(isp, ISP_LOGCONFIG, + "Loading secondary firmware image."); + rval = isp_load_risc_flash(isp, srisc_addr, fcp->flt_region_fw_sec); + return (rval); + +try_primary_fw: + isp_prt(isp, ISP_LOGCONFIG, + "Loading primary firmware image."); + rval = isp_load_risc_flash(isp, srisc_addr, fcp->flt_region_fw); + return (rval); +} + +static int +isp_read_nvram(ispsoftc_t *isp) { fcparam *fcp = FCPARAM(isp, 0); int retval = 0; uint32_t addr, csum, lwrds, *dptr; uint8_t nvram_data[ISP2400_NVRAM_SIZE]; + struct active_regions active_regions = { }; + + if (IS_27XX(isp)) + isp_get_aux_images(isp, &active_regions); addr = fcp->flt_region_nvram; + + if (IS_28XX(isp)) { + if (active_regions.aux.vpd_nvram == ISP27XX_SECONDARY_IMAGE) + addr = fcp->flt_region_nvram_sec; + + isp_prt(isp, ISP_LOGCONFIG, "Loading %s NVRAM image", + active_regions.aux.vpd_nvram == ISP27XX_PRIMARY_IMAGE ? + "primary" : "secondary"); + } + dptr = (uint32_t *) nvram_data; for (lwrds = 0; lwrds < ISP2400_NVRAM_SIZE >> 2; lwrds++) { isp_rd_2xxx_flash(isp, addr++, dptr++); diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index 85344692100..fdf4c0eb4e1 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -212,6 +212,15 @@ isp_attach_chan(ispsoftc_t *isp, struct cam_devq *devq, int chan) SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "use_gff_id", CTLFLAG_RWTUN, &fcp->isp_use_gff_id, 0, "Use GFF_ID during fabric scan"); + SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "fw_version_flash", CTLFLAG_RD, fcp->fw_version_flash, 0, + "Firmware version in (active) flash region"); + SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "fw_version_ispfw", CTLFLAG_RD, fcp->fw_version_ispfw, 0, + "Firmware version loaded from ispfw(4)"); + SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "fw_version_run", CTLFLAG_RD, fcp->fw_version_run, 0, + "Firmware version currently running"); return (0); } @@ -1500,7 +1509,7 @@ isp_handle_srr_start(ispsoftc_t *isp, atio_private_data_t *atp) */ isp_prt(isp, ISP_LOGWARN, "Got an FCP DATA IN SRR- dropping"); goto fail; - + default: isp_prt(isp, ISP_LOGWARN, "Got an unknown information (%x) SRR- dropping", inot->in_srr_iu); goto fail; @@ -2847,9 +2856,9 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) lipp = ISP_READ(isp, OUTMAILBOX1); fcp = FCPARAM(isp, bus); - + isp_prt(isp, ISP_LOGINFO, "Chan %d LOOP Reset, LIP primitive %x", bus, lipp); - /* + /* * Per FCP-4, a Reset LIP should result in a CRN reset. Other * LIPs and loop up/down events should never reset the CRN. For * an as of yet unknown reason, 24xx series cards (and @@ -2910,7 +2919,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) } break; case ISPASYNC_DEV_CHANGED: - case ISPASYNC_DEV_STAYED: + case ISPASYNC_DEV_STAYED: { int crn_reset_done; @@ -2925,7 +2934,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) if (cmd == ISPASYNC_DEV_CHANGED) isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->new_portid, lp->handle, buf, "changed"); else - isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->portid, lp->handle, buf, "stayed"); + isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->portid, lp->handle, buf, "stayed"); if (lp->is_target != ((FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) && @@ -3221,7 +3230,7 @@ isp_prt(ispsoftc_t *isp, int level, const char *fmt, ...) snprintf(lbuf, sizeof (lbuf), "%s: ", device_get_nameunit(isp->isp_dev)); loc = strlen(lbuf); va_start(ap, fmt); - vsnprintf(&lbuf[loc], sizeof (lbuf) - loc - 1, fmt, ap); + vsnprintf(&lbuf[loc], sizeof (lbuf) - loc - 1, fmt, ap); va_end(ap); printf("%s\n", lbuf); } diff --git a/sys/dev/isp/isp_freebsd.h b/sys/dev/isp/isp_freebsd.h index 0c0df2899ac..bd5bba92c0a 100644 --- a/sys/dev/isp/isp_freebsd.h +++ b/sys/dev/isp/isp_freebsd.h @@ -244,7 +244,7 @@ struct isposinfo { /* * Firmware pointer */ - const struct firmware * fw; + const struct firmware * ispfw; /* * DMA related stuff diff --git a/sys/dev/isp/isp_pci.c b/sys/dev/isp/isp_pci.c index c4dbceba25c..e7f9d4b77e3 100644 --- a/sys/dev/isp/isp_pci.c +++ b/sys/dev/isp/isp_pci.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -463,9 +462,8 @@ isp_pci_attach(device_t dev) struct isp_pcisoftc *pcs = device_get_softc(dev); ispsoftc_t *isp = &pcs->pci_isp; int i; - uint32_t data, cmd, linesz, did; + uint32_t data, cmd, linesz; size_t psize, xsize; - char fwname[32]; isp->isp_dev = dev; isp->isp_nchan = 1; @@ -485,23 +483,23 @@ isp_pci_attach(device_t dev) switch (pci_get_devid(dev)) { case PCI_QLOGIC_ISP2422: case PCI_QLOGIC_ISP2432: - did = 0x2400; + isp->isp_did = 0x2400; isp->isp_mdvec = &mdvec_2400; isp->isp_type = ISP_HA_FC_2400; break; case PCI_QLOGIC_ISP2532: - did = 0x2500; + isp->isp_did = 0x2500; isp->isp_mdvec = &mdvec_2500; isp->isp_type = ISP_HA_FC_2500; break; case PCI_QLOGIC_ISP5432: - did = 0x2500; + isp->isp_did = 0x2500; isp->isp_mdvec = &mdvec_2500; isp->isp_type = ISP_HA_FC_2500; break; case PCI_QLOGIC_ISP2031: case PCI_QLOGIC_ISP8031: - did = 0x2600; + isp->isp_did = 0x2600; isp->isp_mdvec = &mdvec_2600; isp->isp_type = ISP_HA_FC_2600; break; @@ -509,13 +507,13 @@ isp_pci_attach(device_t dev) case PCI_QLOGIC_ISP2692: case PCI_QLOGIC_ISP2714: case PCI_QLOGIC_ISP2722: - did = 0x2700; + isp->isp_did = 0x2700; isp->isp_mdvec = &mdvec_2700; isp->isp_type = ISP_HA_FC_2700; break; case PCI_QLOGIC_ISP2812: case PCI_QLOGIC_ISP2814: - did = 0x2800; + isp->isp_did = 0x2800; isp->isp_mdvec = &mdvec_2800; isp->isp_type = ISP_HA_FC_2800; break; @@ -582,16 +580,6 @@ isp_pci_attach(device_t dev) isp_get_specific_options(dev, i, isp); } - isp->isp_osinfo.fw = NULL; - if (isp->isp_osinfo.fw == NULL) { - snprintf(fwname, sizeof (fwname), "isp_%04x", did); - isp->isp_osinfo.fw = firmware_get(fwname); - } - if (isp->isp_osinfo.fw != NULL) { - isp_prt(isp, ISP_LOGCONFIG, "loaded firmware %s", fwname); - isp->isp_mdvec->dv_ispfw = isp->isp_osinfo.fw->data; - } - /* * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER are set. */ @@ -650,15 +638,6 @@ isp_pci_attach(device_t dev) return (0); bad: - if (isp->isp_osinfo.fw == NULL && !IS_26XX(isp)) { - /* - * Failure to attach at boot time might have been caused - * by a missing ispfw(4). Except for 16Gb adapters, - * there's no loadable firmware for them. - */ - isp_prt(isp, ISP_LOGWARN, "See the ispfw(4) man page on " - "how to load known good firmware at boot time"); - } for (i = 0; i < isp->isp_nirq; i++) { (void) bus_teardown_intr(dev, pcs->irq[i].irq, pcs->irq[i].ih); (void) bus_release_resource(dev, SYS_RES_IRQ, pcs->irq[i].iqd, diff --git a/sys/dev/isp/ispmbox.h b/sys/dev/isp/ispmbox.h index 42a45e9c7ea..c6ac9d9ce97 100644 --- a/sys/dev/isp/ispmbox.h +++ b/sys/dev/isp/ispmbox.h @@ -41,14 +41,15 @@ #define MBOX_NO_OP 0x0000 #define MBOX_LOAD_RAM 0x0001 #define MBOX_EXEC_FIRMWARE 0x0002 -#define MBOX_DUMP_RAM 0x0003 +#define MBOX_LOAD_FLASH_FIRMWARE 0x0003 #define MBOX_WRITE_RAM_WORD 0x0004 #define MBOX_READ_RAM_WORD 0x0005 #define MBOX_MAILBOX_REG_TEST 0x0006 #define MBOX_VERIFY_CHECKSUM 0x0007 #define MBOX_ABOUT_FIRMWARE 0x0008 #define MBOX_LOAD_RISC_RAM_2100 0x0009 - /* a */ +#define MBOX_DUMP_RISC_RAM_2100 0x000a +#define MBOX_SECURE_FLASH_UPDATE 0x000a /* Secure Flash Update(28xx) */ #define MBOX_LOAD_RISC_RAM 0x000b #define MBOX_DUMP_RISC_RAM 0x000c #define MBOX_WRITE_RAM_WORD_EXTENDED 0x000d @@ -124,7 +125,6 @@ #define MBOX_GET_TARGET_STATUS 0x0056 /* These are for the ISP2X00 FC cards */ -#define MBOX_LOAD_FLASH_FIRMWARE 0x0003 #define MBOX_WRITE_FC_SERDES_REG 0x0003 /* FC only */ #define MBOX_READ_FC_SERDES_REG 0x0004 /* FC only */ #define MBOX_GET_IO_STATUS 0x0012 @@ -554,39 +554,47 @@ typedef struct { /* * About Firmware returns an 'attribute' word. */ -#define ISP2400_FW_ATTR_CLASS2 0x0001 -#define ISP2400_FW_ATTR_IP 0x0002 -#define ISP2400_FW_ATTR_MULTIID 0x0004 -#define ISP2400_FW_ATTR_SB2 0x0008 -#define ISP2400_FW_ATTR_T10CRC 0x0010 -#define ISP2400_FW_ATTR_VI 0x0020 -#define ISP2400_FW_ATTR_MQ 0x0040 -#define ISP2400_FW_ATTR_MSIX 0x0080 -#define ISP2400_FW_ATTR_FCOE 0x0800 -#define ISP2400_FW_ATTR_VP0 0x1000 -#define ISP2400_FW_ATTR_EXPFW 0x2000 -#define ISP2400_FW_ATTR_HOTFW 0x4000 -#define ISP2400_FW_ATTR_EXTNDED 0x8000 -#define ISP2400_FW_ATTR_EXTVP 0x00010000 -#define ISP2400_FW_ATTR_VN2VN 0x00040000 -#define ISP2400_FW_ATTR_EXMOFF 0x00080000 -#define ISP2400_FW_ATTR_NPMOFF 0x00100000 -#define ISP2400_FW_ATTR_DIFCHOP 0x00400000 -#define ISP2400_FW_ATTR_SRIOV 0x02000000 -#define ISP2400_FW_ATTR_ASICTMP 0x0200000000 -#define ISP2400_FW_ATTR_ATIOMQ 0x0400000000 +#define ISP_FW_ATTR_CLASS2 0x0001 +#define ISP_FW_ATTR_IP 0x0002 +#define ISP_FW_ATTR_MULTIID 0x0004 +#define ISP_FW_ATTR_SB2 0x0008 +#define ISP_FW_ATTR_T10CRC 0x0010 +#define ISP_FW_ATTR_VI 0x0020 +#define ISP_FW_ATTR_MQ 0x0040 +#define ISP_FW_ATTR_MSIX 0x0080 +#define ISP_FW_ATTR_FCOE 0x0800 +#define ISP_FW_ATTR_VP0 0x1000 +#define ISP_FW_ATTR_EXPFW 0x2000 +#define ISP_FW_ATTR_HOTFW 0x4000 +#define ISP_FW_ATTR_EXTNDED 0x8000 + +#define ISP_FW_ATTR_H_EXTVP 0x0001 +#define ISP_FW_ATTR_H_NVME_FB 0x0002 /* NVMe first burst */ +#define ISP_FW_ATTR_H_VN2VN 0x0004 /* Extended login */ +#define ISP_FW_ATTR_H_EXMOFF 0x0008 /* Exchange offload */ +#define ISP_FW_ATTR_H_NPMOFF 0x0010 +#define ISP_FW_ATTR_H_DIFCHOP 0x0040 +#define ISP_FW_ATTR_H_SRIOV 0x0200 +#define ISP_FW_ATTR_H_NVME 0x0400 /* FC-NVMe */ +#define ISP_FW_ATTR_H_NVME_UP 0x4000 /* FC-NVMe updated */ + +#define ISP_FW_ATTR_E0_ASICTMP 0x0002 +#define ISP_FW_ATTR_E0_ATIOMQ 0x0004 +#define ISP_FW_ATTR_E0_EDIF 0x0020 /* Encryption of data in flight */ +#define ISP_FW_ATTR_E0_SCM 0x1000 /* Simplified Configuration and Management */ +#define ISP_FW_ATTR_E0_NVME2 0x2000 /* NVMe2 */ /* * This is only true for 24XX cards with this f/w attribute */ #define ISP_CAP_MULTI_ID(isp) \ - (isp->isp_fwattr & ISP2400_FW_ATTR_MULTIID) + (isp->isp_fwattr & ISP_FW_ATTR_MULTIID) #define ISP_GET_VPIDX(isp, tag) \ (ISP_CAP_MULTI_ID(isp) ? tag : 0) #define ISP_CAP_MSIX(isp) \ - (isp->isp_fwattr & ISP2400_FW_ATTR_MSIX) + (isp->isp_fwattr & ISP_FW_ATTR_MSIX) #define ISP_CAP_VP0(isp) \ - (isp->isp_fwattr & ISP2400_FW_ATTR_VP0) + (isp->isp_fwattr & ISP_FW_ATTR_VP0) #define ISP_FCTAPE_ENABLED(isp, chan) \ ((FCPARAM(isp, chan)->isp_xfwoptions & ICB2400_OPT2_FCTAPE) != 0) diff --git a/sys/dev/isp/ispreg.h b/sys/dev/isp/ispreg.h index 322b2db35fe..cf25f6120ea 100644 --- a/sys/dev/isp/ispreg.h +++ b/sys/dev/isp/ispreg.h @@ -343,4 +343,15 @@ struct flt_region { #define FLT_REG_VPD_SEC_28XX_2 0x110 #define FLT_REG_VPD_SEC_28XX_3 0x112 +#define ISP27XX_IMG_STATUS_VER_MAJOR 0x01 +#define ISP27XX_IMG_STATUS_VER_MINOR 0x00 +#define ISP27XX_IMG_STATUS_SIGN 0xfacefade +#define ISP28XX_IMG_STATUS_SIGN 0xfacefadf +#define ISP28XX_AUX_IMG_STATUS_SIGN 0xfacefaed +#define ISP27XX_DEFAULT_IMAGE 0 +#define ISP27XX_PRIMARY_IMAGE 1 +#define ISP27XX_SECONDARY_IMAGE 2 + +#define ISP_RISC_CODE_SEGMENTS 2 + #endif /* _ISPREG_H */ diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h index 810850ef9b7..6c3430246b2 100644 --- a/sys/dev/isp/ispvar.h +++ b/sys/dev/isp/ispvar.h @@ -67,7 +67,7 @@ struct ispmdvec { int (*dv_send_cmd) (ispsoftc_t *, void *, void *, uint32_t); int (*dv_irqsetup) (ispsoftc_t *); void (*dv_dregs) (ispsoftc_t *, const char *); - const void * dv_ispfw; /* ptr to f/w */ + const void * dv_ispfw; /* ptr to f/w of ispfw(4)*/ }; /* @@ -369,30 +369,39 @@ typedef struct { int isp_use_gff_id; /* Use GFF_ID */ uint32_t flash_data_addr; + uint32_t fw_flashrev[4]; /* Flash F/W revision */ + uint32_t fw_ispfwrev[4]; /* ispfw(4) F/W revision */ + char fw_version_flash[12]; + char fw_version_ispfw[12]; + char fw_version_run[12]; + uint32_t fw_ability_mask; + uint16_t max_supported_speed; + /* * FLT */ uint16_t flt_length; uint32_t flt_region_entries; - uint32_t flt_region_aux_img_status_pri; - uint32_t flt_region_aux_img_status_sec; - uint32_t flt_region_boot; - uint32_t flt_region_fcp_prio; - uint32_t flt_region_fdt; uint32_t flt_region_flt; - uint32_t flt_region_fw; - uint32_t flt_region_gold_fw; - uint32_t flt_region_img_status_pri; - uint32_t flt_region_img_status_sec; - uint32_t flt_region_fw_sec; + uint32_t flt_region_fdt; + uint32_t flt_region_boot; uint32_t flt_region_boot_sec; - uint32_t flt_region_npiv_conf; - uint32_t flt_region_nvram; - uint32_t flt_region_nvram_sec; - uint32_t flt_region_vpd; + uint32_t flt_region_fw; + uint32_t flt_region_fw_sec; uint32_t flt_region_vpd_nvram; uint32_t flt_region_vpd_nvram_sec; + uint32_t flt_region_vpd; uint32_t flt_region_vpd_sec; + uint32_t flt_region_nvram; + uint32_t flt_region_nvram_sec; + uint32_t flt_region_npiv_conf; + uint32_t flt_region_gold_fw; + uint32_t flt_region_fcp_prio; + uint32_t flt_region_bootload; + uint32_t flt_region_img_status_pri; + uint32_t flt_region_img_status_sec; + uint32_t flt_region_aux_img_status_pri; + uint32_t flt_region_aux_img_status_sec; /* * Current active WWNN/WWPN @@ -420,6 +429,41 @@ typedef struct { uint8_t isp_scanscratch[ISP_FC_SCRLEN]; } fcparam; +/* + * Image status + */ +struct isp_image_status{ + uint8_t image_status_mask; + uint16_t generation; + uint8_t ver_major; + uint8_t ver_minor; + uint8_t bitmap; /* 28xx only */ + uint8_t reserved[2]; + uint32_t checksum; + uint32_t signature; +} __packed; + +/* 28xx aux image status bitmap values */ +#define ISP28XX_AUX_IMG_BOARD_CONFIG 0x1 +#define ISP28XX_AUX_IMG_VPD_NVRAM 0x2 +#define ISP28XX_AUX_IMG_NPIV_CONFIG_0_1 0x4 +#define ISP28XX_AUX_IMG_NPIV_CONFIG_2_3 0x8 +#define ISP28XX_AUX_IMG_NVME_PARAMS 0x10 + +/* + * Active regions + */ +struct active_regions { + uint8_t global; + struct { + uint8_t board_config; + uint8_t vpd_nvram; + uint8_t npiv_config_0_1; + uint8_t npiv_config_2_3; + uint8_t nvme_params; + } aux; +}; + #define FW_CONFIG_WAIT 0 #define FW_WAIT_LINK 1 #define FW_WAIT_LOGIN 2 @@ -473,11 +517,14 @@ struct ispsoftc { */ fcparam *isp_param; /* Per-channel storage. */ - uint64_t isp_fwattr; /* firmware attributes */ + uint16_t isp_fwattr; /* firmware attributes */ + uint16_t isp_fwattr_h; /* firmware attributes */ + uint16_t isp_fwattr_ext[2]; /* firmware attributes */ uint16_t isp_fwrev[3]; /* Loaded F/W revision */ uint16_t isp_maxcmds; /* max possible I/O cmds */ uint16_t isp_nchan; /* number of channels */ uint16_t isp_dblev; /* debug log mask */ + uint32_t isp_did; /* DID */ uint8_t isp_type; /* HBA Chip Type */ uint8_t isp_revision; /* HBA Chip H/W Revision */ uint8_t isp_nirq; /* number of IRQs */ @@ -554,8 +601,8 @@ struct ispsoftc { #define ISP_CFG_NPORT 0x08 /* prefer {N/F}-Port connection */ #define ISP_CFG_1GB 0x10 /* force 1Gb connection (23XX only) */ #define ISP_CFG_2GB 0x20 /* force 2Gb connection (23XX only) */ -#define ISP_CFG_NORELOAD 0x80 /* don't download f/w */ #define ISP_CFG_NONVRAM 0x40 /* ignore NVRAM */ +#define ISP_CFG_NORELOAD 0x80 /* don't download f/w */ #define ISP_CFG_NOFCTAPE 0x100 /* disable FC-Tape */ #define ISP_CFG_FCTAPE 0x200 /* enable FC-Tape */ #define ISP_CFG_OWNFSZ 0x400 /* override NVRAM frame size */ @@ -613,18 +660,22 @@ struct ispsoftc { #define ISP_CODE_ORG 0x1000 /* default f/w code start */ #define ISP_CODE_ORG_2300 0x0800 /* ..except for 2300s */ #define ISP_CODE_ORG_2400 0x100000 /* ..and 2400s */ -#define ISP_FW_REV(maj, min, mic) ((maj << 24) | (min << 16) | mic) -#define ISP_FW_MAJOR(code) ((code >> 24) & 0xff) -#define ISP_FW_MINOR(code) ((code >> 16) & 0xff) -#define ISP_FW_MICRO(code) ((code >> 8) & 0xff) -#define ISP_FW_REVX(xp) ((xp[0]<<24) | (xp[1] << 16) | xp[2]) +#define ISP_FW_REV(maj, min, mic) (((maj) << 16) | ((min) << 8) | (mic)) +#define ISP_FW_MAJOR(code) (((code) >> 16) & 0xff) +#define ISP_FW_MINOR(code) (((code) >> 8) & 0xff) +#define ISP_FW_MICRO(code) ((code) & 0xff) +#define ISP_FW_REVX(xp) (((xp)[0] << 16) | ((xp)[1] << 8) | (xp)[2]) #define ISP_FW_MAJORX(xp) (xp[0]) #define ISP_FW_MINORX(xp) (xp[1]) #define ISP_FW_MICROX(xp) (xp[2]) #define ISP_FW_NEWER_THAN(i, major, minor, micro) \ - (ISP_FW_REVX((i)->isp_fwrev) > ISP_FW_REV(major, minor, micro)) + (ISP_FW_REVX(i) > ISP_FW_REV(major, minor, micro)) #define ISP_FW_OLDER_THAN(i, major, minor, micro) \ - (ISP_FW_REVX((i)->isp_fwrev) < ISP_FW_REV(major, minor, micro)) + (ISP_FW_REVX(i) < ISP_FW_REV(major, minor, micro)) +#define ISP_FW_NEWER_THANX(i, j) \ + (ISP_FW_REVX(i) > ISP_FW_REVX(j)) +#define ISP_FW_OLDER_THANX(i, j) \ + (ISP_FW_REVX(i) < ISP_FW_REVX(j)) /* * Chip Types @@ -651,6 +702,36 @@ struct ispsoftc { #define DMA_LO32(x) ((uint32_t) (x)) #define DMA_HI32(x) ((uint32_t)(((uint64_t)x) >> 32)) +/* + * function return status codes + */ +#define MBS_MASK 0x3fff + +#define ISP_SUCCESS (MBOX_COMMAND_COMPLETE & MBS_MASK) +#define ISP_INVALID_COMMAND (MBOX_INVALID_COMMAND & MBS_MASK) +#define ISP_INTERFACE_ERROR (MBOX_HOST_INTERFACE_ERROR & MBS_MASK) +#define ISP_TEST_FAILED (MBOX_TEST_FAILED & MBS_MASK) +#define ISP_COMMAND_ERROR (MBOX_COMMAND_ERROR & MBS_MASK) +#define ISP_PARAMETER_ERROR (MBOX_COMMAND_PARAMETER_ERROR & MBS_MASK) +#define ISP_PORT_ID_USED (MBOX_PORT_ID_USED & MBS_MASK) +#define ISP_LOOP_ID_USED (MBOX_LOOP_ID_USED & MBS_MASK) +#define ISP_ALL_IDS_IN_USE (MBOX_ALL_IDS_IN_USE & MBS_MASK) +#define ISP_NOT_LOGGED_IN (MBOX_NOT_LOGGED_IN & MBS_MASK) + +#define ISP_FUNCTION_TIMEOUT 0x100 +#define ISP_FUNCTION_PARAMETER_ERROR 0x101 +#define ISP_FUNCTION_FAILED 0x102 +#define ISP_MEMORY_ALLOC_FAILED 0x103 +#define ISP_LOCK_TIMEOUT 0x104 +#define ISP_ABORTED 0x105 +#define ISP_SUSPENDED 0x106 +#define ISP_BUSY 0x107 +#define ISP_ALREADY_REGISTERED 0x109 +#define ISP_OS_TIMER_EXPIRED 0x10a +#define ISP_ERR_NO_QPAIR 0x10b +#define ISP_ERR_NOT_FOUND 0x10c +#define ISP_ERR_FROM_FW 0x10d + /* * Core System Function Prototypes */