Print this page
NEX-5717 import QLogic 16G FC drivers
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
@@ -18,43 +18,41 @@
*
* CDDL HEADER END
*/
/*
- * 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.
*
* ***********************************************************************
* * **
* * NOTICE **
- * * COPYRIGHT (C) 1996-2010 QLOGIC CORPORATION **
+ * * COPYRIGHT (C) 1996-2015 QLOGIC CORPORATION **
* * ALL RIGHTS RESERVED **
* * **
* ***********************************************************************
*
*/
#include <ql_apps.h>
#include <ql_api.h>
#include <ql_debug.h>
+#include <ql_init.h>
#include <ql_mbx.h>
#include <ql_nx.h>
/*
* 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 *);
static uint32_t ql_8021_pci_mem_bound_check(ql_adapter_state_t *, uint64_t,
uint32_t);
@@ -84,10 +82,39 @@
static int ql_8021_reset_hw(ql_adapter_state_t *, int);
static int ql_8021_init_p3p(ql_adapter_state_t *);
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.
*/
static uint32_t crb_addr_xform[MAX_CRB_XFORM];
@@ -321,21 +348,10 @@
0,
UNM_HW_CRB_HUB_AGT_ADR_PGNC,
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)
{
crb_addr_transform(XDMA);
@@ -402,28 +418,28 @@
* side effect: lock crb window
*/
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
* 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;
rv = ql_8021_pci_get_crb_addr_2M(ha, &off);
@@ -441,11 +457,11 @@
if (rv == 1) {
ql_8021_crb_win_unlock(ha);
}
}
-static void
+void
ql_8021_rd_32(ql_adapter_state_t *ha, uint64_t off, uint32_t *data)
{
int rv;
uint32_t n;
@@ -488,11 +504,11 @@
timeout++;
/* 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);
}
static void
@@ -572,14 +588,12 @@
/*LINTED suspicious 0 comparison*/
if (QL_8021_ADDR_IN_RANGE(addr, UNM_ADDR_DDR_NET,
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);
}
addr = GET_MEM_OFFS_2M(addr) + UNM_PCI_DDR_NET;
@@ -592,14 +606,12 @@
EL(ha, "QM access not handled\n");
addr = -1UL;
}
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) {
EL(ha, "Written OCMwin (0x%x) != Read OCMwin (0x%x)\n",
temp1, win_read);
@@ -608,13 +620,12 @@
} else if (QL_8021_ADDR_IN_RANGE(addr, UNM_ADDR_QDR_NET,
NX_P3_ADDR_QDR_NET_MAX)) {
/* 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);
}
addr = GET_MEM_OFFS_2M(addr) + UNM_PCI_QDR_NET;
@@ -682,14 +693,11 @@
EL(ha, "out of bound pci memory access. offset is 0x%llx\n",
off);
return (-1);
}
- addr = ql_8021_pci_base_offsetfset(ha, start);
- if (!addr) {
addr = (void *)((uint8_t *)ha->nx_pcibase + start);
- }
switch (size) {
case 1:
*(uint8_t *)data = RD_REG_BYTE(ha, addr);
break;
@@ -728,14 +736,11 @@
EL(ha, "out of bound pci memory access. offset is 0x%llx\n",
off);
return (-1);
}
- addr = ql_8021_pci_base_offsetfset(ha, start);
- if (!addr) {
addr = (void *)((uint8_t *)ha->nx_pcibase + start);
- }
switch (size) {
case 1:
WRT_REG_BYTE(ha, addr, *(uint8_t *)data);
break;
@@ -943,12 +948,12 @@
word[startword] &= ~((~(~0ULL << (sz[0] * 8))) <<
(off0 * 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));
word[startword] |= tmpw << (off0 * 8);
@@ -1117,11 +1122,11 @@
ql_8021_wait_flash_done(ql_adapter_state_t *ha)
{
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);
if (ql_8021_wait_rom_done(ha)) {
EL(ha, "Error waiting for rom done2\n");
@@ -1131,11 +1136,11 @@
/* Get status. */
ql_8021_rd_32(ha, UNM_ROMUSB_ROM_RDATA, &status);
if (!(status & BIT_0)) {
return (0);
}
- delay(1);
+ drv_usecwait(10);
}
EL(ha, "timeout status=%x\n", status);
return (-1);
}
@@ -1165,12 +1170,12 @@
int
ql_8021_rom_fast_read(ql_adapter_state_t *ha, uint32_t addr, uint32_t *valp)
{
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) {
EL(ha, "rom_lock failed\n");
return (-1);
@@ -1252,12 +1257,12 @@
int
ql_8021_rom_write(ql_adapter_state_t *ha, uint32_t addr, uint32_t data)
{
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) {
EL(ha, "rom_lock failed\n");
ret = QL_FUNCTION_TIMEOUT;
@@ -1273,12 +1278,12 @@
int
ql_8021_rom_erase(ql_adapter_state_t *ha, uint32_t addr)
{
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) {
EL(ha, "rom_lock failed\n");
ret = QL_FUNCTION_TIMEOUT;
@@ -1294,12 +1299,12 @@
int
ql_8021_rom_wrsr(ql_adapter_state_t *ha, uint32_t data)
{
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) {
EL(ha, "rom_lock failed\n");
ret = QL_FUNCTION_TIMEOUT;
@@ -1377,10 +1382,11 @@
/* Grab the lock so that no one can read flash when we reset the chip */
(void) ql_8021_rom_lock(ha);
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) {
EL(ha, "ERROR Reading crb_init area: n: %08x\n", n);
return (-1);
@@ -1510,28 +1516,39 @@
uint32_t flashaddr, memaddr;
uint32_t high, low, size;
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)) ||
(ql_8021_rom_fast_read(ha, flashaddr + 4, &high))) {
EL(ha, "ql_8021_rom_fast_read != 0\n");
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)) ||
(ql_8021_rom_fast_read(ha, flashaddr + 4, &high))) {
EL(ha, "ql_8021_rom_fast_read3 != 0\n");
@@ -1539,12 +1556,18 @@
}
data = ((uint64_t)high << 32) | low;
(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);
}
static int
ql_8021_load_firmware(ql_adapter_state_t *ha)
@@ -1559,22 +1582,24 @@
dp[n] = *bp++;
}
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++) {
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;
}
bp = (uint8_t *)(ha->risc_fw[0].code + FW_SIZE_OFFSET);
dp = (uint8_t *)&size;
@@ -1583,20 +1608,23 @@
}
LITTLE_ENDIAN_32(&size);
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++) {
for (n = 0; n < 8; n++) {
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;
}
return (0);
}
@@ -1644,12 +1672,13 @@
ql_8021_enable_intrs(ha);
ADAPTER_STATE_LOCK(ha);
ha->flags |= INTERRUPTS_ENABLED;
ADAPTER_STATE_UNLOCK(ha);
-
+ if (!(ha->task_daemon_flags & ISP_ABORT_NEEDED)) {
(void) ql_stop_firmware(ha);
+ }
}
static int
ql_8021_reset_hw(ql_adapter_state_t *ha, int type)
{
@@ -1663,13 +1692,49 @@
ql_8021_wr_32(ha, CRB_CMDPEG_STATE, 0);
ql_8021_wr_32(ha, CRB_RCVPEG_STATE, 0);
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));
ql_8021_wr_32(ha, UNM_ROMUSB_GLB_SW_RESET, rst);
@@ -1695,18 +1760,16 @@
ret = ql_8021_phantom_init(ha);
}
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;
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 {
/*
@@ -1715,12 +1778,10 @@
*/
EL(ha, "from flash\n");
rv = ql_8021_reset_hw(ha, 1);
}
if (rv == 0) {
- ql_8021_fw_loaded = 1;
-
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();
@@ -1727,35 +1788,40 @@
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);
+
+ 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);
+
(void) ql_8021_enable_intrs(ha);
ADAPTER_STATE_LOCK(ha);
ha->flags |= INTERRUPTS_ENABLED;
ADAPTER_STATE_UNLOCK(ha);
} else {
GLOBAL_HW_UNLOCK();
}
- } else {
- GLOBAL_HW_UNLOCK();
- EL(ha, "Firmware loaded by other function\n");
- }
if (rv == 0) {
ql_8021_rd_32(ha, UNM_FW_VERSION_MAJOR, &ha->fw_major_version);
ql_8021_rd_32(ha, UNM_FW_VERSION_MINOR, &ha->fw_minor_version);
ql_8021_rd_32(ha, UNM_FW_VERSION_SUB, &ha->fw_subminor_version);
EL(ha, "fw v%d.%02d.%02d\n", ha->fw_major_version,
ha->fw_minor_version, ha->fw_subminor_version);
} else {
EL(ha, "status = -1\n");
- return (QL_FUNCTION_FAILED);
}
- return (QL_SUCCESS);
+ return (rv);
}
void
ql_8021_clr_hw_intr(ql_adapter_state_t *ha)
{
@@ -1775,11 +1841,13 @@
ql_8021_enable_intrs(ql_adapter_state_t *ha)
{
GLOBAL_HW_LOCK();
ql_8021_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
GLOBAL_HW_UNLOCK();
+ if (!(ha->task_daemon_flags & ISP_ABORT_NEEDED)) {
(void) ql_toggle_interrupt(ha, 1);
+ }
}
void
ql_8021_disable_intrs(ql_adapter_state_t *ha)
{
@@ -1793,12 +1861,11 @@
ql_8021_update_crb_int_ptr(ql_adapter_state_t *ha)
{
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;
ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
@@ -1813,13 +1880,13 @@
return;
}
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);
ql_8021_hw_unlock(ha);
}
@@ -1832,140 +1899,1203 @@
if (ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT)) {
return;
}
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);
}
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;
+ ql_8021_rd_32(ha, CRB_DRV_STATE, &drv_state);
+ 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);
+
+ 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);
- drv_state |= (1 << (ha->function_number * 4));
+ ql_8021_rd_32(ha, CRB_DRV_ACTIVE, &drv_active);
+ 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;
+ }
+ }
+}
- ql_8021_rd_32(ha, CRB_DRV_ACTIVE, &drv_active);
+int
+ql_8021_fw_reload(ql_adapter_state_t *ha)
+{
+ 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);
- for (timer = 30; timer && drv_state != drv_active; timer--) {
- delay(100);
+ rval = ql_8021_load_fw(ha) == 0 ? NX_DEV_READY : NX_DEV_FAILED;
(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_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);
}
-uint32_t
-ql_8021_idc_handler(ql_adapter_state_t *ha)
+void
+ql_8021_idc_poll(ql_adapter_state_t *ha)
{
- uint32_t dev_state, drv_state, rval;
- clock_t timer;
+ 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;
- }
+
+ /* 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);
+ }
switch (dev_state) {
case 0xffffffff:
case NX_DEV_COLD:
+ 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);
ql_8021_rd_32(ha, UNM_FW_VERSION_MINOR,
&ha->fw_minor_version);
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:
+ 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:
+ 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);
+ /*
+ * 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:
+ if (ha->dev_state != dev_state) {
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) {
- 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));
+ 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);
break;
-
case NX_DEV_INITIALIZING:
+ 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:
+ 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:
+ 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;
}
- if (timer) {
+ /* 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);
- timer--;
+ 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;
+ }
+
+ 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;
+ }
+
+ /* 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);
}