summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_nx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_nx.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c919
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 *)&reg->req_q_out[0], 0);
WRT_REG_DWORD((unsigned long __iomem *)&reg->rsp_q_in[0], 0);
WRT_REG_DWORD((unsigned long __iomem *)&reg->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(&reg->host_int)) {
stat = RD_REG_DWORD(&reg->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(&reg->host_int)) {
stat = RD_REG_DWORD(&reg->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(
+ &reg->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;