diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_nx.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nx.c | 919 |
1 files changed, 469 insertions, 450 deletions
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index ff562de0e8e7..8d9edfb39803 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -19,6 +19,7 @@ #define QLA82XX_PCI_OCM0_2M (0xc0000) #define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800) #define GET_MEM_OFFS_2M(addr) (addr & MASK(18)) +#define BLOCK_PROTECT_BITS 0x0F /* CRB window related */ #define CRB_BLK(off) ((off >> 20) & 0x3f) @@ -402,6 +403,54 @@ qla82xx_pci_set_crbwindow(struct qla_hw_data *ha, u64 off) return off; } +static int +qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong *off) +{ + struct crb_128M_2M_sub_block_map *m; + + if (*off >= QLA82XX_CRB_MAX) + return -1; + + if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) { + *off = (*off - QLA82XX_PCI_CAMQM) + + QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase; + return 0; + } + + if (*off < QLA82XX_PCI_CRBSPACE) + return -1; + + *off -= QLA82XX_PCI_CRBSPACE; + + /* Try direct map */ + m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)]; + + if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) { + *off = *off + m->start_2M - m->start_128M + ha->nx_pcibase; + return 0; + } + /* Not in direct map, use crb window */ + return 1; +} + +#define CRB_WIN_LOCK_TIMEOUT 100000000 +static int qla82xx_crb_win_lock(struct qla_hw_data *ha) +{ + int done = 0, timeout = 0; + + while (!done) { + /* acquire semaphore3 from PCI HW block */ + done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK)); + if (done == 1) + break; + if (timeout >= CRB_WIN_LOCK_TIMEOUT) + return -1; + timeout++; + } + qla82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->portnum); + return 0; +} + int qla82xx_wr_32(struct qla_hw_data *ha, ulong off, u32 data) { @@ -452,24 +501,6 @@ qla82xx_rd_32(struct qla_hw_data *ha, ulong off) return data; } -#define CRB_WIN_LOCK_TIMEOUT 100000000 -int qla82xx_crb_win_lock(struct qla_hw_data *ha) -{ - int done = 0, timeout = 0; - - while (!done) { - /* acquire semaphore3 from PCI HW block */ - done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK)); - if (done == 1) - break; - if (timeout >= CRB_WIN_LOCK_TIMEOUT) - return -1; - timeout++; - } - qla82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->portnum); - return 0; -} - #define IDC_LOCK_TIMEOUT 100000000 int qla82xx_idc_lock(struct qla_hw_data *ha) { @@ -503,36 +534,6 @@ void qla82xx_idc_unlock(struct qla_hw_data *ha) qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK)); } -int -qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong *off) -{ - struct crb_128M_2M_sub_block_map *m; - - if (*off >= QLA82XX_CRB_MAX) - return -1; - - if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) { - *off = (*off - QLA82XX_PCI_CAMQM) + - QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase; - return 0; - } - - if (*off < QLA82XX_PCI_CRBSPACE) - return -1; - - *off -= QLA82XX_PCI_CRBSPACE; - - /* Try direct map */ - m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)]; - - if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) { - *off = *off + m->start_2M - m->start_128M + ha->nx_pcibase; - return 0; - } - /* Not in direct map, use crb window */ - return 1; -} - /* PCI Windowing for DDR regions. */ #define QLA82XX_ADDR_IN_RANGE(addr, low, high) \ (((addr) <= (high)) && ((addr) >= (low))) @@ -556,7 +557,7 @@ qla82xx_pci_mem_bound_check(struct qla_hw_data *ha, int qla82xx_pci_set_window_warning_count; -unsigned long +static unsigned long qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr) { int window; @@ -796,181 +797,9 @@ qla82xx_pci_mem_write_direct(struct qla_hw_data *ha, return ret; } -int -qla82xx_wrmem(struct qla_hw_data *ha, u64 off, void *data, int size) -{ - int i, j, ret = 0, loop, sz[2], off0; - u32 temp; - u64 off8, mem_crb, tmpw, word[2] = {0, 0}; -#define MAX_CTL_CHECK 1000 - /* - * If not MN, go check for MS or invalid. - */ - if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) { - mem_crb = QLA82XX_CRB_QDR_NET; - } else { - mem_crb = QLA82XX_CRB_DDR_NET; - if (qla82xx_pci_mem_bound_check(ha, off, size) == 0) - return qla82xx_pci_mem_write_direct(ha, off, - data, size); - } - - off8 = off & 0xfffffff8; - off0 = off & 0x7; - sz[0] = (size < (8 - off0)) ? size : (8 - off0); - sz[1] = size - sz[0]; - loop = ((off0 + size - 1) >> 3) + 1; - - if ((size != 8) || (off0 != 0)) { - for (i = 0; i < loop; i++) { - if (qla82xx_rdmem(ha, off8 + (i << 3), &word[i], 8)) - return -1; - } - } - - switch (size) { - case 1: - tmpw = *((u8 *)data); - break; - case 2: - tmpw = *((u16 *)data); - break; - case 4: - tmpw = *((u32 *)data); - break; - case 8: - default: - tmpw = *((u64 *)data); - break; - } - - word[0] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); - word[0] |= tmpw << (off0 * 8); - - if (loop == 2) { - word[1] &= ~(~0ULL << (sz[1] * 8)); - word[1] |= tmpw >> (sz[0] * 8); - } - - for (i = 0; i < loop; i++) { - temp = off8 + (i << 3); - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); - temp = word[i] & 0xffffffff; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); - temp = (word[i] >> 32) & 0xffffffff; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); - temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp); - - for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); - if ((temp & MIU_TA_CTL_BUSY) == 0) - break; - } - - if (j >= MAX_CTL_CHECK) { - qla_printk(KERN_WARNING, ha, - "%s: Fail to write through agent\n", - QLA2XXX_DRIVER_NAME); - ret = -1; - break; - } - } - return ret; -} - -int -qla82xx_rdmem(struct qla_hw_data *ha, u64 off, void *data, int size) -{ - int i, j = 0, k, start, end, loop, sz[2], off0[2]; - u32 temp; - u64 off8, val, mem_crb, word[2] = {0, 0}; -#define MAX_CTL_CHECK 1000 - - /* - * If not MN, go check for MS or invalid. - */ - if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) - mem_crb = QLA82XX_CRB_QDR_NET; - else { - mem_crb = QLA82XX_CRB_DDR_NET; - if (qla82xx_pci_mem_bound_check(ha, off, size) == 0) - return qla82xx_pci_mem_read_direct(ha, off, - data, size); - } - - off8 = off & 0xfffffff8; - off0[0] = off & 0x7; - off0[1] = 0; - sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]); - sz[1] = size - sz[0]; - loop = ((off0[0] + size - 1) >> 3) + 1; - - for (i = 0; i < loop; i++) { - temp = off8 + (i << 3); - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp); - temp = MIU_TA_CTL_ENABLE; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); - - for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); - if ((temp & MIU_TA_CTL_BUSY) == 0) - break; - } - - if (j >= MAX_CTL_CHECK) { - qla_printk(KERN_INFO, ha, - "%s: Fail to read through agent\n", - QLA2XXX_DRIVER_NAME); - break; - } - - start = off0[i] >> 2; - end = (off0[i] + sz[i] - 1) >> 2; - for (k = start; k <= end; k++) { - temp = qla82xx_rd_32(ha, - mem_crb + MIU_TEST_AGT_RDDATA(k)); - word[i] |= ((u64)temp << (32 * k)); - } - } - - if (j >= MAX_CTL_CHECK) - return -1; - - if (sz[0] == 8) { - val = word[0]; - } else { - val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) | - ((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8)); - } - - switch (size) { - case 1: - *(u8 *)data = val; - break; - case 2: - *(u16 *)data = val; - break; - case 4: - *(u32 *)data = val; - break; - case 8: - *(u64 *)data = val; - break; - } - return 0; -} - #define MTU_FUDGE_FACTOR 100 -unsigned long qla82xx_decode_crb_addr(unsigned long addr) +static unsigned long +qla82xx_decode_crb_addr(unsigned long addr) { int i; unsigned long base_addr, offset, pci_base; @@ -996,7 +825,7 @@ unsigned long qla82xx_decode_crb_addr(unsigned long addr) static long rom_max_timeout = 100; static long qla82xx_rom_lock_timeout = 100; -int +static int qla82xx_rom_lock(struct qla_hw_data *ha) { int done = 0, timeout = 0; @@ -1014,7 +843,7 @@ qla82xx_rom_lock(struct qla_hw_data *ha) return 0; } -int +static int qla82xx_wait_rom_busy(struct qla_hw_data *ha) { long timeout = 0; @@ -1034,7 +863,7 @@ qla82xx_wait_rom_busy(struct qla_hw_data *ha) return 0; } -int +static int qla82xx_wait_rom_done(struct qla_hw_data *ha) { long timeout = 0; @@ -1054,7 +883,7 @@ qla82xx_wait_rom_done(struct qla_hw_data *ha) return 0; } -int +static int qla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) { qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr); @@ -1077,7 +906,7 @@ qla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) return 0; } -int +static int qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) { int ret, loops = 0; @@ -1098,7 +927,7 @@ qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) return ret; } -int +static int qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val) { qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR); @@ -1112,7 +941,7 @@ qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val) return 0; } -int +static int qla82xx_flash_wait_write_finish(struct qla_hw_data *ha) { long timeout = 0; @@ -1136,7 +965,7 @@ qla82xx_flash_wait_write_finish(struct qla_hw_data *ha) return ret; } -int +static int qla82xx_flash_set_write_enable(struct qla_hw_data *ha) { uint32_t val; @@ -1153,7 +982,7 @@ qla82xx_flash_set_write_enable(struct qla_hw_data *ha) return 0; } -int +static int qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val) { if (qla82xx_flash_set_write_enable(ha)) @@ -1168,7 +997,7 @@ qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val) return qla82xx_flash_wait_write_finish(ha); } -int +static int qla82xx_write_disable_flash(struct qla_hw_data *ha) { qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WRDI); @@ -1180,7 +1009,7 @@ qla82xx_write_disable_flash(struct qla_hw_data *ha) return 0; } -int +static int ql82xx_rom_lock_d(struct qla_hw_data *ha) { int loops = 0; @@ -1196,7 +1025,7 @@ ql82xx_rom_lock_d(struct qla_hw_data *ha) return 0;; } -int +static int qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr, uint32_t data) { @@ -1233,7 +1062,8 @@ done_write: /* This routine does CRB initialize sequence * to put the ISP into operational state */ -int qla82xx_pinit_from_rom(scsi_qla_host_t *vha) +static int +qla82xx_pinit_from_rom(scsi_qla_host_t *vha) { int addr, val; int i ; @@ -1346,11 +1176,6 @@ int qla82xx_pinit_from_rom(scsi_qla_host_t *vha) continue; } - if (off == (QLA82XX_CRB_PEG_NET_1 + 0x18)) { - if (!QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) - buf[i].data = 0x1020; - } - qla82xx_wr_32(ha, off, buf[i].data); /* ISP requires much bigger delay to settle down, @@ -1384,7 +1209,8 @@ int qla82xx_pinit_from_rom(scsi_qla_host_t *vha) return 0; } -int qla82xx_check_for_bad_spd(struct qla_hw_data *ha) +static int +qla82xx_check_for_bad_spd(struct qla_hw_data *ha) { u32 val = 0; val = qla82xx_rd_32(ha, BOOT_LOADER_DIMM_STATUS); @@ -1402,12 +1228,122 @@ int qla82xx_check_for_bad_spd(struct qla_hw_data *ha) return 0; } -int +static int +qla82xx_pci_mem_write_2M(struct qla_hw_data *ha, + u64 off, void *data, int size) +{ + int i, j, ret = 0, loop, sz[2], off0; + int scale, shift_amount, startword; + uint32_t temp; + uint64_t off8, mem_crb, tmpw, word[2] = {0, 0}; + + /* + * If not MN, go check for MS or invalid. + */ + if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) + mem_crb = QLA82XX_CRB_QDR_NET; + else { + mem_crb = QLA82XX_CRB_DDR_NET; + if (qla82xx_pci_mem_bound_check(ha, off, size) == 0) + return qla82xx_pci_mem_write_direct(ha, + off, data, size); + } + + off0 = off & 0x7; + sz[0] = (size < (8 - off0)) ? size : (8 - off0); + sz[1] = size - sz[0]; + + off8 = off & 0xfffffff0; + loop = (((off & 0xf) + size - 1) >> 4) + 1; + shift_amount = 4; + scale = 2; + startword = (off & 0xf)/8; + + for (i = 0; i < loop; i++) { + if (qla82xx_pci_mem_read_2M(ha, off8 + + (i << shift_amount), &word[i * scale], 8)) + return -1; + } + + switch (size) { + case 1: + tmpw = *((uint8_t *)data); + break; + case 2: + tmpw = *((uint16_t *)data); + break; + case 4: + tmpw = *((uint32_t *)data); + break; + case 8: + default: + tmpw = *((uint64_t *)data); + break; + } + + if (sz[0] == 8) { + word[startword] = tmpw; + } else { + 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); + } + + /* + * don't lock here - write_wx gets the lock if each time + * write_lock_irqsave(&adapter->adapter_lock, flags); + * netxen_nic_pci_change_crbwindow_128M(adapter, 0); + */ + for (i = 0; i < loop; i++) { + temp = off8 + (i << shift_amount); + qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); + temp = 0; + qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); + temp = word[i * scale] & 0xffffffff; + qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); + temp = (word[i * scale] >> 32) & 0xffffffff; + qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); + temp = word[i*scale + 1] & 0xffffffff; + qla82xx_wr_32(ha, mem_crb + + MIU_TEST_AGT_WRDATA_UPPER_LO, temp); + temp = (word[i*scale + 1] >> 32) & 0xffffffff; + qla82xx_wr_32(ha, mem_crb + + MIU_TEST_AGT_WRDATA_UPPER_HI, temp); + + temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; + qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); + temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; + qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); + + for (j = 0; j < MAX_CTL_CHECK; j++) { + temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); + if ((temp & MIU_TA_CTL_BUSY) == 0) + break; + } + + if (j >= MAX_CTL_CHECK) { + if (printk_ratelimit()) + dev_err(&ha->pdev->dev, + "failed to write through agent\n"); + ret = -1; + break; + } + } + + return ret; +} + +static int qla82xx_fw_load_from_flash(struct qla_hw_data *ha) { int i; long size = 0; - long flashaddr = BOOTLD_START, memaddr = BOOTLD_START; + long flashaddr = ha->flt_region_bootload << 2; + long memaddr = BOOTLD_START; u64 data; u32 high, low; size = (IMAGE_START - BOOTLD_START) / 8; @@ -1427,12 +1363,8 @@ qla82xx_fw_load_from_flash(struct qla_hw_data *ha) } udelay(100); read_lock(&ha->hw_lock); - if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); - } else { - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d); - } + qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); + qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); read_unlock(&ha->hw_lock); return 0; } @@ -1459,17 +1391,10 @@ qla82xx_pci_mem_read_2M(struct qla_hw_data *ha, off, data, size); } - if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { - off8 = off & 0xfffffff0; - off0[0] = off & 0xf; - sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]); - shift_amount = 4; - } else { - off8 = off & 0xfffffff8; - off0[0] = off & 0x7; - sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]); - shift_amount = 4; - } + off8 = off & 0xfffffff0; + off0[0] = off & 0xf; + sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]); + shift_amount = 4; loop = ((off0[0] + size - 1) >> shift_amount) + 1; off0[1] = 0; sz[1] = size - sz[0]; @@ -1544,137 +1469,93 @@ qla82xx_pci_mem_read_2M(struct qla_hw_data *ha, return 0; } -int -qla82xx_pci_mem_write_2M(struct qla_hw_data *ha, - u64 off, void *data, int size) + +static struct qla82xx_uri_table_desc * +qla82xx_get_table_desc(const u8 *unirom, int section) { - int i, j, ret = 0, loop, sz[2], off0; - int scale, shift_amount, p3p, startword; - uint32_t temp; - uint64_t off8, mem_crb, tmpw, word[2] = {0, 0}; + uint32_t i; + struct qla82xx_uri_table_desc *directory = + (struct qla82xx_uri_table_desc *)&unirom[0]; + __le32 offset; + __le32 tab_type; + __le32 entries = cpu_to_le32(directory->num_entries); - /* - * If not MN, go check for MS or invalid. - */ - if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) - mem_crb = QLA82XX_CRB_QDR_NET; - else { - mem_crb = QLA82XX_CRB_DDR_NET; - if (qla82xx_pci_mem_bound_check(ha, off, size) == 0) - return qla82xx_pci_mem_write_direct(ha, - off, data, size); + for (i = 0; i < entries; i++) { + offset = cpu_to_le32(directory->findex) + + (i * cpu_to_le32(directory->entry_size)); + tab_type = cpu_to_le32(*((u32 *)&unirom[offset] + 8)); + + if (tab_type == section) + return (struct qla82xx_uri_table_desc *)&unirom[offset]; } - off0 = off & 0x7; - sz[0] = (size < (8 - off0)) ? size : (8 - off0); - sz[1] = size - sz[0]; + return NULL; +} - if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { - off8 = off & 0xfffffff0; - loop = (((off & 0xf) + size - 1) >> 4) + 1; - shift_amount = 4; - scale = 2; - p3p = 1; - startword = (off & 0xf)/8; - } else { - off8 = off & 0xfffffff8; - loop = ((off0 + size - 1) >> 3) + 1; - shift_amount = 3; - scale = 1; - p3p = 0; - startword = 0; - } - - if (p3p || (size != 8) || (off0 != 0)) { - for (i = 0; i < loop; i++) { - if (qla82xx_pci_mem_read_2M(ha, off8 + - (i << shift_amount), &word[i * scale], 8)) - return -1; - } - } +static struct qla82xx_uri_data_desc * +qla82xx_get_data_desc(struct qla_hw_data *ha, + u32 section, u32 idx_offset) +{ + const u8 *unirom = ha->hablob->fw->data; + int idx = cpu_to_le32(*((int *)&unirom[ha->file_prd_off] + idx_offset)); + struct qla82xx_uri_table_desc *tab_desc = NULL; + __le32 offset; - switch (size) { - case 1: - tmpw = *((uint8_t *)data); - break; - case 2: - tmpw = *((uint16_t *)data); - break; - case 4: - tmpw = *((uint32_t *)data); - break; - case 8: - default: - tmpw = *((uint64_t *)data); - break; - } + tab_desc = qla82xx_get_table_desc(unirom, section); + if (!tab_desc) + return NULL; - if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { - if (sz[0] == 8) { - word[startword] = tmpw; - } else { - 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); + offset = cpu_to_le32(tab_desc->findex) + + (cpu_to_le32(tab_desc->entry_size) * idx); - if (loop == 2) { - word[1] &= ~(~0ULL << (sz[1] * 8)); - word[1] |= tmpw >> (sz[0] * 8); - } + return (struct qla82xx_uri_data_desc *)&unirom[offset]; +} + +static u8 * +qla82xx_get_bootld_offset(struct qla_hw_data *ha) +{ + u32 offset = BOOTLD_START; + struct qla82xx_uri_data_desc *uri_desc = NULL; + + if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) { + uri_desc = qla82xx_get_data_desc(ha, + QLA82XX_URI_DIR_SECT_BOOTLD, QLA82XX_URI_BOOTLD_IDX_OFF); + if (uri_desc) + offset = cpu_to_le32(uri_desc->findex); } - /* - * don't lock here - write_wx gets the lock if each time - * write_lock_irqsave(&adapter->adapter_lock, flags); - * netxen_nic_pci_change_crbwindow_128M(adapter, 0); - */ - for (i = 0; i < loop; i++) { - temp = off8 + (i << shift_amount); - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); - temp = word[i * scale] & 0xffffffff; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); - temp = (word[i * scale] >> 32) & 0xffffffff; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); - if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { - temp = word[i*scale + 1] & 0xffffffff; - qla82xx_wr_32(ha, mem_crb + - MIU_TEST_AGT_WRDATA_UPPER_LO, temp); - temp = (word[i*scale + 1] >> 32) & 0xffffffff; - qla82xx_wr_32(ha, mem_crb + - MIU_TEST_AGT_WRDATA_UPPER_HI, temp); - } + return (u8 *)&ha->hablob->fw->data[offset]; +} - temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); +static __le32 +qla82xx_get_fw_size(struct qla_hw_data *ha) +{ + struct qla82xx_uri_data_desc *uri_desc = NULL; - for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); - if ((temp & MIU_TA_CTL_BUSY) == 0) - break; - } + if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) { + uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW, + QLA82XX_URI_FIRMWARE_IDX_OFF); + if (uri_desc) + return cpu_to_le32(uri_desc->size); + } - if (j >= MAX_CTL_CHECK) { - if (printk_ratelimit()) - dev_err(&ha->pdev->dev, - "failed to write through agent\n"); - ret = -1; - break; - } + return cpu_to_le32(*(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]); +} + +static u8 * +qla82xx_get_fw_offs(struct qla_hw_data *ha) +{ + u32 offset = IMAGE_START; + struct qla82xx_uri_data_desc *uri_desc = NULL; + + if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) { + uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW, + QLA82XX_URI_FIRMWARE_IDX_OFF); + if (uri_desc) + offset = cpu_to_le32(uri_desc->findex); } - return ret; + return (u8 *)&ha->hablob->fw->data[offset]; } /* PCI related functions */ @@ -1714,22 +1595,6 @@ int qla82xx_pci_region_offset(struct pci_dev *pdev, int region) return val; } -int qla82xx_pci_region_len(struct pci_dev *pdev, int region) -{ - unsigned long val = 0; - u32 control; - switch (region) { - case 0: - pci_read_config_dword(pdev, QLA82XX_PCI_REG_MSIX_TBL, &control); - val = control; - break; - case 1: - val = pci_resource_len(pdev, 0) - - qla82xx_pci_region_offset(pdev, 1); - break; - } - return val; -} int qla82xx_iospace_config(struct qla_hw_data *ha) @@ -1851,12 +1716,6 @@ void qla82xx_config_rings(struct scsi_qla_host *vha) icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma)); icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); - icb->version = 1; - icb->frame_payload_size = 2112; - icb->execution_throttle = 8; - icb->exchange_count = 128; - icb->login_retry_count = 8; - WRT_REG_DWORD((unsigned long __iomem *)®->req_q_out[0], 0); WRT_REG_DWORD((unsigned long __iomem *)®->rsp_q_in[0], 0); WRT_REG_DWORD((unsigned long __iomem *)®->rsp_q_out[0], 0); @@ -1870,7 +1729,8 @@ void qla82xx_reset_adapter(struct scsi_qla_host *vha) ha->isp_ops->disable_intrs(ha); } -int qla82xx_fw_load_from_blob(struct qla_hw_data *ha) +static int +qla82xx_fw_load_from_blob(struct qla_hw_data *ha) { u64 *ptr64; u32 i, flashaddr, size; @@ -1878,19 +1738,19 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha) size = (IMAGE_START - BOOTLD_START) / 8; - ptr64 = (u64 *)&ha->hablob->fw->data[BOOTLD_START]; + ptr64 = (u64 *)qla82xx_get_bootld_offset(ha); flashaddr = BOOTLD_START; for (i = 0; i < size; i++) { data = cpu_to_le64(ptr64[i]); - qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8); + if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8)) + return -EIO; flashaddr += 8; } - size = *(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]; - size = (__force u32)cpu_to_le32(size) / 8; - ptr64 = (u64 *)&ha->hablob->fw->data[IMAGE_START]; flashaddr = FLASH_ADDR_START; + size = (__force u32)qla82xx_get_fw_size(ha) / 8; + ptr64 = (u64 *)qla82xx_get_fw_offs(ha); for (i = 0; i < size; i++) { data = cpu_to_le64(ptr64[i]); @@ -1899,23 +1759,90 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha) return -EIO; flashaddr += 8; } + udelay(100); /* Write a magic value to CAMRAM register * at a specified offset to indicate * that all data is written and * ready for firmware to initialize. */ - qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), 0x12345678); + qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), QLA82XX_BDINFO_MAGIC); - if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); - } else - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d); + read_lock(&ha->hw_lock); + qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); + qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); + read_unlock(&ha->hw_lock); return 0; } -int qla82xx_check_cmdpeg_state(struct qla_hw_data *ha) +static int +qla82xx_set_product_offset(struct qla_hw_data *ha) +{ + struct qla82xx_uri_table_desc *ptab_desc = NULL; + const uint8_t *unirom = ha->hablob->fw->data; + uint32_t i; + __le32 entries; + __le32 flags, file_chiprev, offset; + uint8_t chiprev = ha->chip_revision; + /* Hardcoding mn_present flag for P3P */ + int mn_present = 0; + uint32_t flagbit; + + ptab_desc = qla82xx_get_table_desc(unirom, + QLA82XX_URI_DIR_SECT_PRODUCT_TBL); + if (!ptab_desc) + return -1; + + entries = cpu_to_le32(ptab_desc->num_entries); + + for (i = 0; i < entries; i++) { + offset = cpu_to_le32(ptab_desc->findex) + + (i * cpu_to_le32(ptab_desc->entry_size)); + flags = cpu_to_le32(*((int *)&unirom[offset] + + QLA82XX_URI_FLAGS_OFF)); + file_chiprev = cpu_to_le32(*((int *)&unirom[offset] + + QLA82XX_URI_CHIP_REV_OFF)); + + flagbit = mn_present ? 1 : 2; + + if ((chiprev == file_chiprev) && ((1ULL << flagbit) & flags)) { + ha->file_prd_off = offset; + return 0; + } + } + return -1; +} + +int +qla82xx_validate_firmware_blob(scsi_qla_host_t *vha, uint8_t fw_type) +{ + __le32 val; + uint32_t min_size; + struct qla_hw_data *ha = vha->hw; + const struct firmware *fw = ha->hablob->fw; + + ha->fw_type = fw_type; + + if (fw_type == QLA82XX_UNIFIED_ROMIMAGE) { + if (qla82xx_set_product_offset(ha)) + return -EINVAL; + + min_size = QLA82XX_URI_FW_MIN_SIZE; + } else { + val = cpu_to_le32(*(u32 *)&fw->data[QLA82XX_FW_MAGIC_OFFSET]); + if ((__force u32)val != QLA82XX_BDINFO_MAGIC) + return -EINVAL; + + min_size = QLA82XX_FW_MIN_SIZE; + } + + if (fw->size < min_size) + return -EINVAL; + return 0; +} + +static int +qla82xx_check_cmdpeg_state(struct qla_hw_data *ha) { u32 val = 0; int retries = 60; @@ -1953,7 +1880,8 @@ int qla82xx_check_cmdpeg_state(struct qla_hw_data *ha) return QLA_FUNCTION_FAILED; } -int qla82xx_check_rcvpeg_state(struct qla_hw_data *ha) +static int +qla82xx_check_rcvpeg_state(struct qla_hw_data *ha) { u32 val = 0; int retries = 60; @@ -2012,7 +1940,7 @@ static struct qla82xx_legacy_intr_set legacy_intr[] = \ * @ha: SCSI driver HA context * @mb0: Mailbox0 register */ -void +static void qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) { uint16_t cnt; @@ -2097,8 +2025,6 @@ qla82xx_intr_handler(int irq, void *dev_id) if (RD_REG_DWORD(®->host_int)) { stat = RD_REG_DWORD(®->host_status); - if ((stat & HSRX_RISC_INT) == 0) - break; switch (stat & 0xff) { case 0x1: @@ -2173,8 +2099,6 @@ qla82xx_msix_default(int irq, void *dev_id) do { if (RD_REG_DWORD(®->host_int)) { stat = RD_REG_DWORD(®->host_status); - if ((stat & HSRX_RISC_INT) == 0) - break; switch (stat & 0xff) { case 0x1: @@ -2340,7 +2264,7 @@ void qla82xx_init_flags(struct qla_hw_data *ha) ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; } -static inline void +inline void qla82xx_set_drv_active(scsi_qla_host_t *vha) { uint32_t drv_active; @@ -2350,10 +2274,11 @@ qla82xx_set_drv_active(scsi_qla_host_t *vha) /* If reset value is all FF's, initialize DRV_ACTIVE */ if (drv_active == 0xffffffff) { - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, 0); + qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, + QLA82XX_DRV_NOT_ACTIVE); drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); } - drv_active |= (1 << (ha->portnum * 4)); + drv_active |= (QLA82XX_DRV_ACTIVE << (ha->portnum * 4)); qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); } @@ -2363,7 +2288,7 @@ qla82xx_clear_drv_active(struct qla_hw_data *ha) uint32_t drv_active; drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - drv_active &= ~(1 << (ha->portnum * 4)); + drv_active &= ~(QLA82XX_DRV_ACTIVE << (ha->portnum * 4)); qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); } @@ -2374,7 +2299,7 @@ qla82xx_need_reset(struct qla_hw_data *ha) int rval; drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - rval = drv_state & (1 << (ha->portnum * 4)); + rval = drv_state & (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); return rval; } @@ -2388,7 +2313,7 @@ qla82xx_set_rst_ready(struct qla_hw_data *ha) /* If reset value is all FF's, initialize DRV_STATE */ if (drv_state == 0xffffffff) { - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); + qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, QLA82XX_DRVST_NOT_RDY); drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); } drv_state |= (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); @@ -2418,18 +2343,13 @@ qla82xx_set_qsnt_ready(struct qla_hw_data *ha) qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state); } -int qla82xx_load_fw(scsi_qla_host_t *vha) +static int +qla82xx_load_fw(scsi_qla_host_t *vha) { int rst; struct fw_blob *blob; struct qla_hw_data *ha = vha->hw; - /* Put both the PEG CMD and RCV PEG to default state - * of 0 before resetting the hardware - */ - qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0); - qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0); - if (qla82xx_pinit_from_rom(vha) != QLA_SUCCESS) { qla_printk(KERN_ERR, ha, "%s: Error during CRB Initialization\n", __func__); @@ -2470,6 +2390,18 @@ try_blob_fw: goto fw_load_failed; } + /* Validating firmware blob */ + if (qla82xx_validate_firmware_blob(vha, + QLA82XX_FLASH_ROMIMAGE)) { + /* Fallback to URI format */ + if (qla82xx_validate_firmware_blob(vha, + QLA82XX_UNIFIED_ROMIMAGE)) { + qla_printk(KERN_ERR, ha, + "No valid firmware image found!!!"); + return QLA_FUNCTION_FAILED; + } + } + if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) { qla_printk(KERN_ERR, ha, "%s: Firmware loaded successfully " @@ -2488,7 +2420,7 @@ fw_load_failed: return QLA_FUNCTION_FAILED; } -static int +int qla82xx_start_firmware(scsi_qla_host_t *vha) { int pcie_cap; @@ -2496,7 +2428,13 @@ qla82xx_start_firmware(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; /* scrub dma mask expansion register */ - qla82xx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555); + qla82xx_wr_32(ha, CRB_DMA_SHIFT, QLA82XX_DMA_SHIFT_VALUE); + + /* Put both the PEG CMD and RCV PEG to default state + * of 0 before resetting the hardware + */ + qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0); + qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0); /* Overwrite stale initialization register values */ qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0); @@ -2743,6 +2681,19 @@ qla82xx_start_scsi(srb_t *sp) sufficient_dsds: req_cnt = 1; + if (req->cnt < (req_cnt + 2)) { + cnt = (uint16_t)RD_REG_DWORD_RELAXED( + ®->req_q_out[0]); + if (req->ring_index < cnt) + req->cnt = cnt - req->ring_index; + else + req->cnt = req->length - + (req->ring_index - cnt); + } + + if (req->cnt < (req_cnt + 2)) + goto queuing_error; + ctx = sp->ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC); if (!sp->ctx) { DEBUG(printk(KERN_INFO @@ -2940,7 +2891,7 @@ queuing_error: return QLA_FUNCTION_FAILED; } -uint32_t * +static uint32_t * qla82xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, uint32_t length) { @@ -2961,7 +2912,7 @@ done_read: return dwptr; } -int +static int qla82xx_unprotect_flash(struct qla_hw_data *ha) { int ret; @@ -2977,10 +2928,10 @@ qla82xx_unprotect_flash(struct qla_hw_data *ha) if (ret < 0) goto done_unprotect; - val &= ~(0x7 << 2); + val &= ~(BLOCK_PROTECT_BITS << 2); ret = qla82xx_write_status_reg(ha, val); if (ret < 0) { - val |= (0x7 << 2); + val |= (BLOCK_PROTECT_BITS << 2); qla82xx_write_status_reg(ha, val); } @@ -2992,7 +2943,7 @@ done_unprotect: return ret; } -int +static int qla82xx_protect_flash(struct qla_hw_data *ha) { int ret; @@ -3008,7 +2959,7 @@ qla82xx_protect_flash(struct qla_hw_data *ha) if (ret < 0) goto done_protect; - val |= (0x7 << 2); + val |= (BLOCK_PROTECT_BITS << 2); /* LOCK all sectors */ ret = qla82xx_write_status_reg(ha, val); if (ret < 0) @@ -3021,7 +2972,7 @@ done_protect: return ret; } -int +static int qla82xx_erase_sector(struct qla_hw_data *ha, int addr) { int ret = 0; @@ -3201,14 +3152,33 @@ qla82xx_start_iocbs(srb_t *sp) dbval = 0x04 | (ha->portnum << 5); dbval = dbval | (req->id << 8) | (req->ring_index << 16); - WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval); - wmb(); - while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) { - WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval); + if (ql2xdbwr) + qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval); + else { + WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval); wmb(); + while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) { + WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, + dbval); + wmb(); + } } } +void qla82xx_rom_lock_recovery(struct qla_hw_data *ha) +{ + if (qla82xx_rom_lock(ha)) + /* Someone else is holding the lock. */ + qla_printk(KERN_INFO, ha, "Resetting rom_lock\n"); + + /* + * Either we got the lock, or someone + * else died while holding it. + * In either case, unlock. + */ + qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); +} + /* * qla82xx_device_bootstrap * Initialize device, set DEV_READY, start fw @@ -3223,12 +3193,13 @@ qla82xx_start_iocbs(srb_t *sp) static int qla82xx_device_bootstrap(scsi_qla_host_t *vha) { - int rval, i, timeout; + int rval = QLA_SUCCESS; + int i, timeout; uint32_t old_count, count; struct qla_hw_data *ha = vha->hw; + int need_reset = 0, peg_stuck = 1; - if (qla82xx_need_reset(ha)) - goto dev_initialize; + need_reset = qla82xx_need_reset(ha); old_count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); @@ -3242,9 +3213,27 @@ qla82xx_device_bootstrap(scsi_qla_host_t *vha) count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); if (count != old_count) + peg_stuck = 0; + } + + if (need_reset) { + /* We are trying to perform a recovery here. */ + if (peg_stuck) + qla82xx_rom_lock_recovery(ha); + goto dev_initialize; + } else { + /* Start of day for this ha context. */ + if (peg_stuck) { + /* Either we are the first or recovery in progress. */ + qla82xx_rom_lock_recovery(ha); + goto dev_initialize; + } else + /* Firmware already running. */ goto dev_ready; } + return rval; + dev_initialize: /* set to DEV_INITIALIZING */ qla_printk(KERN_INFO, ha, "HW State: INITIALIZING\n"); @@ -3279,6 +3268,10 @@ qla82xx_dev_failed_handler(scsi_qla_host_t *vha) /* Disable the board */ qla_printk(KERN_INFO, ha, "Disabling the board\n"); + qla82xx_idc_lock(ha); + qla82xx_clear_drv_active(ha); + qla82xx_idc_unlock(ha); + /* Set DEV_FAILED flag to disable timer */ vha->device_flags |= DFLG_DEV_FAILED; qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); @@ -3353,6 +3346,9 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; fw_heartbeat_counter = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); + /* all 0xff, assume AER/EEH in progress, ignore */ + if (fw_heartbeat_counter == 0xffffffff) + return; if (vha->fw_heartbeat_counter == fw_heartbeat_counter) { vha->seconds_since_last_heartbeat++; /* FW not alive after 2 seconds */ @@ -3369,8 +3365,19 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha) set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); } qla2xxx_wake_dpc(vha); + ha->flags.fw_hung = 1; + if (ha->flags.mbox_busy) { + ha->flags.mbox_int = 1; + DEBUG2(qla_printk(KERN_ERR, ha, + "Due to fw hung, doing premature " + "completion of mbx command\n")); + if (test_bit(MBX_INTR_WAIT, + &ha->mbx_cmd_flags)) + complete(&ha->mbx_intr_comp); + } } - } + } else + vha->seconds_since_last_heartbeat = 0; vha->fw_heartbeat_counter = fw_heartbeat_counter; } @@ -3472,6 +3479,16 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) "%s(): Adapter reset needed!\n", __func__); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); + ha->flags.fw_hung = 1; + if (ha->flags.mbox_busy) { + ha->flags.mbox_int = 1; + DEBUG2(qla_printk(KERN_ERR, ha, + "Need reset, doing premature " + "completion of mbx command\n")); + if (test_bit(MBX_INTR_WAIT, + &ha->mbx_cmd_flags)) + complete(&ha->mbx_intr_comp); + } } else { qla82xx_check_fw_alive(vha); } @@ -3527,8 +3544,10 @@ qla82xx_abort_isp(scsi_qla_host_t *vha) qla82xx_clear_rst_ready(ha); qla82xx_idc_unlock(ha); - if (rval == QLA_SUCCESS) + if (rval == QLA_SUCCESS) { + ha->flags.fw_hung = 0; qla82xx_restart_isp(vha); + } if (rval) { vha->flags.online = 1; |