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 */