--- old/usr/src/uts/common/io/fibre-channel/fca/qlc/ql_nx.c	Mon Aug  5 17:28:45 2019
+++ new/usr/src/uts/common/io/fibre-channel/fca/qlc/ql_nx.c	Mon Aug  5 17:28:45 2019
@@ -20,11 +20,11 @@
  */
 
 /*
- * Copyright 2010 QLogic Corporation.  All rights reserved.
+ * Copyright 2015 QLogic Corporation.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"Copyright 2010 QLogic Corporation; ql_nx.c"
+#pragma ident	"Copyright 2015 QLogic Corporation; ql_nx.c"
 
 /*
  * ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
@@ -32,7 +32,7 @@
  * ***********************************************************************
  * *									**
  * *				NOTICE					**
- * *		COPYRIGHT (C) 1996-2010 QLOGIC CORPORATION		**
+ * *		COPYRIGHT (C) 1996-2015 QLOGIC CORPORATION		**
  * *			ALL RIGHTS RESERVED				**
  * *									**
  * ***********************************************************************
@@ -42,6 +42,7 @@
 #include <ql_apps.h>
 #include <ql_api.h>
 #include <ql_debug.h>
+#include <ql_init.h>
 #include <ql_mbx.h>
 #include <ql_nx.h>
 
@@ -48,11 +49,8 @@
 /*
  *  Local Function Prototypes.
  */
-static void *ql_8021_pci_base_offsetfset(ql_adapter_state_t *, uint64_t);
 static void ql_crb_addr_transform_setup(ql_adapter_state_t *);
 static void ql_8021_pci_set_crbwindow_2M(ql_adapter_state_t *, uint64_t *);
-static void ql_8021_wr_32(ql_adapter_state_t *, uint64_t, uint32_t);
-static void ql_8021_rd_32(ql_adapter_state_t *, uint64_t, uint32_t *);
 static int ql_8021_crb_win_lock(ql_adapter_state_t *);
 static void ql_8021_crb_win_unlock(ql_adapter_state_t *);
 static int ql_8021_pci_get_crb_addr_2M(ql_adapter_state_t *, uint64_t *);
@@ -86,6 +84,35 @@
 static int ql_8021_hw_lock(ql_adapter_state_t *, uint32_t);
 static void ql_8021_hw_unlock(ql_adapter_state_t *);
 static void ql_8021_need_reset_handler(ql_adapter_state_t *);
+static int ql_8021_load_fw(ql_adapter_state_t *);
+static uint32_t ql_8021_check_fw_alive(ql_adapter_state_t *);
+static int ql_8021_get_fw_dump(ql_adapter_state_t *);
+static void ql_8021_md_parse_template(ql_adapter_state_t *, caddr_t, caddr_t,
+    uint32_t, uint32_t);
+static int ql_8021_md_rdcrb(ql_adapter_state_t *, md_entry_rdcrb_t *,
+    uint32_t *);
+static int ql_8021_md_L2Cache(ql_adapter_state_t *, md_entry_cache_t *,
+    uint32_t *);
+static int ql_8021_md_L1Cache(ql_adapter_state_t *, md_entry_cache_t *,
+    uint32_t *);
+static int ql_8021_md_rdocm(ql_adapter_state_t *, md_entry_rdocm_t *,
+    uint32_t *);
+static int ql_8021_md_rdmem(ql_adapter_state_t *, md_entry_rdmem_t *,
+    uint32_t *);
+static int ql_8021_md_rdrom(ql_adapter_state_t *, md_entry_rdrom_t *,
+    uint32_t *);
+static int ql_8021_md_rdmux(ql_adapter_state_t *, md_entry_mux_t *,
+    uint32_t *);
+static int ql_8021_md_rdqueue(ql_adapter_state_t *, md_entry_queue_t *,
+    uint32_t *);
+static int ql_8021_md_cntrl(ql_adapter_state_t *, md_template_hdr_t *,
+    md_entry_cntrl_t *);
+static void ql_8021_md_entry_err_chk(ql_adapter_state_t *, md_entry_t *,
+    uint32_t, int);
+static uint32_t ql_8021_md_template_checksum(ql_adapter_state_t *);
+static uint32_t ql_8021_read_reg(ql_adapter_state_t *, uint32_t);
+static void ql_8021_write_reg(ql_adapter_state_t *, uint32_t, uint32_t);
+static uint32_t ql_8021_read_ocm(ql_adapter_state_t *, uint32_t);
 
 /*
  * Local Data.
@@ -120,7 +147,7 @@
 	{{{1, 0x0500000, 0x0510000, 0x140000}}},	/* 5: SRE   */
 	{{{1, 0x0600000, 0x0610000, 0x1c0000}}},	/* 6: NIU   */
 	{{{1, 0x0700000, 0x0704000, 0x1b8000}}},	/* 7: QM    */
