git: 10ed63fc06cb - main - isp(4): Rework firmware handling/loading

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Thu, 28 Dec 2023 18:35:45 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=10ed63fc06cb9902cc783ce8d0086c9aa97ed1e1

commit 10ed63fc06cb9902cc783ce8d0086c9aa97ed1e1
Author:     Joerg Pulz <Joerg.Pulz@frm2.tum.de>
AuthorDate: 2023-10-27 15:27:37 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2023-12-28 18:33:07 +0000

    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         | 981 ++++++++++++++++++++++++++++++++++++++--------
 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      | 127 ++++--
 8 files changed, 1002 insertions(+), 258 deletions(-)

diff --git a/share/man/man4/isp.4 b/share/man/man4/isp.4
index 277e7775ddee..350a0ea59a64 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 74f90b64441c..aa2f1fb74c59 100644
--- a/sys/dev/isp/isp.c
+++ b/sys/dev/isp/isp.c
@@ -49,7 +49,9 @@ __KERNEL_RCSID(0, "$NetBSD$");
 #include <dev/ic/isp_netbsd.h>
 #endif
 #ifdef	__FreeBSD__
+#include <sys/param.h>
 #include <sys/cdefs.h>
+#include <sys/firmware.h>
 #include <dev/isp/isp_freebsd.h>
 #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;
+	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 & 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%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 & ISP2400_FW_ATTR_ATIOMQ) {
-		fwt ^= ISP2400_FW_ATTR_ATIOMQ;
+	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%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[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;
-		}
-		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);
+	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);
 		}
-	} 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_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)
*** 879 LINES SKIPPED ***