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,60 **** * * CDDL HEADER END */ /* ! * Copyright 2010 QLogic Corporation. All rights reserved. * Use is subject to license terms. */ ! #pragma ident "Copyright 2010 QLogic Corporation; ql_nx.c" /* * ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file. * * *********************************************************************** * * ** * * NOTICE ** ! * * COPYRIGHT (C) 1996-2010 QLOGIC CORPORATION ** * * ALL RIGHTS RESERVED ** * * ** * *********************************************************************** * */ #include <ql_apps.h> #include <ql_api.h> #include <ql_debug.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); --- 18,58 ---- * * CDDL HEADER END */ /* ! * Copyright 2015 QLogic Corporation. All rights reserved. * Use is subject to license terms. */ ! #pragma ident "Copyright 2015 QLogic Corporation; ql_nx.c" /* * ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file. * * *********************************************************************** * * ** * * NOTICE ** ! * * 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_crb_addr_transform_setup(ql_adapter_state_t *); static void ql_8021_pci_set_crbwindow_2M(ql_adapter_state_t *, uint64_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,93 **** --- 82,120 ---- 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,341 **** 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); --- 348,357 ----
*** 402,429 **** * 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; ! ha->crb_win = (uint32_t)CRB_HI(*off); ! WRT_REG_DWORD(ha, CRB_WINDOW_2M + ha->nx_pcibase, ha->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) { EL(ha, "Written crbwin (0x%x) != Read crbwin (0x%x), " ! "off=0x%llx\n", ha->crb_win, win_read, *off); } *off = (*off & MASK(16)) + CRB_INDIRECT_2M + (uintptr_t)ha->nx_pcibase; } ! static 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); --- 418,445 ---- * 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, 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 != crb_win) { EL(ha, "Written crbwin (0x%x) != Read crbwin (0x%x), " ! "off=0x%llx\n", crb_win, win_read, *off); } *off = (*off & MASK(16)) + CRB_INDIRECT_2M + (uintptr_t)ha->nx_pcibase; } ! 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,451 **** if (rv == 1) { ql_8021_crb_win_unlock(ha); } } ! static void ql_8021_rd_32(ql_adapter_state_t *ha, uint64_t off, uint32_t *data) { int rv; uint32_t n; --- 457,467 ---- if (rv == 1) { ql_8021_crb_win_unlock(ha); } } ! void ql_8021_rd_32(ql_adapter_state_t *ha, uint64_t off, uint32_t *data) { int rv; uint32_t n;
*** 488,498 **** timeout++; /* Yield CPU */ delay(1); } ! ql_8021_wr_32(ha, UNM_CRB_WIN_LOCK_ID, ha->function_number); return (0); } static void --- 504,514 ---- timeout++; /* Yield CPU */ delay(1); } ! ql_8021_wr_32(ha, UNM_CRB_WIN_LOCK_ID, ha->pci_function_number); return (0); } static void
*** 572,585 **** /*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); 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; --- 588,599 ---- /*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); ! 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,605 **** 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); 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); --- 606,617 ---- EL(ha, "QM access not handled\n"); addr = -1UL; } window = (uint32_t)OCM_WIN(addr); ! 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,620 **** } 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); 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; --- 620,631 ---- } 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, 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,695 **** 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; --- 693,703 ----
*** 728,741 **** 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; --- 736,746 ----
*** 943,954 **** 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); } } else { word[startword] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); word[startword] |= tmpw << (off0 * 8); --- 948,959 ---- 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); } } else { word[startword] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); word[startword] |= tmpw << (off0 * 8);
*** 1117,1127 **** ql_8021_wait_flash_done(ql_adapter_state_t *ha) { clock_t timer; uint32_t status; ! for (timer = 30 * drv_usectohz(1000000); 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"); --- 1122,1132 ---- ql_8021_wait_flash_done(ql_adapter_state_t *ha) { clock_t timer; uint32_t status; ! 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,1141 **** /* Get status. */ ql_8021_rd_32(ha, UNM_ROMUSB_ROM_RDATA, &status); if (!(status & BIT_0)) { return (0); } ! delay(1); } EL(ha, "timeout status=%x\n", status); return (-1); } --- 1136,1146 ---- /* Get status. */ ql_8021_rd_32(ha, UNM_ROMUSB_ROM_RDATA, &status); if (!(status & BIT_0)) { return (0); } ! drv_usecwait(10); } EL(ha, "timeout status=%x\n", status); return (-1); }
*** 1165,1176 **** 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); loops++; } if (loops >= 50000) { EL(ha, "rom_lock failed\n"); return (-1); --- 1170,1181 ---- 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 < 500000)) { ! drv_usecwait(10); loops++; } if (loops >= 50000) { EL(ha, "rom_lock failed\n"); return (-1);
*** 1252,1263 **** 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); loops++; } if (loops >= 50000) { EL(ha, "rom_lock failed\n"); ret = QL_FUNCTION_TIMEOUT; --- 1257,1268 ---- 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 < 500000)) { ! drv_usecwait(10); loops++; } if (loops >= 50000) { EL(ha, "rom_lock failed\n"); ret = QL_FUNCTION_TIMEOUT;
*** 1273,1284 **** 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); loops++; } if (loops >= 50000) { EL(ha, "rom_lock failed\n"); ret = QL_FUNCTION_TIMEOUT; --- 1278,1289 ---- 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 < 500000)) { ! drv_usecwait(10); loops++; } if (loops >= 50000) { EL(ha, "rom_lock failed\n"); ret = QL_FUNCTION_TIMEOUT;
*** 1294,1305 **** 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); loops++; } if (loops >= 50000) { EL(ha, "rom_lock failed\n"); ret = QL_FUNCTION_TIMEOUT; --- 1299,1310 ---- 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 < 500000)) { ! drv_usecwait(10); loops++; } if (loops >= 50000) { EL(ha, "rom_lock failed\n"); ret = QL_FUNCTION_TIMEOUT;
*** 1377,1386 **** --- 1382,1392 ---- /* 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,1537 **** 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; 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); flashaddr += 8; memaddr += 8; } size = ha->flash_fw_size / 2; ! flashaddr = ha->flash_fw_addr << 2; ! memaddr = IMAGE_START; 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"); --- 1516,1554 ---- uint32_t flashaddr, memaddr; uint32_t high, low, size; uint64_t data; size = ha->bootloader_size / 2; ! 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; ! 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; ! 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,1550 **** } data = ((uint64_t)high << 32) | low; (void) ql_8021_pci_mem_write_2M(ha, memaddr, &data, 8); flashaddr += 8; memaddr += 8; - } return (0); } static int ql_8021_load_firmware(ql_adapter_state_t *ha) --- 1556,1573 ---- } 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,1580 **** dp[n] = *bp++; } LITTLE_ENDIAN_32(&size); EL(ha, "signature=%x\n", size); ! size = (IMAGE_START - BOOTLD_START) / 8; ! bp = (uint8_t *)(ha->risc_fw[0].code + BOOTLD_START); ! flashaddr = BOOTLD_START; ! 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); flashaddr += 8; } bp = (uint8_t *)(ha->risc_fw[0].code + FW_SIZE_OFFSET); dp = (uint8_t *)&size; --- 1582,1605 ---- dp[n] = *bp++; } LITTLE_ENDIAN_32(&size); EL(ha, "signature=%x\n", size); ! size = ha->bootloader_size / 2; ! flashaddr = ha->bootloader_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); ! 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,1602 **** } 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; 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); flashaddr += 8; } return (0); } --- 1608,1630 ---- } LITTLE_ENDIAN_32(&size); EL(ha, "IMAGE_START size=%llx\n", size); size = (size + 7) / 8; ! 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); ! 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,1655 **** ql_8021_enable_intrs(ha); ADAPTER_STATE_LOCK(ha); ha->flags |= INTERRUPTS_ENABLED; ADAPTER_STATE_UNLOCK(ha); ! (void) ql_stop_firmware(ha); } static int ql_8021_reset_hw(ql_adapter_state_t *ha, int type) { --- 1672,1684 ---- 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,1675 **** 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); 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); --- 1692,1740 ---- 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); ! /* ! * 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,1712 **** ret = ql_8021_phantom_init(ha); } return (ret); } ! int ! ql_8021_load_risc(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 { /* --- 1760,1775 ---- ret = ql_8021_phantom_init(ha); } return (ret); } ! static int ! ql_8021_load_fw(ql_adapter_state_t *ha) { int rv = 0; GLOBAL_HW_LOCK(); if (ha->risc_fw[0].code) { EL(ha, "from driver\n"); rv = ql_8021_reset_hw(ha, 2); } else { /*
*** 1715,1726 **** */ 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(); --- 1778,1787 ----
*** 1727,1761 **** ADAPTER_STATE_LOCK(ha); ha->flags &= ~INTERRUPTS_ENABLED; ADAPTER_STATE_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); } void ql_8021_clr_hw_intr(ql_adapter_state_t *ha) { --- 1788,1827 ---- 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(); } 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 (rv); } void ql_8021_clr_hw_intr(ql_adapter_state_t *ha) {
*** 1775,1785 **** --- 1841,1853 ---- 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,1804 **** 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]; 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; --- 1861,1871 ---- 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; ! 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,1825 **** return; } ql_8021_rd_32(ha, CRB_DRV_ACTIVE, &val); if (val == 0xffffffff) { ! val = (1 << (ha->function_number * 4)); } else { ! val |= (1 << (ha->function_number * 4)); } ql_8021_wr_32(ha, CRB_DRV_ACTIVE, val); ql_8021_hw_unlock(ha); } --- 1880,1892 ---- return; } ql_8021_rd_32(ha, CRB_DRV_ACTIVE, &val); if (val == 0xffffffff) { ! val = (1 << (ha->pci_function_number * 4)); } else { ! val |= (1 << (ha->pci_function_number * 4)); } ql_8021_wr_32(ha, CRB_DRV_ACTIVE, val); ql_8021_hw_unlock(ha); }
*** 1832,1971 **** 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)); 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; (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_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--) { ! 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); } } ! uint32_t ! ql_8021_idc_handler(ql_adapter_state_t *ha) { ! uint32_t dev_state, drv_state, rval; ! clock_t timer; ql_mbx_data_t mr; ! boolean_t stalled = B_FALSE, lock = 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; ! } 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"); 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 && (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; } (void) ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT); ql_8021_wr_32(ha, CRB_DEV_STATE, rval); break; case NX_DEV_READY: rval = NX_DEV_READY; ! timer = 0; break; case NX_DEV_FAILED: EL(ha, "dev_state=NX_DEV_FAILED\n"); rval = NX_DEV_FAILED; ! timer = 0; break; - case NX_DEV_NEED_RESET: 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); } 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) { ! 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); } break; - case NX_DEV_INITIALIZING: EL(ha, "dev_state=NX_DEV_INITIALIZING\n"); break; case NX_DEV_QUIESCENT: EL(ha, "dev_state=NX_DEV_QUIESCENT\n"); break; default: EL(ha, "dev_state=%x, default\n", dev_state); break; } ! if (lock == B_TRUE) { ! (void) ql_8021_hw_unlock(ha); ! lock = B_FALSE; } ! if (timer) { delay(100); ! timer--; } - } - if (stalled) { ql_restart_driver(ha); } return (rval); } --- 1899,3101 ---- if (ql_8021_hw_lock(ha, IDC_LOCK_TIMEOUT)) { return; } ql_8021_rd_32(ha, CRB_DRV_ACTIVE, &val); ! 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, 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); ! 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; + } + } + } ! 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); ! 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, reset_needed = B_FALSE; ! boolean_t force_load = B_FALSE; (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); + } 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); ! 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 (!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; ! 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; ! 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; 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"); ! } 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); 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; } ! 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; + } + + 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); }