-	{{{1, 0x0800000, 0x0802000, 0x170000},  	/* 8: SQM0  */
+	{{{1, 0x0800000, 0x0802000, 0x170000},		/* 8: SQM0  */
 	    {0, 0x0000000, 0x0000000, 0x000000},
 	    {0, 0x0000000, 0x0000000, 0x000000},
 	    {0, 0x0000000, 0x0000000, 0x000000},
@@ -323,17 +350,6 @@
 	0,
 };
 
-static void *
-ql_8021_pci_base_offsetfset(ql_adapter_state_t *ha, uint64_t off)
-{
-	if ((off < ha->first_page_group_end) &&
-	    (off >= ha->first_page_group_start)) {
-		return ((void *)(ha->nx_pcibase + off));
-	}
-
-	return (NULL);
-}
-
 /* ARGSUSED */
 static void
 ql_crb_addr_transform_setup(ql_adapter_state_t *ha)
@@ -404,10 +420,10 @@
 static void
 ql_8021_pci_set_crbwindow_2M(ql_adapter_state_t *ha, uint64_t *off)
 {
-	uint32_t	win_read;
+	uint32_t	win_read, crb_win;
 
-	ha->crb_win = (uint32_t)CRB_HI(*off);
-	WRT_REG_DWORD(ha, CRB_WINDOW_2M + ha->nx_pcibase, ha->crb_win);
+	crb_win = (uint32_t)CRB_HI(*off);
+	WRT_REG_DWORD(ha, CRB_WINDOW_2M + ha->nx_pcibase, crb_win);
 
 	/*
 	 * Read back value to make sure write has gone through before trying
@@ -414,14 +430,14 @@
 	 * to use it.
 	 */
 	win_read = RD_REG_DWORD(ha, CRB_WINDOW_2M + ha->nx_pcibase);
-	if (win_read != ha->crb_win) {
+	if (win_read != crb_win) {
 		EL(ha, "Written crbwin (0x%x) != Read crbwin (0x%x), "
-		    "off=0x%llx\n", ha->crb_win, win_read, *off);
+		    "off=0x%llx\n", crb_win, win_read, *off);
 	}
 	*off = (*off & MASK(16)) + CRB_INDIRECT_2M + (uintptr_t)ha->nx_pcibase;
 }
 
-static void
+void
 ql_8021_wr_32(ql_adapter_state_t *ha, uint64_t off, uint32_t data)
 {
 	int	rv;
@@ -443,7 +459,7 @@
 	}
 }
 
-static void
+void
 ql_8021_rd_32(ql_adapter_state_t *ha, uint64_t off, uint32_t *data)
 {
 	int		rv;
@@ -490,7 +506,7 @@
 		/* Yield CPU */
 		delay(1);
 	}
-	ql_8021_wr_32(ha, UNM_CRB_WIN_LOCK_ID, ha->function_number);
+	ql_8021_wr_32(ha, UNM_CRB_WIN_LOCK_ID, ha->pci_function_number);
 
 	return (0);
 }
@@ -574,10 +590,8 @@
 	    UNM_ADDR_DDR_NET_MAX)) {
 		/* DDR network side */
 		window = (uint32_t)MN_WIN(addr);
-		ha->ddr_mn_window = window;
-		ql_8021_wr_32(ha, ha->mn_win_crb | UNM_PCI_CRBSPACE, window);
-		ql_8021_rd_32(ha, ha->mn_win_crb | UNM_PCI_CRBSPACE,
-		    &win_read);
+		ql_8021_wr_32(ha, UNM_PCI_CRBSPACE, window);
+		ql_8021_rd_32(ha, UNM_PCI_CRBSPACE, &win_read);
 		if ((win_read << 17) != window) {
 			EL(ha, "Warning, Written MNwin (0x%x) != Read MNwin "
 			    "(0x%x)\n", window, win_read);
@@ -594,10 +608,8 @@
 		}
 
 		window = (uint32_t)OCM_WIN(addr);
-		ha->ddr_mn_window = window;
-		ql_8021_wr_32(ha, ha->mn_win_crb | UNM_PCI_CRBSPACE, window);
-		ql_8021_rd_32(ha, ha->mn_win_crb | UNM_PCI_CRBSPACE,
-		    &win_read);
+		ql_8021_wr_32(ha, UNM_PCI_CRBSPACE, window);
+		ql_8021_rd_32(ha, UNM_PCI_CRBSPACE, &win_read);
 		temp1 = ((window & 0x1FF) << 7) |
 		    ((window & 0x0FFFE0000) >> 17);
 		if (win_read != temp1) {
@@ -610,9 +622,8 @@
 		/* QDR network side */
 		window = (uint32_t)MS_WIN(addr);
 		ha->qdr_sn_window = window;
-		ql_8021_wr_32(ha, ha->mn_win_crb | UNM_PCI_CRBSPACE, window);
-		ql_8021_rd_32(ha, ha->mn_win_crb | UNM_PCI_CRBSPACE,
-		    &win_read);
+		ql_8021_wr_32(ha, UNM_PCI_CRBSPACE, window);
+		ql_8021_rd_32(ha, UNM_PCI_CRBSPACE, &win_read);
 		if (win_read != window) {
 			EL(ha, "Written MSwin (0x%x) != Read MSwin (0x%x)\n",
 			    window, win_read);
@@ -684,23 +695,20 @@
 		return (-1);
 	}
 
-	addr = ql_8021_pci_base_offsetfset(ha, start);
-	if (!addr) {
-		addr = (void *)((uint8_t *)ha->nx_pcibase + start);
-	}
+	addr = (void *)((uint8_t *)ha->nx_pcibase + start);
 
 	switch (size) {
 	case 1:
-		*(uint8_t  *)data = RD_REG_BYTE(ha, addr);
+		*(uint8_t *)data = RD_REG_BYTE(ha, addr);
 		break;
 	case 2:
-		*(uint16_t  *)data = RD_REG_WORD(ha, addr);
+		*(uint16_t *)data = RD_REG_WORD(ha, addr);
 		break;
 	case 4:
-		*(uint32_t  *)data = RD_REG_DWORD(ha, addr);
+		*(uint32_t *)data = RD_REG_DWORD(ha, addr);
 		break;
 	case 8:
-		*(uint64_t  *)data = RD_REG_DDWORD(ha, addr);
+		*(uint64_t *)data = RD_REG_DDWORD(ha, addr);
 		break;
 	default:
 		EL(ha, "invalid size=%x\n", size);
@@ -730,10 +738,7 @@
 		return (-1);
 	}
 
-	addr = ql_8021_pci_base_offsetfset(ha, start);
-	if (!addr) {
-		addr = (void *)((uint8_t *)ha->nx_pcibase + start);
-	}
+	addr = (void *)((uint8_t *)ha->nx_pcibase + start);
 
 	switch (size) {
 	case 1:
@@ -945,8 +950,8 @@
 			word[startword] |= tmpw << (off0 * 8);
 		}
 		if (sz[1] != 0) {
-			word[startword+1] &= ~(~0ULL << (sz[1] * 8));
-			word[startword+1] |= tmpw >> (sz[0] * 8);
+			word[startword + 1] &= ~(~0ULL << (sz[1] * 8));
+			word[startword + 1] |= tmpw >> (sz[0] * 8);
 		}
 	} else {
 		word[startword] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
@@ -1119,7 +1124,7 @@
 	clock_t		timer;
 	uint32_t	status;
 
-	for (timer = 30 * drv_usectohz(1000000); timer; timer--) {
+	for (timer = 500000; timer; timer--) {
 		ql_8021_wr_32(ha, UNM_ROMUSB_ROM_ABYTE_CNT, 0);
 		ql_8021_wr_32(ha, UNM_ROMUSB_ROM_INSTR_OPCODE,
 		    UNM_ROMUSB_ROM_RDSR_INSTR);
@@ -1133,7 +1138,7 @@
 		if (!(status & BIT_0)) {
 			return (0);
 		}
-		delay(1);
+		drv_usecwait(10);
 	}
 
 	EL(ha, "timeout status=%x\n", status);
@@ -1167,8 +1172,8 @@
 {
 	int	ret, loops = 0;
 
-	while ((ql_8021_rom_lock(ha) != 0) && (loops < 50000)) {
-		drv_usecwait(100);
+	while ((ql_8021_rom_lock(ha) != 0) && (loops < 500000)) {
+		drv_usecwait(10);
 		loops++;
 	}
 	if (loops >= 50000) {
@@ -1254,8 +1259,8 @@
 {
 	int	ret, loops = 0;
 
-	while ((ql_8021_rom_lock(ha) != 0) && (loops < 50000)) {
-		drv_usecwait(100);
+	while ((ql_8021_rom_lock(ha) != 0) && (loops < 500000)) {
+		drv_usecwait(10);
 		loops++;
 	}
 	if (loops >= 50000) {
@@ -1275,8 +1280,8 @@
 {
 	int	ret, loops = 0;
 
-	while ((ql_8021_rom_lock(ha) != 0) && (loops < 50000)) {
-		drv_usecwait(100);
+	while ((ql_8021_rom_lock(ha) != 0) && (loops < 500000)) {
+		drv_usecwait(10);
 		loops++;
 	}
 	if (loops >= 50000) {
@@ -1296,8 +1301,8 @@
 {
 	int	ret = QL_SUCCESS, loops = 0;
 
-	while ((ql_8021_rom_lock(ha) != 0) && (loops < 50000)) {
-		drv_usecwait(100);
+	while ((ql_8021_rom_lock(ha) != 0) && (loops < 500000)) {
+		drv_usecwait(10);
 		loops++;
 	}
 	if (loops >= 50000) {
@@ -1379,6 +1384,7 @@
 	ql_8021_wr_32(ha, UNM_ROMUSB_GLB_SW_RESET, 0xffffffff);
 	/* Just in case it was held when we reset the chip */
 	ql_8021_rom_unlock(ha);
+	delay(100);
 
 	if (ql_8021_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafe ||
 	    ql_8021_rom_fast_read(ha, 4, &n) != 0) {
@@ -1512,8 +1518,7 @@
 	uint64_t	data;
 
 	size = ha->bootloader_size / 2;
-	flashaddr = ha->bootloader_addr << 2;
-	memaddr = BOOTLD_START;
+	memaddr = flashaddr = ha->bootloader_addr << 2;
 
 	for (i = 0; i < size; i++) {
 		if ((ql_8021_rom_fast_read(ha, flashaddr, &low)) ||
@@ -1522,14 +1527,26 @@
 			return (-1);
 		}
 		data = ((uint64_t)high << 32) | low;
-		(void) ql_8021_pci_mem_write_2M(ha, memaddr, &data, 8);
+		if (ql_8021_pci_mem_write_2M(ha, memaddr, &data, 8)) {
+			EL(ha, "qla_fc_8021_pci_mem_write_2M != 0\n");
+			return (-1);
+		}
 		flashaddr += 8;
 		memaddr += 8;
+
+		/* Allow other system activity. */
+		if (i % 0x1000 == 0) {
+			/* Delay for 1 tick (10ms). */
+			delay(1);
+		}
 	}
 
+#if 0
+	/* Allow other system activity, delay for 1 tick (10ms). */
+	delay(1);
+
 	size = ha->flash_fw_size / 2;
-	flashaddr = ha->flash_fw_addr << 2;
-	memaddr = IMAGE_START;
+	memaddr = flashaddr = ha->flash_fw_addr << 2;
 
 	for (i = 0; i < size; i++) {
 		if ((ql_8021_rom_fast_read(ha, flashaddr, &low)) ||
@@ -1541,8 +1558,14 @@
 		(void) ql_8021_pci_mem_write_2M(ha, memaddr, &data, 8);
 		flashaddr += 8;
 		memaddr += 8;
-	}
 
+		/* Allow other system activity. */
+		if (i % 0x1000 == 0) {
+			/* Delay for 1 tick (10ms). */
+			delay(1);
+		}
+	}
+#endif
 	return (0);
 }
 
@@ -1561,11 +1584,10 @@
 	LITTLE_ENDIAN_32(&size);
 	EL(ha, "signature=%x\n", size);
 
-	size = (IMAGE_START - BOOTLD_START) / 8;
+	size = ha->bootloader_size / 2;
+	flashaddr = ha->bootloader_addr << 2;
 
-	bp = (uint8_t *)(ha->risc_fw[0].code + BOOTLD_START);
-	flashaddr = BOOTLD_START;
-
+	bp = (uint8_t *)(ha->risc_fw[0].code + flashaddr);
 	dp = (uint8_t *)&data;
 	for (i = 0; i < size; i++) {
 		for (n = 0; n < 8; n++) {
@@ -1572,7 +1594,10 @@
 			dp[n] = *bp++;
 		}
 		LITTLE_ENDIAN_64(&data);
-		(void) ql_8021_pci_mem_write_2M(ha, flashaddr, &data, 8);
+		if (ql_8021_pci_mem_write_2M(ha, flashaddr, &data, 8)) {
+			EL(ha, "qla_fc_8021_pci_mem_write_2M != 0\n");
+			return (-1);
+		}
 		flashaddr += 8;
 	}
 
@@ -1585,8 +1610,8 @@
 	EL(ha, "IMAGE_START size=%llx\n", size);
 	size = (size + 7) / 8;
 
-	bp = (uint8_t *)(ha->risc_fw[0].code + IMAGE_START);
-	flashaddr = IMAGE_START;
+	flashaddr = ha->flash_fw_addr << 2;
+	bp = (uint8_t *)(ha->risc_fw[0].code + flashaddr);
 
 	dp = (uint8_t *)&data;
 	for (i = 0; i < size; i++) {
@@ -1594,7 +1619,10 @@
 			dp[n] = *bp++;
 		}
 		LITTLE_ENDIAN_64(&data);
-		(void) ql_8021_pci_mem_write_2M(ha, flashaddr, &data, 8);
+		if (ql_8021_pci_mem_write_2M(ha, flashaddr, &data, 8)) {
+			EL(ha, "qla_fc_8021_pci_mem_write_2M != 0\n");
+			return (-1);
+		}
 		flashaddr += 8;
 	}
 
@@ -1646,8 +1674,9 @@
 	ADAPTER_STATE_LOCK(ha);
 	ha->flags |= INTERRUPTS_ENABLED;
 	ADAPTER_STATE_UNLOCK(ha);
-
-	(void) ql_stop_firmware(ha);
+	if (!(ha->task_daemon_flags & ISP_ABORT_NEEDED)) {
+		(void) ql_stop_firmware(ha);
+	}
 }
 
 static int
@@ -1665,9 +1694,45 @@
 	ql_8021_wr_32(ha, UNM_PEG_HALT_STATUS1, 0);
 	ql_8021_wr_32(ha, UNM_PEG_HALT_STATUS2, 0);
 
-	(void) ql_8021_pinit_from_rom(ha);
+	/*
+	 * This reset sequence is to provide a graceful shutdown of the
+	 * different hardware blocks prior to performing an ASIC Reset,
+	 * has to be done before writing 0xffffffff to ASIC_RESET.
+	 */
+	ql_8021_wr_32(ha, UNM_CRB_I2Q + 0x10, 0);
+	ql_8021_wr_32(ha, UNM_CRB_I2Q + 0x14, 0);
+	ql_8021_wr_32(ha, UNM_CRB_I2Q + 0x18, 0);
+	ql_8021_wr_32(ha, UNM_CRB_I2Q + 0x1c, 0);
+	ql_8021_wr_32(ha, UNM_CRB_I2Q + 0x20, 0);
+	ql_8021_wr_32(ha, UNM_CRB_I2Q + 0x24, 0);
+	ql_8021_wr_32(ha, UNM_CRB_NIU + 0x40, 0xff);
+	ql_8021_wr_32(ha, UNM_CRB_NIU + 0x70000, 0x0);
+	ql_8021_wr_32(ha, UNM_CRB_NIU + 0x80000, 0x0);
+	ql_8021_wr_32(ha, UNM_CRB_NIU + 0x90000, 0x0);
+	ql_8021_wr_32(ha, UNM_CRB_NIU + 0xa0000, 0x0);
+	ql_8021_wr_32(ha, UNM_CRB_NIU + 0xb0000, 0x0);
+	ql_8021_wr_32(ha, UNM_CRB_SRE + 0x1000, 0x28ff000c);
+	ql_8021_wr_32(ha, UNM_CRB_EPG + 0x1300, 0x1);
+	ql_8021_wr_32(ha, UNM_CRB_TIMER + 0x0, 0x0);
+	ql_8021_wr_32(ha, UNM_CRB_TIMER + 0x8, 0x0);
+	ql_8021_wr_32(ha, UNM_CRB_TIMER + 0x10, 0x0);
+	ql_8021_wr_32(ha, UNM_CRB_TIMER + 0x18, 0x0);
+	ql_8021_wr_32(ha, UNM_CRB_TIMER + 0x100, 0x0);
+	ql_8021_wr_32(ha, UNM_CRB_TIMER + 0x200, 0x0);
+	ql_8021_wr_32(ha, UNM_CRB_PEG_NET_0 + 0x3C, 0x1);
+	ql_8021_wr_32(ha, UNM_CRB_PEG_NET_1 + 0x3C, 0x1);
+	ql_8021_wr_32(ha, UNM_CRB_PEG_NET_2 + 0x3C, 0x1);
+	ql_8021_wr_32(ha, UNM_CRB_PEG_NET_3 + 0x3C, 0x1);
+	ql_8021_wr_32(ha, UNM_CRB_PEG_NET_4 + 0x3C, 0x1);
 	delay(1);
 
+	ret = ql_8021_pinit_from_rom(ha);
+	if (ret) {
+		EL(ha, "pinit_from_rom ret=%d\n", ret);
+		return (ret);
+	}
+	delay(1);
+
 	/* Bring QM and CAMRAM out of reset */
 	ql_8021_rd_32(ha, UNM_ROMUSB_GLB_SW_RESET, &rst);
 	rst &= ~((1 << 28) | (1 << 24));
@@ -1697,49 +1762,51 @@
 	return (ret);
 }
 
-int
-ql_8021_load_risc(ql_adapter_state_t *ha)
+static int
+ql_8021_load_fw(ql_adapter_state_t *ha)
 {
-	int		rv = 0;
-	static int	ql_8021_fw_loaded = 0;
+	int	rv = 0;
 
 	GLOBAL_HW_LOCK();
-	if (!ql_8021_fw_loaded) {
-		if (ha->risc_fw[0].code) {
-			EL(ha, "from driver\n");
-			rv = ql_8021_reset_hw(ha, 2);
-		} else {
-			/*
-			 * BIOS method
-			 * ql_8021_reset_hw(ha, 0)
-			 */
-			EL(ha, "from flash\n");
-			rv = ql_8021_reset_hw(ha, 1);
-		}
-		if (rv == 0) {
-			ql_8021_fw_loaded = 1;
+	if (ha->risc_fw[0].code) {
+		EL(ha, "from driver\n");
+		rv = ql_8021_reset_hw(ha, 2);
+	} else {
+		/*
+		 * BIOS method
+		 * ql_8021_reset_hw(ha, 0)
+		 */
+		EL(ha, "from flash\n");
+		rv = ql_8021_reset_hw(ha, 1);
+	}
+	if (rv == 0) {
+		ql_8021_wr_32(ha, CRB_DMA_SHIFT, 0x55555555);
+		ql_8021_wr_32(ha, UNM_PEG_HALT_STATUS1, 0x0);
+		ql_8021_wr_32(ha, UNM_PEG_HALT_STATUS2, 0x0);
 
-			ql_8021_wr_32(ha, CRB_DMA_SHIFT, 0x55555555);
-			ql_8021_wr_32(ha, UNM_PEG_HALT_STATUS1, 0x0);
-			ql_8021_wr_32(ha, UNM_PEG_HALT_STATUS2, 0x0);
+		GLOBAL_HW_UNLOCK();
 
-			GLOBAL_HW_UNLOCK();
+		ADAPTER_STATE_LOCK(ha);
+		ha->flags &= ~INTERRUPTS_ENABLED;
+		ADAPTER_STATE_UNLOCK(ha);
 
-			ADAPTER_STATE_LOCK(ha);
-			ha->flags &= ~INTERRUPTS_ENABLED;
-			ADAPTER_STATE_UNLOCK(ha);
+		/* clear the mailbox command pointer. */
+		INTR_LOCK(ha);
+		ha->mcp = NULL;
+		INTR_UNLOCK(ha);
 
-			(void) ql_8021_enable_intrs(ha);
+		MBX_REGISTER_LOCK(ha);
+		ha->mailbox_flags = (uint8_t)(ha->mailbox_flags &
+		    ~(MBX_BUSY_FLG | MBX_WANT_FLG | MBX_ABORT | MBX_INTERRUPT));
+		MBX_REGISTER_UNLOCK(ha);
 
-			ADAPTER_STATE_LOCK(ha);
-			ha->flags |= INTERRUPTS_ENABLED;
-			ADAPTER_STATE_UNLOCK(ha);
-		} else {
-			GLOBAL_HW_UNLOCK();
-		}
+		(void) ql_8021_enable_intrs(ha);
+
+		ADAPTER_STATE_LOCK(ha);
+		ha->flags |= INTERRUPTS_ENABLED;
+		ADAPTER_STATE_UNLOCK(ha);
 	} else {
 		GLOBAL_HW_UNLOCK();
-		EL(ha, "Firmware loaded by other function\n");
 	}
 
 	if (rv == 0) {
@@ -1750,10 +1817,9 @@
 		    ha->fw_minor_version, ha->fw_subminor_version);
 	} else {
 		EL(ha, "status = -1\n");
-		return (QL_FUNCTION_FAILED);
 	}
 
-	return (QL_SUCCESS);
+	return (rv);
 }
 
 void
@@ -1777,7 +1843,9 @@
 	GLOBAL_HW_LOCK();
 	ql_8021_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
 	GLOBAL_HW_UNLOCK();
-	(void) ql_toggle_interrupt(ha, 1);
+	if (!(ha->task_daemon_flags & ISP_ABORT_NEEDED)) {
+		(void) ql_toggle_interrupt(ha, 1);
+	}
 }
 
 void
@@ -1795,8 +1863,7 @@
 	struct legacy_intr_set	*nx_legacy_intr;
 
 	ha->qdr_sn_window = (uint32_t)-1;
-	ha->ddr_mn_window = (uint32_t)-1;
-	nx_legacy_intr = &legacy_intr[ha->function_number];
+	nx_legacy_intr = &legacy_intr[ha->pci_function_number];
 
 	ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
 	ha->nx_legacy_intr.tgt_status_reg = nx_legacy_intr->tgt_status_reg;
@@ -1815,9 +1882,9 @@
 
 	ql_8021_rd_32(ha, CRB_DRV_ACTIVE, &val);
 	if (val == 0xffffffff) {
-		val = (1 << (ha->function_number * 4));
+		val = (1 << (ha->pci_function_number * 4));
 	} else {
-		val |= (1 << (ha->function_number * 4));
+		val |= (1 << (ha->pci_function_number * 4));
 	}
 	ql_8021_wr_32(ha, CRB_DRV_ACTIVE, val);
 
@@ -1834,7 +1901,7 @@
 	}
 
 	ql_8021_rd_32(ha, CRB_DRV_ACTIVE, &val);
-	val &= ~(1 << (ha->function_number * 4));
+	val &= ~(1 << (ha->pci_function_number * 4));
 	ql_8021_wr_32(ha, CRB_DRV_ACTIVE, val);
 
 	ql_8021_hw_unlock(ha);
@@ -1843,55 +1910,117 @@
 static void
 ql_8021_need_reset_handler(ql_adapter_state_t *ha)
 {
-	uint32_t	drv_state, drv_active;
-	clock_t		timer;
+	uint32_t	drv_state, drv_active, cnt;
 
-	(void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT);
-
 	ql_8021_rd_32(ha, CRB_DRV_STATE, &drv_state);
-	drv_state |= (1 << (ha->function_number * 4));
+	if (drv_state == 0xffffffff) {
+		drv_state = 0;
+	}
+	if (!(ha->ql_dump_state & QL_DUMPING)) {
+		drv_state |= (1 << (ha->pci_function_number * 4));
+	}
 	ql_8021_wr_32(ha, CRB_DRV_STATE, drv_state);
 
-	ql_8021_rd_32(ha, CRB_DRV_ACTIVE, &drv_active);
-
-	ql_8021_hw_unlock(ha);
-
-	for (timer = 30; timer && drv_state != drv_active; timer--) {
+	for (cnt = 60; cnt; cnt--) {
+		ql_8021_hw_unlock(ha);
 		delay(100);
-
 		(void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT);
+
 		ql_8021_rd_32(ha, CRB_DRV_STATE, &drv_state);
 		ql_8021_rd_32(ha, CRB_DRV_ACTIVE, &drv_active);
-		ql_8021_hw_unlock(ha);
+		if (ha->ql_dump_state & QL_DUMPING) {
+			drv_state |= (1 << (ha->pci_function_number * 4));
+		}
+		if (drv_state == drv_active) {
+			if (ha->ql_dump_state & QL_DUMPING) {
+				ql_8021_wr_32(ha, CRB_DRV_STATE, drv_state);
+			}
+			break;
+		}
 	}
 }
 
-uint32_t
-ql_8021_idc_handler(ql_adapter_state_t *ha)
+int
+ql_8021_fw_reload(ql_adapter_state_t *ha)
 {
-	uint32_t	dev_state, drv_state, rval;
-	clock_t		timer;
+	int	rval;
+
+	(void) ql_stall_driver(ha, BIT_0);
+
+	(void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT);
+	ql_8021_wr_32(ha, CRB_DEV_STATE, NX_DEV_INITIALIZING);
+	ql_8021_hw_unlock(ha);
+
+	rval = ql_8021_load_fw(ha) == 0 ? NX_DEV_READY : NX_DEV_FAILED;
+
+	(void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT);
+	ql_8021_wr_32(ha, CRB_DEV_STATE, rval);
+	ql_8021_hw_unlock(ha);
+
+	TASK_DAEMON_LOCK(ha);
+	ha->task_daemon_flags &= ~(TASK_DAEMON_STALLED_FLG | DRIVER_STALL);
+	TASK_DAEMON_UNLOCK(ha);
+
+	if (rval != NX_DEV_READY) {
+		EL(ha, "status=%xh\n", QL_FUNCTION_FAILED);
+		return (QL_FUNCTION_FAILED);
+	}
+	return (QL_SUCCESS);
+}
+
+void
+ql_8021_idc_poll(ql_adapter_state_t *ha)
+{
+	uint32_t	new_state;
+
+	if (ha->ql_dump_state & QL_DUMPING) {
+		return;
+	}
+	new_state = ql_8021_check_fw_alive(ha);
+
+	if (new_state == NX_DEV_NEED_RESET &&
+	    !(ha->ql_dump_state & QL_DUMPING ||
+	    (ha->ql_dump_state & QL_DUMP_VALID &&
+	    !(ha->ql_dump_state & QL_DUMP_UPLOADED)))) {
+		(void) ql_dump_firmware(ha);
+	} else {
+		(void) ql_8021_idc_handler(ha, new_state);
+	}
+}
+
+int
+ql_8021_idc_handler(ql_adapter_state_t *ha, uint32_t new_state)
+{
+	int		rval;
+	uint32_t	dev_state, drv_state, loop;
 	ql_mbx_data_t	mr;
-	boolean_t	stalled = B_FALSE, lock = B_FALSE;
+	boolean_t	stalled = B_FALSE, reset_needed = B_FALSE;
+	boolean_t	force_load = B_FALSE;
 
-	/* wait for 30 seconds for device to go ready */
-	timer = 30;
-	while (timer) {
-		if (lock == B_FALSE) {
-			(void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT);
-			lock = B_TRUE;
+	(void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT);
+
+	/* wait for 180 seconds for device to go ready */
+	for (loop = 180; loop; loop--) {
+		if (new_state != NX_DEV_POLL) {
+			ql_8021_wr_32(ha, CRB_DEV_STATE, new_state);
+			dev_state = new_state;
+			new_state = NX_DEV_POLL;
+		} else {
+			ql_8021_rd_32(ha, CRB_DEV_STATE, &dev_state);
 		}
-		ql_8021_rd_32(ha, CRB_DEV_STATE, &dev_state);
 
 		switch (dev_state) {
 		case 0xffffffff:
 		case NX_DEV_COLD:
-			EL(ha, "dev_state=NX_DEV_COLD\n");
+			if (ha->dev_state != dev_state) {
+				EL(ha, "dev_state=NX_DEV_COLD\n");
+			}
 			rval = NX_DEV_COLD;
 			ql_8021_wr_32(ha, CRB_DEV_STATE, NX_DEV_INITIALIZING);
 			ql_8021_wr_32(ha, CRB_DRV_IDC_VERSION, NX_IDC_VERSION);
-			(void) ql_8021_hw_unlock(ha);
-			if (ql_get_fw_version(ha, &mr, 2) == QL_SUCCESS &&
+			ql_8021_hw_unlock(ha);
+			if (!force_load &&
+			    ql_get_fw_version(ha, &mr, 2) == QL_SUCCESS &&
 			    (mr.mb[1] | mr.mb[2] | mr.mb[3])) {
 				ql_8021_rd_32(ha, UNM_FW_VERSION_MAJOR,
 				    &ha->fw_major_version);
@@ -1900,72 +2029,1073 @@
 				ql_8021_rd_32(ha, UNM_FW_VERSION_SUB,
 				    &ha->fw_subminor_version);
 				rval = NX_DEV_READY;
-			} else if (ql_8021_load_risc(ha) == QL_SUCCESS) {
-				rval = NX_DEV_READY;
+			} else {
+				if (!stalled) {
+					TASK_DAEMON_LOCK(ha);
+					ha->task_daemon_flags |=
+					    TASK_DAEMON_STALLED_FLG;
+					TASK_DAEMON_UNLOCK(ha);
+					ql_abort_queues(ha);
+					stalled = B_TRUE;
+				}
+				if (ha->ql_dump_state & QL_DUMPING) {
+					(void) ql_8021_get_fw_dump(ha);
+				}
+				rval = ql_8021_load_fw(ha) == 0 ?
+				    NX_DEV_READY : NX_DEV_FAILED;
 			}
 			(void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT);
 			ql_8021_wr_32(ha, CRB_DEV_STATE, rval);
 			break;
 		case NX_DEV_READY:
+			if (ha->dev_state != dev_state) {
+				EL(ha, "dev_state=NX_DEV_READY\n");
+			}
 			rval = NX_DEV_READY;
-			timer = 0;
+			loop = 1;
 			break;
 		case NX_DEV_FAILED:
-			EL(ha, "dev_state=NX_DEV_FAILED\n");
+			if (ha->dev_state != dev_state) {
+				EL(ha, "dev_state=NX_DEV_FAILED\n");
+			}
 			rval = NX_DEV_FAILED;
-			timer = 0;
+			loop = 1;
 			break;
-
 		case NX_DEV_NEED_RESET:
-			EL(ha, "dev_state=NX_DEV_NEED_RESET\n");
+			if (ha->dev_state != dev_state) {
+				EL(ha, "dev_state=NX_DEV_NEED_RESET\n");
+			}
 			rval = NX_DEV_NEED_RESET;
-			(void) ql_8021_hw_unlock(ha);
-			lock = B_FALSE;
-			if (ql_stall_driver(ha, 0) == QL_SUCCESS) {
-				stalled = B_TRUE;
-				ql_8021_need_reset_handler(ha);
+			ql_8021_need_reset_handler(ha);
+			/*
+			 * Force to DEV_COLD unless someone else is starting
+			 * a reset
+			 */
+			ql_8021_rd_32(ha, CRB_DEV_STATE, &dev_state);
+			if (dev_state == NX_DEV_NEED_RESET) {
+				EL(ha, "HW State: COLD/RE-INIT\n");
+				ql_8021_wr_32(ha, CRB_DEV_STATE, NX_DEV_COLD);
+				force_load = B_TRUE;
 			}
+			reset_needed = B_TRUE;
 			break;
-
 		case NX_DEV_NEED_QUIESCENT:
-			EL(ha, "dev_state=NX_DEV_NEED_QUIESCENT\n");
-			(void) ql_8021_hw_unlock(ha);
-			lock = B_FALSE;
-			rval = ql_stall_driver(ha, 0);
-			if (rval == QL_SUCCESS) {
+			if (ha->dev_state != dev_state) {
+				EL(ha, "dev_state=NX_DEV_NEED_QUIESCENT\n");
+			}
+			ql_8021_rd_32(ha, CRB_DRV_STATE, &drv_state);
+			drv_state |= (2 << (ha->pci_function_number * 4));
+			ql_8021_wr_32(ha, CRB_DRV_STATE, drv_state);
+			ql_8021_hw_unlock(ha);
+			if (!stalled) {
+				TASK_DAEMON_LOCK(ha);
+				ha->task_daemon_flags |=
+				    TASK_DAEMON_STALLED_FLG;
+				TASK_DAEMON_UNLOCK(ha);
+				(void) ql_stall_driver(ha, BIT_0);
 				stalled = B_TRUE;
-				(void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT);
-				lock = B_TRUE;
-				ql_8021_rd_32(ha, CRB_DRV_STATE, &drv_state);
-				drv_state |=
-				    (2 << (ha->function_number * 4));
-				ql_8021_wr_32(ha, CRB_DRV_STATE, drv_state);
 			}
+			(void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT);
 			break;
-
 		case NX_DEV_INITIALIZING:
-			EL(ha, "dev_state=NX_DEV_INITIALIZING\n");
+			if (ha->dev_state != dev_state) {
+				EL(ha, "dev_state=NX_DEV_INITIALIZING\n");
+			}
+			ql_8021_hw_unlock(ha);
+			if (!stalled) {
+				TASK_DAEMON_LOCK(ha);
+				ha->task_daemon_flags |=
+				    TASK_DAEMON_STALLED_FLG;
+				TASK_DAEMON_UNLOCK(ha);
+				ql_awaken_task_daemon(ha, NULL,
+				    DRIVER_STALL, 0);
+				stalled = B_TRUE;
+				ql_requeue_all_cmds(ha);
+				ADAPTER_STATE_LOCK(ha);
+				ha->flags &= ~INTERRUPTS_ENABLED;
+				ADAPTER_STATE_UNLOCK(ha);
+			}
+			delay(100);
+			(void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT);
+			reset_needed = B_TRUE;
 			break;
 		case NX_DEV_QUIESCENT:
-			EL(ha, "dev_state=NX_DEV_QUIESCENT\n");
+			if (ha->dev_state != dev_state) {
+				EL(ha, "dev_state=NX_DEV_QUIESCENT\n");
+			}
+			ql_8021_hw_unlock(ha);
+			delay(100);
+			(void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT);
 			break;
 		default:
-			EL(ha, "dev_state=%x, default\n", dev_state);
+			if (ha->dev_state != dev_state) {
+				EL(ha, "dev_state=%x, default\n", dev_state);
+			}
+			ql_8021_hw_unlock(ha);
+			delay(100);
+			(void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT);
 			break;
 		}
-		if (lock == B_TRUE) {
-			(void) ql_8021_hw_unlock(ha);
-			lock = B_FALSE;
+		ha->dev_state = dev_state;
+	}
+
+	/* Clear reset ready and quiescent flags. */
+	ql_8021_rd_32(ha, CRB_DRV_STATE, &drv_state);
+	drv_state &= ~(1 << (ha->pci_function_number * 4));
+	drv_state &= ~(2 << (ha->pci_function_number * 4));
+	ql_8021_wr_32(ha, CRB_DRV_STATE, drv_state);
+
+	ql_8021_hw_unlock(ha);
+	if (reset_needed && ha->flags & ONLINE &&
+	    !(ha->task_daemon_flags & ABORT_ISP_ACTIVE)) {
+		delay(100);
+		ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED, 0);
+	}
+	if (stalled) {
+		TASK_DAEMON_LOCK(ha);
+		ha->task_daemon_flags &= ~TASK_DAEMON_STALLED_FLG;
+		TASK_DAEMON_UNLOCK(ha);
+		ql_restart_driver(ha);
+	}
+	return (rval);
+}
+
+void
+ql_8021_wr_req_in(ql_adapter_state_t *ha, uint32_t index)
+{
+	index = index << 16 | ha->pci_function_number << 5 | 4;
+
+	if (NX_IS_REVISION_P3PLUS_B0(ha->rev_id)) {
+		uint64_t	addr;
+
+		addr = ha->function_number ? (uint64_t)CRB_PORT_1_REQIN :
+		    (uint64_t)CRB_PORT_0_REQIN;
+		ql_8021_wr_32(ha, addr, index);
+	} else {
+		do {
+			ddi_put32(ha->db_dev_handle, ha->nx_req_in, index);
+		} while (RD_REG_DWORD(ha, ha->db_read) != index);
+	}
+}
+
+/* Called every 2 seconds */
+static uint32_t
+ql_8021_check_fw_alive(ql_adapter_state_t *ha)
+{
+	uint32_t	dev_state, fw_heartbeat_counter, cnt, data[7];
+	uint32_t	new_state = NX_DEV_POLL;
+
+	ql_8021_rd_32(ha, CRB_DEV_STATE, &dev_state);
+	if (dev_state != NX_DEV_READY) {
+		return (new_state);
+	}
+
+	ql_8021_rd_32(ha, UNM_PEG_ALIVE_COUNTER, &fw_heartbeat_counter);
+
+	if (ha->fw_heartbeat_counter == fw_heartbeat_counter) {
+		ha->seconds_since_last_heartbeat++;
+		/* FW not alive after 6 seconds */
+		if (ha->seconds_since_last_heartbeat == 3) {
+			ha->seconds_since_last_heartbeat = 0;
+			/* FW not alive after 5 milliseconds */
+			for (cnt = 5; cnt; cnt--) {
+				ql_8021_rd_32(ha, UNM_PEG_ALIVE_COUNTER,
+				    &fw_heartbeat_counter);
+				if (ha->fw_heartbeat_counter !=
+				    fw_heartbeat_counter) {
+					break;
+				}
+				drv_usecwait(1000);
+			}
+			if (ha->fw_heartbeat_counter == fw_heartbeat_counter) {
+				EL(ha, "nx_dev_need_reset\n");
+				ql_8021_rd_32(ha, UNM_PEG_HALT_STATUS1,
+				    &data[0]);
+				ql_8021_rd_32(ha, UNM_PEG_HALT_STATUS2,
+				    &data[1]);
+				ql_8021_rd_32(ha, UNM_CRB_PEG_NET_0 + 0x3C,
+				    &data[2]);
+				ql_8021_rd_32(ha, UNM_CRB_PEG_NET_1 + 0x3C,
+				    &data[3]);
+				ql_8021_rd_32(ha, UNM_CRB_PEG_NET_2 + 0x3C,
+				    &data[4]);
+				ql_8021_rd_32(ha, UNM_CRB_PEG_NET_3 + 0x3C,
+				    &data[5]);
+				ql_8021_rd_32(ha, UNM_CRB_PEG_NET_4 + 0x3C,
+				    &data[6]);
+				EL(ha, "halt_status1=%xh, halt_status2=%xh,\n"
+				    "peg_pc0=%xh, peg_pc1=%xh, peg_pc2=%xh, "
+				    "peg_pc3=%xh, peg_pc4=%xh\n", data[0],
+				    data[1], data[2], data[3], data[4],
+				    data[5], data[6]);
+				new_state = NX_DEV_NEED_RESET;
+			}
 		}
+	} else {
+		ha->seconds_since_last_heartbeat = 0;
+	}
 
-		if (timer) {
-			delay(100);
-			timer--;
+	ha->fw_heartbeat_counter = fw_heartbeat_counter;
+	return (new_state);
+}
+
+int
+ql_8021_reset_fw(ql_adapter_state_t *ha)
+{
+	return (ql_8021_idc_handler(ha, NX_DEV_NEED_RESET));
+}
+
+int
+ql_8021_fw_chk(ql_adapter_state_t *ha)
+{
+	uint32_t	dev_state, new_state = NX_DEV_POLL;
+	int		rval;
+	ql_mbx_data_t	mr;
+
+	ql_8021_rd_32(ha, CRB_DEV_STATE, &dev_state);
+	switch (dev_state) {
+	case 0xffffffff:
+	case NX_DEV_COLD:
+	case NX_DEV_NEED_RESET:
+	case NX_DEV_NEED_QUIESCENT:
+	case NX_DEV_INITIALIZING:
+	case NX_DEV_QUIESCENT:
+	case NX_DEV_BADOBADO:
+		break;
+	case NX_DEV_READY:
+		if (ql_get_fw_version(ha, &mr, 2) != QL_SUCCESS ||
+		    (mr.mb[1] | mr.mb[2] | mr.mb[3]) == 0) {
+			EL(ha, "version check needs reset\n", dev_state);
+			new_state = NX_DEV_NEED_RESET;
 		}
+		break;
+	case NX_DEV_FAILED:
+		EL(ha, "device needs reset\n");
+		new_state = NX_DEV_NEED_RESET;
+		break;
+	default:
+		EL(ha, "state=%xh needs reset\n", dev_state);
+		new_state = NX_DEV_COLD;
+		break;
 	}
 
-	if (stalled) {
-		ql_restart_driver(ha);
+	/* Test for firmware running. */
+	rval = ql_8021_idc_handler(ha, new_state) == NX_DEV_READY ?
+	    QL_SUCCESS : QL_FUNCTION_FAILED;
+
+	return (rval);
+}
+
+/* ****************************************************************** */
+/* ***************** NetXen MiniDump Functions ********************** */
+/* ****************************************************************** */
+
+/*
+ * ql_8021_get_fw_dump
+ *
+ * Input:
+ *	pi:	FC port info pointer.
+ *
+ * Returns:
+ *	qla driver local function return status codes
+ *
+ * Context:
+ *	Interrupt or Kernel context, no mailbox commands allowed.
+ */
+static int
+ql_8021_get_fw_dump(ql_adapter_state_t *ha)
+{
+	uint32_t	tsize, cnt, *dp, *bp;
+
+	QL_PRINT_10(ha, "started\n");
+
+	tsize = ha->dmp_template.size;
+	cnt = (uint32_t)(tsize / sizeof (uint32_t));
+	dp = (uint32_t *)ha->ql_dump_ptr;
+	bp = (uint32_t *)ha->dmp_template.bp;
+	while (cnt--) {
+		*dp++ = ddi_get32(ha->dmp_template.acc_handle, bp++);
 	}
+	ql_8021_md_parse_template(ha, ha->ql_dump_ptr, (caddr_t)dp,
+	    ha->md_capture_size - tsize, ha->md_capture_mask);
+
+#ifdef _BIG_ENDIAN
+	cnt = (uint32_t)(ha->ql_dump_size / sizeof (uint32_t));
+	dp = (uint32_t *)ha->ql_dump_ptr;
+	while (cnt--) {
+		ql_chg_endian((uint8_t *)dp, 4);
+		dp++;
+	}
+#endif
+	QL_PRINT_10(ha, "done\n");
+	return (QL_SUCCESS);
+}
+
+/*
+ * ql_8021_get_md_template
+ *	Get mini-dump template
+ *
+ * Input:
+ *	ha:	adapter state pointer.
+ *
+ * Returns:
+ *	ql local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+ql_8021_get_md_template(ql_adapter_state_t *ha)
+{
+	ql_mbx_data_t	mr;
+	uint32_t	tsize, chksum;
+	int		rval;
+
+	rval = ql_get_md_template(ha, NULL, &mr, 0, GTO_TEMPLATE_SIZE);
+	if (rval != QL_SUCCESS ||
+	    (tsize = SHORT_TO_LONG(mr.mb[2], mr.mb[3])) == 0) {
+		EL(ha, "size=%xh status=%xh\n", tsize, rval);
+		ha->md_capture_size = 0;
+		ql_free_phys(ha, &ha->dmp_template);
+		return (rval);
+	}
+	if (ha->dmp_template.dma_handle && ha->dmp_template.size != tsize) {
+		ql_free_phys(ha, &ha->dmp_template);
+	}
+	ha->md_capture_mask = 0x1f;
+	ha->md_capture_size = SHORT_TO_LONG(mr.mb[4], mr.mb[5]) +
+	    SHORT_TO_LONG(mr.mb[6], mr.mb[7]) +
+	    SHORT_TO_LONG(mr.mb[8], mr.mb[9]) +
+	    SHORT_TO_LONG(mr.mb[10], mr.mb[11]) + tsize;
+	/*
+	 * Determine ascii dump file size
+	 * 2 ascii bytes per binary byte + a space and
+	 * a newline every 16 binary bytes
+	 */
+	ha->risc_dump_size = ha->md_capture_size << 1;
+	ha->risc_dump_size += ha->md_capture_size;
+	ha->risc_dump_size += ha->md_capture_size / 16 + 1;
+
+	/* Allocate template buffer. */
+	if (ha->dmp_template.dma_handle == NULL) {
+		rval = ql_get_dma_mem(ha, &ha->dmp_template, tsize,
+		    LITTLE_ENDIAN_DMA, QL_DMA_RING_ALIGN);
+		if (rval != QL_SUCCESS) {
+			EL(ha, "unable to allocate template buffer, "
+			    "status=%xh\n", rval);
+			ha->md_capture_size = 0;
+			ql_free_phys(ha, &ha->dmp_template);
+			return (rval);
+		}
+	}
+	rval = ql_get_md_template(ha, &ha->dmp_template, &mr, 0, GTO_TEMPLATE);
+	if (rval != QL_SUCCESS ||
+	    (chksum = ql_8021_md_template_checksum(ha))) {
+		EL(ha, "status=%xh, chksum=%xh\n", rval, chksum);
+		if (rval == QL_SUCCESS) {
+			rval = QL_FUNCTION_FAILED;
+		}
+		ql_free_phys(ha, &ha->dmp_template);
+		ha->md_capture_size = 0;
+	}
+
 	return (rval);
+}
+
+static void
+ql_8021_md_parse_template(ql_adapter_state_t *ha, caddr_t template_buff,
+    caddr_t dump_buff, uint32_t buff_size, uint32_t capture_mask)
+{
+	int			e_cnt, buff_level, esize;
+	uint32_t		num_of_entries;
+	time_t			time;
+	caddr_t			dbuff;
+	int			sane_start = 0, sane_end = 0;
+	md_template_hdr_t	*template_hdr;
+	md_entry_t		*entry;
+
+	if ((capture_mask & 0x3) != 0x3) {
+		EL(ha, "capture mask %02xh below minimum needed for valid "
+		    "dump\n", capture_mask);
+		return;
+	}
+	/* Setup parameters */
+	template_hdr = (md_template_hdr_t *)template_buff;
+	if (template_hdr->entry_type == TLHDR) {
+		sane_start = 1;
+	}
+	(void) drv_getparm(TIME, &time);
+	template_hdr->driver_timestamp = LSD(time);
+	template_hdr->driver_capture_mask = capture_mask;
+	num_of_entries = template_hdr->num_of_entries;
+	entry = (md_entry_t *)((caddr_t)template_buff +
+	    template_hdr->first_entry_offset);
+	for (buff_level = 0, e_cnt = 0; e_cnt < num_of_entries; e_cnt++) {
+		/*
+		 * If the capture_mask of the entry does not match capture mask
+		 * skip the entry after marking the driver_flags indicator.
+		 */
+		if (!(entry->h.a.ecw.entry_capture_mask & capture_mask)) {
+			entry->h.a.ecw.driver_flags = (uint8_t)
+			    (entry->h.a.ecw.driver_flags |
+			    QL_DBG_SKIPPED_FLAG);
+			entry = (md_entry_t *)((char *)entry +
+			    entry->h.entry_size);
+			continue;
+		}
+		/*
+		 * This is ONLY needed in implementations where
+		 * the capture buffer allocated is too small to capture
+		 * all of the required entries for a given capture mask.
+		 * We need to empty the buffer contents to a file
+		 * if possible, before processing the next entry
+		 * If the buff_full_flag is set, no further capture will
+		 * happen and all remaining non-control entries will be
+		 * skipped.
+		 */
+		if (entry->h.entry_capture_size != 0) {
+			if ((buff_level + entry->h.entry_capture_size) >
+			    buff_size) {
+				entry = (md_entry_t *)((char *)entry +
+				    entry->h.entry_size);
+				continue;
+			}
+		}
+		/*
+		 * Decode the entry type and process it accordingly
+		 */
+		switch (entry->h.entry_type) {
+		case RDNOP:
+			break;
+		case RDEND:
+			sane_end += 1;
+			break;
+		case RDCRB:
+			dbuff = dump_buff + buff_level;
+			esize = ql_8021_md_rdcrb(ha, (void *)entry,
+			    (void *)dbuff);
+			ql_8021_md_entry_err_chk(ha, entry, esize, e_cnt);
+			buff_level += esize;
+			break;
+		case L2ITG:
+		case L2DTG:
+		case L2DAT:
+		case L2INS:
+			dbuff = dump_buff + buff_level;
+			esize = ql_8021_md_L2Cache(ha, (void *)entry,
+			    (void *)dbuff);
+			if (esize == -1) {
+				entry->h.a.ecw.driver_flags = (uint8_t)
+				    (entry->h.a.ecw.driver_flags |
+				    QL_DBG_SKIPPED_FLAG);
+			} else {
+				ql_8021_md_entry_err_chk(ha, entry, esize,
+				    e_cnt);
+				buff_level += esize;
+			}
+			break;
+		case L1DAT:
+		case L1INS:
+			dbuff = dump_buff + buff_level;
+			esize = ql_8021_md_L1Cache(ha, (void *)entry,
+			    (void *)dbuff);
+			ql_8021_md_entry_err_chk(ha, entry, esize, e_cnt);
+			buff_level += esize;
+			break;
+		case RDOCM:
+			dbuff = dump_buff + buff_level;
+			esize = ql_8021_md_rdocm(ha, (void *)entry,
+			    (void *)dbuff);
+			ql_8021_md_entry_err_chk(ha, entry, esize, e_cnt);
+			buff_level += esize;
+			break;
+		case RDMEM:
+			dbuff = dump_buff + buff_level;
+			esize = ql_8021_md_rdmem(ha, (void *)entry,
+			    (void *)dbuff);
+			ql_8021_md_entry_err_chk(ha, entry, esize, e_cnt);
+			buff_level += esize;
+			break;
+		case BOARD:
+		case RDROM:
+			dbuff = dump_buff + buff_level;
+			esize = ql_8021_md_rdrom(ha, (void *)entry,
+			    (void *)dbuff);
+			ql_8021_md_entry_err_chk(ha, entry, esize, e_cnt);
+			buff_level += esize;
+			break;
+		case RDMUX:
+			dbuff = dump_buff + buff_level;
+			esize = ql_8021_md_rdmux(ha, (void *)entry,
+			    (void *)dbuff);
+			ql_8021_md_entry_err_chk(ha, entry, esize, e_cnt);
+			buff_level += esize;
+			break;
+		case QUEUE:
+			dbuff = dump_buff + buff_level;
+			esize = ql_8021_md_rdqueue(ha, (void *)entry,
+			    (void *)dbuff);
+			ql_8021_md_entry_err_chk(ha, entry, esize, e_cnt);
+			buff_level += esize;
+			break;
+		case CNTRL:
+			if (ql_8021_md_cntrl(ha, template_hdr,
+			    (void *)entry)) {
+				entry->h.a.ecw.driver_flags = (uint8_t)
+				    (entry->h.a.ecw.driver_flags |
+				    QL_DBG_SKIPPED_FLAG);
+				EL(ha, "Entry ID=%d, entry_type=%d non zero "
+				    "status\n", e_cnt, entry->h.entry_type);
+			}
+			break;
+		default:
+			entry->h.a.ecw.driver_flags = (uint8_t)
+			    (entry->h.a.ecw.driver_flags |
+			    QL_DBG_SKIPPED_FLAG);
+			EL(ha, "Entry ID=%d, entry_type=%d unknown\n", e_cnt,
+			    entry->h.entry_type);
+			break;
+		}
+		/* next entry in the template */
+		entry = (md_entry_t *)((caddr_t)entry + entry->h.entry_size);
+	}
+	if (!sane_start || (sane_end > 1)) {
+		EL(ha, "Template configuration error. Check Template\n");
+	}
+	QL_PRINT_10(ha, "Minidump num of entries=%d\n",
+	    template_hdr->num_of_entries);
+}
+
+/*
+ * Read CRB operation.
+ */
+static int
+ql_8021_md_rdcrb(ql_adapter_state_t *ha, md_entry_rdcrb_t *crbEntry,
+    uint32_t *data_buff)
+{
+	uint32_t	loop_cnt, op_count, addr, stride, value;
+	int		i;
+
+	addr = crbEntry->addr;
+	op_count = crbEntry->op_count;
+	stride = crbEntry->a.ac.addr_stride;
+
+	for (loop_cnt = 0; loop_cnt < op_count; loop_cnt++) {
+		value = ql_8021_read_reg(ha, addr);
+		*data_buff++ = addr;
+		*data_buff++ = value;
+		addr = addr + stride;
+	}
+
+	/*
+	 * for testing purpose we return amount of data written
+	 */
+	i = (int)(loop_cnt * (2 * sizeof (uint32_t)));
+
+	return (i);
+}
+
+/*
+ * Handle L2 Cache.
+ */
+static int
+ql_8021_md_L2Cache(ql_adapter_state_t *ha, md_entry_cache_t *cacheEntry,
+    uint32_t *data_buff)
+{
+	int			i, k, tflag;
+	uint32_t		read_value, loop_cnt, read_cnt;
+	uint32_t		addr, read_addr, cntrl_addr, tag_reg_addr;
+	uint32_t		cntl_value_w, tag_value, tag_value_stride;
+	volatile uint8_t	cntl_value_r;
+	clock_t			timeout, elapsed;
+
+	read_addr = cacheEntry->read_addr;
+	loop_cnt = cacheEntry->op_count;
+	cntrl_addr = cacheEntry->control_addr;
+	cntl_value_w = CHAR_TO_SHORT(cacheEntry->b.cv.write_value[0],
+	    cacheEntry->b.cv.write_value[1]);
+	tag_reg_addr = cacheEntry->tag_reg_addr;
+	tag_value = CHAR_TO_SHORT(cacheEntry->a.sac.init_tag_value[0],
+	    cacheEntry->a.sac.init_tag_value[1]);
+	tag_value_stride = CHAR_TO_SHORT(cacheEntry->a.sac.tag_value_stride[0],
+	    cacheEntry->a.sac.tag_value_stride[1]);
+	read_cnt = cacheEntry->c.rac.read_addr_cnt;
+
+	for (i = 0; i < loop_cnt; i++) {
+		ql_8021_write_reg(ha, tag_value, tag_reg_addr);
+		if (cntl_value_w) {
+			ql_8021_write_reg(ha, cntl_value_w, cntrl_addr);
+		}
+		if (cacheEntry->b.cv.poll_wait) {
+			(void) drv_getparm(LBOLT, &timeout);
+			timeout += drv_usectohz(cacheEntry->b.cv.poll_wait *
+			    1000) + 1;
+			cntl_value_r = (uint8_t)ql_8021_read_reg(ha,
+			    cntrl_addr);
+			tflag = 0;
+			while (!tflag && ((cntl_value_r &
+			    cacheEntry->b.cv.poll_mask) != 0)) {
+				(void) drv_getparm(LBOLT, &elapsed);
+				if (elapsed > timeout) {
+					tflag = 1;
+				}
+				cntl_value_r = (uint8_t)ql_8021_read_reg(ha,
+				    cntrl_addr);
+			}
+			if (tflag) {
+				/*
+				 *  Report timeout error.  core dump capture
+				 *  failed
+				 *  Skip remaining entries. Write buffer out
+				 *  to file
+				 *  Use driver specific fields in template
+				 *  header
+				 *  to report this error.
+				 */
+				EL(ha, "timeout\n");
+				return (-1);
+			}
+		}
+		addr = read_addr;
+		for (k = 0; k < read_cnt; k++) {
+			read_value = ql_8021_read_reg(ha, addr);
+			*data_buff++ = read_value;
+			addr += cacheEntry->c.rac.read_addr_stride;
+		}
+		tag_value += tag_value_stride;
+	}
+	i = (int)(read_cnt * loop_cnt * sizeof (uint32_t));
+
+	return (i);
+}
+
+/*
+ * Handle L1 Cache.
+ */
+static int
+ql_8021_md_L1Cache(ql_adapter_state_t *ha, md_entry_cache_t *cacheEntry,
+    uint32_t *data_buff)
+{
+	int			i, k;
+	uint32_t		read_value, tag_value, tag_value_stride;
+	uint32_t		read_cnt, loop_cnt;
+	uint32_t		addr, read_addr, cntrl_addr, tag_reg_addr;
+	volatile uint32_t	cntl_value_w;
+
+	read_addr = cacheEntry->read_addr;
+	loop_cnt = cacheEntry->op_count;
+	cntrl_addr = cacheEntry->control_addr;
+	cntl_value_w = CHAR_TO_SHORT(cacheEntry->b.cv.write_value[0],
+	    cacheEntry->b.cv.write_value[1]);
+	tag_reg_addr = cacheEntry->tag_reg_addr;
+	tag_value = CHAR_TO_SHORT(cacheEntry->a.sac.init_tag_value[0],
+	    cacheEntry->a.sac.init_tag_value[1]);
+	tag_value_stride = CHAR_TO_SHORT(cacheEntry->a.sac.tag_value_stride[0],
+	    cacheEntry->a.sac.tag_value_stride[1]);
+	read_cnt = cacheEntry->c.rac.read_addr_cnt;
+
+	for (i = 0; i < loop_cnt; i++) {
+		ql_8021_write_reg(ha, tag_value, tag_reg_addr);
+		ql_8021_write_reg(ha, cntl_value_w, cntrl_addr);
+		addr = read_addr;
+		for (k = 0; k < read_cnt; k++) {
+			read_value = ql_8021_read_reg(ha, addr);
+			*data_buff++ = read_value;
+			addr += cacheEntry->c.rac.read_addr_stride;
+		}
+		tag_value += tag_value_stride;
+	}
+	i = (int)(read_cnt * loop_cnt * sizeof (uint32_t));
+
+	return (i);
+}
+
+/*
+ * Reading OCM memory
+ */
+static int
+ql_8021_md_rdocm(ql_adapter_state_t *ha, md_entry_rdocm_t *ocmEntry,
+    uint32_t *data_buff)
+{
+	int		i;
+	uint32_t	addr, value, loop_cnt;
+
+	addr = ocmEntry->read_addr;
+	loop_cnt = ocmEntry->op_count;
+
+	for (i = 0; i < loop_cnt; i++) {
+		value = ql_8021_read_ocm(ha, addr);
+		*data_buff++ = value;
+		addr += ocmEntry->read_addr_stride;
+	}
+	i = (int)(loop_cnt * sizeof (value));
+
+	return (i);
+}
+
+/*
+ * Read memory
+ */
+static int
+ql_8021_md_rdmem(ql_adapter_state_t *ha, md_entry_rdmem_t *memEntry,
+    uint32_t *data_buff)
+{
+	int		i, k;
+	uint32_t	addr, value, loop_cnt;
+
+	addr = memEntry->read_addr;
+	loop_cnt = (uint32_t)(memEntry->read_data_size /
+	    (sizeof (uint32_t) * 4));		/* size in bytes / 16 */
+
+	ql_8021_write_reg(ha, 0, MD_MIU_TEST_AGT_ADDR_HI);
+	for (i = 0; i < loop_cnt; i++) {
+		/*
+		 * Write address
+		 */
+		ql_8021_write_reg(ha, addr, MD_MIU_TEST_AGT_ADDR_LO);
+		ql_8021_write_reg(ha, MD_TA_CTL_ENABLE,
+		    MD_MIU_TEST_AGT_CTRL);
+		ql_8021_write_reg(ha, (MD_TA_CTL_START | MD_TA_CTL_ENABLE),
+		    MD_MIU_TEST_AGT_CTRL);
+		/*
+		 * Check busy bit.
+		 */
+		for (k = 0; k < MD_TA_CTL_CHECK; k++) {
+			value = ql_8021_read_reg(ha, MD_MIU_TEST_AGT_CTRL);
+			if ((value & MD_TA_CTL_BUSY) == 0) {
+				break;
+			}
+		}
+		if (k == MD_TA_CTL_CHECK) {
+			i = (int)((uint_t)i * (sizeof (uint32_t) * 4));
+			EL(ha, "failed to read=xh\n", i);
+			return (i);
+		}
+		/*
+		 * Read data
+		 */
+		value = ql_8021_read_reg(ha, MD_MIU_TEST_AGT_RDDATA_0_31);
+		*data_buff++ = value;
+		value = ql_8021_read_reg(ha, MD_MIU_TEST_AGT_RDDATA_32_63);
+		*data_buff++ = value;
+		value = ql_8021_read_reg(ha, MD_MIU_TEST_AGT_RDDATA_64_95);
+		*data_buff++ = value;
+		value = ql_8021_read_reg(ha, MD_MIU_TEST_AGT_RDDATA_96_127);
+		*data_buff++ = value;
+		/*
+		 *  next address to read
+		 */
+		addr = (uint32_t)(addr + (sizeof (uint32_t) * 4));
+	}
+	i = (int)(loop_cnt * (sizeof (uint32_t) * 4));
+
+	return (i);
+}
+
+/*
+ * Read Rom
+ */
+static int
+ql_8021_md_rdrom(ql_adapter_state_t *ha, md_entry_rdrom_t *romEntry,
+    uint32_t *data_buff)
+{
+	int		i;
+	uint32_t	addr, waddr, raddr, value, loop_cnt;
+
+	addr = romEntry->read_addr;
+	loop_cnt = romEntry->read_data_size;	/* This is size in bytes */
+	loop_cnt = (uint32_t)(loop_cnt / sizeof (value));
+
+	for (i = 0; i < loop_cnt; i++) {
+		waddr = addr & 0xFFFF0000;
+		(void) ql_8021_rom_lock(ha);
+		ql_8021_write_reg(ha, waddr, MD_DIRECT_ROM_WINDOW);
+		raddr = MD_DIRECT_ROM_READ_BASE + (addr & 0x0000FFFF);
+		value = ql_8021_read_reg(ha, raddr);
+		ql_8021_rom_unlock(ha);
+		*data_buff++ = value;
+		addr = (uint32_t)(addr + sizeof (value));
+	}
+	i = (int)(loop_cnt * sizeof (value));
+
+	return (i);
+}
+
+/*
+ * Read MUX data
+ */
+static int
+ql_8021_md_rdmux(ql_adapter_state_t *ha, md_entry_mux_t *muxEntry,
+    uint32_t *data_buff)
+{
+	uint32_t	read_value, sel_value, loop_cnt;
+	uint32_t	read_addr, select_addr;
+	int		i;
+
+	select_addr = muxEntry->select_addr;
+	sel_value = muxEntry->select_value;
+	read_addr = muxEntry->read_addr;
+
+	for (loop_cnt = 0; loop_cnt < muxEntry->op_count; loop_cnt++) {
+		ql_8021_write_reg(ha, sel_value, select_addr);
+		read_value = ql_8021_read_reg(ha, read_addr);
+		*data_buff++ = sel_value;
+		*data_buff++ = read_value;
+		sel_value += muxEntry->select_value_stride;
+	}
+	i = (int)(loop_cnt * (2 * sizeof (uint32_t)));
+
+	return (i);
+}
+
+/*
+ * Handling Queue State Reads.
+ */
+static int
+ql_8021_md_rdqueue(ql_adapter_state_t *ha, md_entry_queue_t *queueEntry,
+    uint32_t *data_buff)
+{
+	int		k;
+	uint32_t	read_value, read_addr, read_stride, select_addr;
+	uint32_t	queue_id, loop_cnt, read_cnt;
+
+	read_cnt = queueEntry->b.rac.read_addr_cnt;
+	read_stride = queueEntry->b.rac.read_addr_stride;
+	select_addr = queueEntry->select_addr;
+
+	for (loop_cnt = 0, queue_id = 0; loop_cnt < queueEntry->op_count;
+	    loop_cnt++) {
+		ql_8021_write_reg(ha, queue_id, select_addr);
+		read_addr = queueEntry->read_addr;
+		for (k = 0; k < read_cnt; k++) {
+			read_value = ql_8021_read_reg(ha, read_addr);
+			*data_buff++ = read_value;
+			read_addr += read_stride;
+		}
+		queue_id += CHAR_TO_SHORT(queueEntry->a.sac.queue_id_stride[0],
+		    queueEntry->a.sac.queue_id_stride[1]);
+	}
+	k = (int)(loop_cnt * (read_cnt * sizeof (uint32_t)));
+
+	return (k);
+}
+
+/*
+ * Handling control entries.
+ */
+static int
+ql_8021_md_cntrl(ql_adapter_state_t *ha, md_template_hdr_t *template_hdr,
+    md_entry_cntrl_t *crbEntry)
+{
+	int		tflag;
+	uint32_t	opcode, read_value, addr, entry_addr, loop_cnt;
+	clock_t		timeout, elapsed;
+
+	entry_addr = crbEntry->addr;
+
+	for (loop_cnt = 0; loop_cnt < crbEntry->op_count; loop_cnt++) {
+		opcode = crbEntry->b.cv.opcode;
+		if (opcode & QL_DBG_OPCODE_WR) {
+			ql_8021_write_reg(ha, crbEntry->value_1, entry_addr);
+			opcode &= ~QL_DBG_OPCODE_WR;
+		}
+		if (opcode & QL_DBG_OPCODE_RW) {
+			read_value = ql_8021_read_reg(ha, entry_addr);
+			ql_8021_write_reg(ha, read_value, entry_addr);
+			opcode &= ~QL_DBG_OPCODE_RW;
+		}
+		if (opcode & QL_DBG_OPCODE_AND) {
+			read_value = ql_8021_read_reg(ha, entry_addr);
+			read_value &= crbEntry->value_2;
+			opcode &= ~QL_DBG_OPCODE_AND;
+
+			/* Checking for OR here to avoid extra register write */
+			if (opcode & QL_DBG_OPCODE_OR) {
+				read_value |= crbEntry->value_3;
+				opcode &= ~QL_DBG_OPCODE_OR;
+			}
+			ql_8021_write_reg(ha, read_value, entry_addr);
+		}
+		if (opcode & QL_DBG_OPCODE_OR) {
+			read_value = ql_8021_read_reg(ha, entry_addr);
+			read_value |= crbEntry->value_3;
+			ql_8021_write_reg(ha, read_value, entry_addr);
+			opcode &= ~QL_DBG_OPCODE_OR;
+		}
+		if (opcode & QL_DBG_OPCODE_POLL) {
+			opcode &= ~QL_DBG_OPCODE_POLL;
+			(void) drv_getparm(LBOLT, &timeout);
+			timeout += drv_usectohz(
+			    CHAR_TO_SHORT(crbEntry->a.ac.poll_timeout[0],
+			    crbEntry->a.ac.poll_timeout[1]) * 1000) + 1;
+			addr = entry_addr;
+			read_value = ql_8021_read_reg(ha, addr);
+			tflag = 0;
+			while (!tflag && ((read_value & crbEntry->value_2) !=
+			    crbEntry->value_1)) {
+				(void) drv_getparm(LBOLT, &elapsed);
+				if (elapsed > timeout) {
+					tflag = 1;
+				}
+				read_value = ql_8021_read_reg(ha, addr);
+			}
+			if (tflag) {
+				/*
+				 *  Report timeout error.  core dump capture
+				 *  failed Skip remaining entries. Write buffer
+				 *  out to file Use driver specific fields in
+				 *  template header to report this error.
+				 */
+				EL(ha, "timeout\n");
+				return (-1);
+			}
+		}
+		if (opcode & QL_DBG_OPCODE_RDSTATE) {
+			/*
+			 * decide which address to use.
+			 */
+			if (crbEntry->a.ac.state_index_a) {
+				addr = template_hdr->saved_state_array[
+				    crbEntry->a.ac.state_index_a];
+			} else {
+				addr = entry_addr;
+			}
+			read_value = ql_8021_read_reg(ha, addr);
+			template_hdr->saved_state_array[
+			    crbEntry->b.cv.state_index_v] = read_value;
+			opcode &= ~QL_DBG_OPCODE_RDSTATE;
+		}
+		if (opcode & QL_DBG_OPCODE_WRSTATE) {
+			/*
+			 * decide which value to use.
+			 */
+			if (crbEntry->b.cv.state_index_v) {
+				read_value = template_hdr->saved_state_array[
+				    crbEntry->b.cv.state_index_v];
+			} else {
+				read_value = crbEntry->value_1;
+			}
+			/*
+			 * decide which address to use.
+			 */
+			if (crbEntry->a.ac.state_index_a) {
+				addr = template_hdr->saved_state_array[
+				    crbEntry->a.ac.state_index_a];
+			} else {
+				addr = entry_addr;
+			}
+			ql_8021_write_reg(ha, read_value, addr);
+			opcode &= ~QL_DBG_OPCODE_WRSTATE;
+		}
+		if (opcode & QL_DBG_OPCODE_MDSTATE) {
+			/* Read value from saved state using index */
+			read_value = template_hdr->saved_state_array[
+			    crbEntry->b.cv.state_index_v];
+			/* Shift left operation */
+			read_value <<= crbEntry->b.cv.shl;
+			/* Shift right operation */
+			read_value >>= crbEntry->b.cv.shr;
+			/* check if AND mask is provided */
+			if (crbEntry->value_2) {
+				read_value &= crbEntry->value_2;
+			}
+			read_value |= crbEntry->value_3; /* OR operation */
+			read_value += crbEntry->value_1; /* inc operation */
+			/* Write value back to state area. */
+			template_hdr->saved_state_array[
+			    crbEntry->b.cv.state_index_v] = read_value;
+			opcode &= ~QL_DBG_OPCODE_MDSTATE;
+		}
+		entry_addr += crbEntry->a.ac.addr_stride;
+	}
+
+	return (0);
+}
+
+/*
+ * Error Checking routines for template consistency.
+ *
+ * We catch an error where driver does not read
+ * as much data as we expect from the entry.
+ */
+static void
+ql_8021_md_entry_err_chk(ql_adapter_state_t *ha, md_entry_t *entry,
+    uint32_t esize, int e_cnt)
+{
+	if (esize != entry->h.entry_capture_size) {
+		EL(ha, "%d %04x Dump write count = %d did not match entry "
+		    "capture size = %d entry_count = %d\n", entry->h.entry_type,
+		    entry->h.a.ecw.entry_capture_mask, esize,
+		    entry->h.entry_capture_size, e_cnt);
+		entry->h.entry_capture_size = esize;
+		entry->h.a.ecw.driver_flags = (uint8_t)
+		    (entry->h.a.ecw.driver_flags | QL_DBG_SKIPPED_FLAG);
+	}
+}
+
+static uint32_t
+ql_8021_md_template_checksum(ql_adapter_state_t *ha)
+{
+	uint64_t	sum = 0;
+	uint32_t	cnt, *bp;
+
+	cnt = (uint32_t)(ha->dmp_template.size / sizeof (uint32_t));
+	bp = ha->dmp_template.bp;
+	while (cnt-- > 0) {
+		sum += ddi_get32(ha->dmp_template.acc_handle, bp++);
+	}
+	while (sum >> 32) {
+		sum = (sum & 0xFFFFFFFF) + (sum >> 32);
+	}
+	cnt = (uint32_t)~sum;
+
+	return (cnt);
+}
+
+static uint32_t
+ql_8021_read_reg(ql_adapter_state_t *ha, uint32_t addr)
+{
+	uint32_t	addr0, addr1, value;
+
+	(void) ql_8021_crb_win_lock(ha);
+
+	addr0 = addr & 0xFFFF0000;
+	WRT_REG_DWORD(ha, (ha->nx_pcibase + 0x00130060), addr0);
+	/* PCI posting read */
+	(void) RD_REG_DWORD(ha, (ha->nx_pcibase + 0x00130060));
+	addr1 = addr & 0x0000FFFF;
+	value = RD_REG_DWORD(ha, (ha->nx_pcibase + 0x001E0000 + addr1));
+
+	ql_8021_crb_win_unlock(ha);
+
+	return (value);
+}
+
+static void
+ql_8021_write_reg(ql_adapter_state_t *ha, uint32_t value, uint32_t addr)
+{
+	uint32_t	addr0, addr1;
+
+	(void) ql_8021_crb_win_lock(ha);
+
+	addr0 = addr & 0xFFFF0000;
+	WRT_REG_DWORD(ha, (ha->nx_pcibase + 0x00130060), addr0);
+	/* PCI posting read */
+	(void) RD_REG_DWORD(ha, (ha->nx_pcibase + 0x00130060));
+	addr1 = addr & 0x0000FFFF;
+	WRT_REG_DWORD(ha, (ha->nx_pcibase + 0x001E0000 + addr1), value);
+	/* PCI posting read */
+	(void) RD_REG_DWORD(ha, (ha->nx_pcibase + 0x001E0000 + addr1));
+
+	ql_8021_crb_win_unlock(ha);
+}
+
+static uint32_t
+ql_8021_read_ocm(ql_adapter_state_t *ha, uint32_t addr)
+{
+	uint32_t	value;
+
+	value = RD_REG_DWORD(ha, (ha->nx_pcibase + addr));
+
+	return (value);
 }
