diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_nx2.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nx2.c | 510 |
1 files changed, 429 insertions, 81 deletions
diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c index 86cf10815db0..da9e3902f219 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.c +++ b/drivers/scsi/qla2xxx/qla_nx2.c | |||
@@ -1,17 +1,20 @@ | |||
1 | /* | 1 | /* |
2 | * QLogic Fibre Channel HBA Driver | 2 | * QLogic Fibre Channel HBA Driver |
3 | * Copyright (c) 2003-2013 QLogic Corporation | 3 | * Copyright (c) 2003-2014 QLogic Corporation |
4 | * | 4 | * |
5 | * See LICENSE.qla2xxx for copyright and licensing details. | 5 | * See LICENSE.qla2xxx for copyright and licensing details. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/vmalloc.h> | 8 | #include <linux/vmalloc.h> |
9 | #include <linux/delay.h> | ||
9 | 10 | ||
10 | #include "qla_def.h" | 11 | #include "qla_def.h" |
11 | #include "qla_gbl.h" | 12 | #include "qla_gbl.h" |
12 | 13 | ||
13 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
14 | 15 | ||
16 | #define TIMEOUT_100_MS 100 | ||
17 | |||
15 | /* 8044 Flash Read/Write functions */ | 18 | /* 8044 Flash Read/Write functions */ |
16 | uint32_t | 19 | uint32_t |
17 | qla8044_rd_reg(struct qla_hw_data *ha, ulong addr) | 20 | qla8044_rd_reg(struct qla_hw_data *ha, ulong addr) |
@@ -117,6 +120,95 @@ qla8044_read_write_crb_reg(struct scsi_qla_host *vha, | |||
117 | qla8044_wr_reg_indirect(vha, waddr, value); | 120 | qla8044_wr_reg_indirect(vha, waddr, value); |
118 | } | 121 | } |
119 | 122 | ||
123 | static int | ||
124 | qla8044_poll_wait_for_ready(struct scsi_qla_host *vha, uint32_t addr1, | ||
125 | uint32_t mask) | ||
126 | { | ||
127 | unsigned long timeout; | ||
128 | uint32_t temp; | ||
129 | |||
130 | /* jiffies after 100ms */ | ||
131 | timeout = jiffies + msecs_to_jiffies(TIMEOUT_100_MS); | ||
132 | do { | ||
133 | qla8044_rd_reg_indirect(vha, addr1, &temp); | ||
134 | if ((temp & mask) != 0) | ||
135 | break; | ||
136 | if (time_after_eq(jiffies, timeout)) { | ||
137 | ql_log(ql_log_warn, vha, 0xb151, | ||
138 | "Error in processing rdmdio entry\n"); | ||
139 | return -1; | ||
140 | } | ||
141 | } while (1); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static uint32_t | ||
147 | qla8044_ipmdio_rd_reg(struct scsi_qla_host *vha, | ||
148 | uint32_t addr1, uint32_t addr3, uint32_t mask, uint32_t addr) | ||
149 | { | ||
150 | uint32_t temp; | ||
151 | int ret = 0; | ||
152 | |||
153 | ret = qla8044_poll_wait_for_ready(vha, addr1, mask); | ||
154 | if (ret == -1) | ||
155 | return -1; | ||
156 | |||
157 | temp = (0x40000000 | addr); | ||
158 | qla8044_wr_reg_indirect(vha, addr1, temp); | ||
159 | |||
160 | ret = qla8044_poll_wait_for_ready(vha, addr1, mask); | ||
161 | if (ret == -1) | ||
162 | return 0; | ||
163 | |||
164 | qla8044_rd_reg_indirect(vha, addr3, &ret); | ||
165 | |||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | |||
170 | static int | ||
171 | qla8044_poll_wait_ipmdio_bus_idle(struct scsi_qla_host *vha, | ||
172 | uint32_t addr1, uint32_t addr2, uint32_t addr3, uint32_t mask) | ||
173 | { | ||
174 | unsigned long timeout; | ||
175 | uint32_t temp; | ||
176 | |||
177 | /* jiffies after 100 msecs */ | ||
178 | timeout = jiffies + msecs_to_jiffies(TIMEOUT_100_MS); | ||
179 | do { | ||
180 | temp = qla8044_ipmdio_rd_reg(vha, addr1, addr3, mask, addr2); | ||
181 | if ((temp & 0x1) != 1) | ||
182 | break; | ||
183 | if (time_after_eq(jiffies, timeout)) { | ||
184 | ql_log(ql_log_warn, vha, 0xb152, | ||
185 | "Error in processing mdiobus idle\n"); | ||
186 | return -1; | ||
187 | } | ||
188 | } while (1); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int | ||
194 | qla8044_ipmdio_wr_reg(struct scsi_qla_host *vha, uint32_t addr1, | ||
195 | uint32_t addr3, uint32_t mask, uint32_t addr, uint32_t value) | ||
196 | { | ||
197 | int ret = 0; | ||
198 | |||
199 | ret = qla8044_poll_wait_for_ready(vha, addr1, mask); | ||
200 | if (ret == -1) | ||
201 | return -1; | ||
202 | |||
203 | qla8044_wr_reg_indirect(vha, addr3, value); | ||
204 | qla8044_wr_reg_indirect(vha, addr1, addr); | ||
205 | |||
206 | ret = qla8044_poll_wait_for_ready(vha, addr1, mask); | ||
207 | if (ret == -1) | ||
208 | return -1; | ||
209 | |||
210 | return 0; | ||
211 | } | ||
120 | /* | 212 | /* |
121 | * qla8044_rmw_crb_reg - Read value from raddr, AND with test_mask, | 213 | * qla8044_rmw_crb_reg - Read value from raddr, AND with test_mask, |
122 | * Shift Left,Right/OR/XOR with values RMW header and write value to waddr. | 214 | * Shift Left,Right/OR/XOR with values RMW header and write value to waddr. |
@@ -356,8 +448,8 @@ qla8044_flash_lock(scsi_qla_host_t *vha) | |||
356 | lock_owner = qla8044_rd_reg(ha, | 448 | lock_owner = qla8044_rd_reg(ha, |
357 | QLA8044_FLASH_LOCK_ID); | 449 | QLA8044_FLASH_LOCK_ID); |
358 | ql_log(ql_log_warn, vha, 0xb113, | 450 | ql_log(ql_log_warn, vha, 0xb113, |
359 | "%s: flash lock by %d failed, held by %d\n", | 451 | "%s: Simultaneous flash access by following ports, active port = %d: accessing port = %d", |
360 | __func__, ha->portnum, lock_owner); | 452 | __func__, ha->portnum, lock_owner); |
361 | ret_val = QLA_FUNCTION_FAILED; | 453 | ret_val = QLA_FUNCTION_FAILED; |
362 | break; | 454 | break; |
363 | } | 455 | } |
@@ -1541,7 +1633,7 @@ static void | |||
1541 | qla8044_need_reset_handler(struct scsi_qla_host *vha) | 1633 | qla8044_need_reset_handler(struct scsi_qla_host *vha) |
1542 | { | 1634 | { |
1543 | uint32_t dev_state = 0, drv_state, drv_active; | 1635 | uint32_t dev_state = 0, drv_state, drv_active; |
1544 | unsigned long reset_timeout, dev_init_timeout; | 1636 | unsigned long reset_timeout; |
1545 | struct qla_hw_data *ha = vha->hw; | 1637 | struct qla_hw_data *ha = vha->hw; |
1546 | 1638 | ||
1547 | ql_log(ql_log_fatal, vha, 0xb0c2, | 1639 | ql_log(ql_log_fatal, vha, 0xb0c2, |
@@ -1555,84 +1647,78 @@ qla8044_need_reset_handler(struct scsi_qla_host *vha) | |||
1555 | qla8044_idc_lock(ha); | 1647 | qla8044_idc_lock(ha); |
1556 | } | 1648 | } |
1557 | 1649 | ||
1650 | dev_state = qla8044_rd_direct(vha, | ||
1651 | QLA8044_CRB_DEV_STATE_INDEX); | ||
1558 | drv_state = qla8044_rd_direct(vha, | 1652 | drv_state = qla8044_rd_direct(vha, |
1559 | QLA8044_CRB_DRV_STATE_INDEX); | 1653 | QLA8044_CRB_DRV_STATE_INDEX); |
1560 | drv_active = qla8044_rd_direct(vha, | 1654 | drv_active = qla8044_rd_direct(vha, |
1561 | QLA8044_CRB_DRV_ACTIVE_INDEX); | 1655 | QLA8044_CRB_DRV_ACTIVE_INDEX); |
1562 | 1656 | ||
1563 | ql_log(ql_log_info, vha, 0xb0c5, | 1657 | ql_log(ql_log_info, vha, 0xb0c5, |
1564 | "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n", | 1658 | "%s(%ld): drv_state = 0x%x, drv_active = 0x%x dev_state = 0x%x\n", |
1565 | __func__, vha->host_no, drv_state, drv_active); | 1659 | __func__, vha->host_no, drv_state, drv_active, dev_state); |
1566 | 1660 | ||
1567 | if (!ha->flags.nic_core_reset_owner) { | 1661 | qla8044_set_rst_ready(vha); |
1568 | ql_dbg(ql_dbg_p3p, vha, 0xb0c3, | ||
1569 | "%s(%ld): reset acknowledged\n", | ||
1570 | __func__, vha->host_no); | ||
1571 | qla8044_set_rst_ready(vha); | ||
1572 | 1662 | ||
1573 | /* Non-reset owners ACK Reset and wait for device INIT state | 1663 | /* wait for 10 seconds for reset ack from all functions */ |
1574 | * as part of Reset Recovery by Reset Owner | 1664 | reset_timeout = jiffies + (ha->fcoe_reset_timeout * HZ); |
1575 | */ | ||
1576 | dev_init_timeout = jiffies + (ha->fcoe_reset_timeout * HZ); | ||
1577 | 1665 | ||
1578 | do { | 1666 | do { |
1579 | if (time_after_eq(jiffies, dev_init_timeout)) { | 1667 | if (time_after_eq(jiffies, reset_timeout)) { |
1580 | ql_log(ql_log_info, vha, 0xb0c4, | 1668 | ql_log(ql_log_info, vha, 0xb0c4, |
1581 | "%s: Non Reset owner: Reset Ack Timeout!\n", | 1669 | "%s: Function %d: Reset Ack Timeout!, drv_state: 0x%08x, drv_active: 0x%08x\n", |
1582 | __func__); | 1670 | __func__, ha->portnum, drv_state, drv_active); |
1583 | break; | 1671 | break; |
1584 | } | 1672 | } |
1585 | 1673 | ||
1586 | qla8044_idc_unlock(ha); | 1674 | qla8044_idc_unlock(ha); |
1587 | msleep(1000); | 1675 | msleep(1000); |
1588 | qla8044_idc_lock(ha); | 1676 | qla8044_idc_lock(ha); |
1589 | 1677 | ||
1590 | dev_state = qla8044_rd_direct(vha, | 1678 | dev_state = qla8044_rd_direct(vha, |
1591 | QLA8044_CRB_DEV_STATE_INDEX); | 1679 | QLA8044_CRB_DEV_STATE_INDEX); |
1592 | } while (((drv_state & drv_active) != drv_active) && | 1680 | drv_state = qla8044_rd_direct(vha, |
1593 | (dev_state == QLA8XXX_DEV_NEED_RESET)); | 1681 | QLA8044_CRB_DRV_STATE_INDEX); |
1682 | drv_active = qla8044_rd_direct(vha, | ||
1683 | QLA8044_CRB_DRV_ACTIVE_INDEX); | ||
1684 | } while (((drv_state & drv_active) != drv_active) && | ||
1685 | (dev_state == QLA8XXX_DEV_NEED_RESET)); | ||
1686 | |||
1687 | /* Remove IDC participation of functions not acknowledging */ | ||
1688 | if (drv_state != drv_active) { | ||
1689 | ql_log(ql_log_info, vha, 0xb0c7, | ||
1690 | "%s(%ld): Function %d turning off drv_active of non-acking function 0x%x\n", | ||
1691 | __func__, vha->host_no, ha->portnum, | ||
1692 | (drv_active ^ drv_state)); | ||
1693 | drv_active = drv_active & drv_state; | ||
1694 | qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, | ||
1695 | drv_active); | ||
1594 | } else { | 1696 | } else { |
1595 | qla8044_set_rst_ready(vha); | 1697 | /* |
1596 | 1698 | * Reset owner should execute reset recovery, | |
1597 | /* wait for 10 seconds for reset ack from all functions */ | 1699 | * if all functions acknowledged |
1598 | reset_timeout = jiffies + (ha->fcoe_reset_timeout * HZ); | 1700 | */ |
1599 | 1701 | if ((ha->flags.nic_core_reset_owner) && | |
1600 | while ((drv_state & drv_active) != drv_active) { | 1702 | (dev_state == QLA8XXX_DEV_NEED_RESET)) { |
1601 | if (time_after_eq(jiffies, reset_timeout)) { | 1703 | ha->flags.nic_core_reset_owner = 0; |
1602 | ql_log(ql_log_info, vha, 0xb0c6, | 1704 | qla8044_device_bootstrap(vha); |
1603 | "%s: RESET TIMEOUT!" | 1705 | return; |
1604 | "drv_state: 0x%08x, drv_active: 0x%08x\n", | ||
1605 | QLA2XXX_DRIVER_NAME, drv_state, drv_active); | ||
1606 | break; | ||
1607 | } | ||
1608 | |||
1609 | qla8044_idc_unlock(ha); | ||
1610 | msleep(1000); | ||
1611 | qla8044_idc_lock(ha); | ||
1612 | |||
1613 | drv_state = qla8044_rd_direct(vha, | ||
1614 | QLA8044_CRB_DRV_STATE_INDEX); | ||
1615 | drv_active = qla8044_rd_direct(vha, | ||
1616 | QLA8044_CRB_DRV_ACTIVE_INDEX); | ||
1617 | } | ||
1618 | |||
1619 | if (drv_state != drv_active) { | ||
1620 | ql_log(ql_log_info, vha, 0xb0c7, | ||
1621 | "%s(%ld): Reset_owner turning off drv_active " | ||
1622 | "of non-acking function 0x%x\n", __func__, | ||
1623 | vha->host_no, (drv_active ^ drv_state)); | ||
1624 | drv_active = drv_active & drv_state; | ||
1625 | qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, | ||
1626 | drv_active); | ||
1627 | } | 1706 | } |
1707 | } | ||
1628 | 1708 | ||
1629 | /* | 1709 | /* Exit if non active function */ |
1630 | * Clear RESET OWNER, will be set at next reset | 1710 | if (!(drv_active & (1 << ha->portnum))) { |
1631 | * by next RST_OWNER | ||
1632 | */ | ||
1633 | ha->flags.nic_core_reset_owner = 0; | 1711 | ha->flags.nic_core_reset_owner = 0; |
1712 | return; | ||
1713 | } | ||
1634 | 1714 | ||
1635 | /* Start Reset Recovery */ | 1715 | /* |
1716 | * Execute Reset Recovery if Reset Owner or Function 7 | ||
1717 | * is the only active function | ||
1718 | */ | ||
1719 | if (ha->flags.nic_core_reset_owner || | ||
1720 | ((drv_state & drv_active) == QLA8044_FUN7_ACTIVE_INDEX)) { | ||
1721 | ha->flags.nic_core_reset_owner = 0; | ||
1636 | qla8044_device_bootstrap(vha); | 1722 | qla8044_device_bootstrap(vha); |
1637 | } | 1723 | } |
1638 | } | 1724 | } |
@@ -1655,6 +1741,19 @@ qla8044_set_drv_active(struct scsi_qla_host *vha) | |||
1655 | qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, drv_active); | 1741 | qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, drv_active); |
1656 | } | 1742 | } |
1657 | 1743 | ||
1744 | static int | ||
1745 | qla8044_check_drv_active(struct scsi_qla_host *vha) | ||
1746 | { | ||
1747 | uint32_t drv_active; | ||
1748 | struct qla_hw_data *ha = vha->hw; | ||
1749 | |||
1750 | drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX); | ||
1751 | if (drv_active & (1 << ha->portnum)) | ||
1752 | return QLA_SUCCESS; | ||
1753 | else | ||
1754 | return QLA_TEST_FAILED; | ||
1755 | } | ||
1756 | |||
1658 | static void | 1757 | static void |
1659 | qla8044_clear_idc_dontreset(struct scsi_qla_host *vha) | 1758 | qla8044_clear_idc_dontreset(struct scsi_qla_host *vha) |
1660 | { | 1759 | { |
@@ -1837,14 +1936,16 @@ qla8044_device_state_handler(struct scsi_qla_host *vha) | |||
1837 | 1936 | ||
1838 | while (1) { | 1937 | while (1) { |
1839 | if (time_after_eq(jiffies, dev_init_timeout)) { | 1938 | if (time_after_eq(jiffies, dev_init_timeout)) { |
1840 | ql_log(ql_log_warn, vha, 0xb0cf, | 1939 | if (qla8044_check_drv_active(vha) == QLA_SUCCESS) { |
1841 | "%s: Device Init Failed 0x%x = %s\n", | 1940 | ql_log(ql_log_warn, vha, 0xb0cf, |
1842 | QLA2XXX_DRIVER_NAME, dev_state, | 1941 | "%s: Device Init Failed 0x%x = %s\n", |
1843 | dev_state < MAX_STATES ? | 1942 | QLA2XXX_DRIVER_NAME, dev_state, |
1844 | qdev_state(dev_state) : "Unknown"); | 1943 | dev_state < MAX_STATES ? |
1845 | 1944 | qdev_state(dev_state) : "Unknown"); | |
1846 | qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX, | 1945 | qla8044_wr_direct(vha, |
1847 | QLA8XXX_DEV_FAILED); | 1946 | QLA8044_CRB_DEV_STATE_INDEX, |
1947 | QLA8XXX_DEV_FAILED); | ||
1948 | } | ||
1848 | } | 1949 | } |
1849 | 1950 | ||
1850 | dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX); | 1951 | dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX); |
@@ -2017,6 +2118,13 @@ qla8044_watchdog(struct scsi_qla_host *vha) | |||
2017 | test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags))) { | 2118 | test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags))) { |
2018 | dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX); | 2119 | dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX); |
2019 | 2120 | ||
2121 | if (qla8044_check_fw_alive(vha)) { | ||
2122 | ha->flags.isp82xx_fw_hung = 1; | ||
2123 | ql_log(ql_log_warn, vha, 0xb10a, | ||
2124 | "Firmware hung.\n"); | ||
2125 | qla82xx_clear_pending_mbx(vha); | ||
2126 | } | ||
2127 | |||
2020 | if (qla8044_check_temp(vha)) { | 2128 | if (qla8044_check_temp(vha)) { |
2021 | set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags); | 2129 | set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags); |
2022 | ha->flags.isp82xx_fw_hung = 1; | 2130 | ha->flags.isp82xx_fw_hung = 1; |
@@ -2037,7 +2145,7 @@ qla8044_watchdog(struct scsi_qla_host *vha) | |||
2037 | qla2xxx_wake_dpc(vha); | 2145 | qla2xxx_wake_dpc(vha); |
2038 | } else { | 2146 | } else { |
2039 | /* Check firmware health */ | 2147 | /* Check firmware health */ |
2040 | if (qla8044_check_fw_alive(vha)) { | 2148 | if (ha->flags.isp82xx_fw_hung) { |
2041 | halt_status = qla8044_rd_direct(vha, | 2149 | halt_status = qla8044_rd_direct(vha, |
2042 | QLA8044_PEG_HALT_STATUS1_INDEX); | 2150 | QLA8044_PEG_HALT_STATUS1_INDEX); |
2043 | if (halt_status & | 2151 | if (halt_status & |
@@ -2073,12 +2181,8 @@ qla8044_watchdog(struct scsi_qla_host *vha) | |||
2073 | __func__); | 2181 | __func__); |
2074 | set_bit(ISP_ABORT_NEEDED, | 2182 | set_bit(ISP_ABORT_NEEDED, |
2075 | &vha->dpc_flags); | 2183 | &vha->dpc_flags); |
2076 | qla82xx_clear_pending_mbx(vha); | ||
2077 | } | 2184 | } |
2078 | } | 2185 | } |
2079 | ha->flags.isp82xx_fw_hung = 1; | ||
2080 | ql_log(ql_log_warn, vha, 0xb10a, | ||
2081 | "Firmware hung.\n"); | ||
2082 | qla2xxx_wake_dpc(vha); | 2186 | qla2xxx_wake_dpc(vha); |
2083 | } | 2187 | } |
2084 | } | 2188 | } |
@@ -2286,8 +2390,6 @@ qla8044_minidump_process_rdmem(struct scsi_qla_host *vha, | |||
2286 | } | 2390 | } |
2287 | 2391 | ||
2288 | if (j >= MAX_CTL_CHECK) { | 2392 | if (j >= MAX_CTL_CHECK) { |
2289 | printk_ratelimited(KERN_ERR | ||
2290 | "%s: failed to read through agent\n", __func__); | ||
2291 | write_unlock_irqrestore(&ha->hw_lock, flags); | 2393 | write_unlock_irqrestore(&ha->hw_lock, flags); |
2292 | return QLA_SUCCESS; | 2394 | return QLA_SUCCESS; |
2293 | } | 2395 | } |
@@ -2882,6 +2984,231 @@ error_exit: | |||
2882 | return rval; | 2984 | return rval; |
2883 | } | 2985 | } |
2884 | 2986 | ||
2987 | static uint32_t | ||
2988 | qla8044_minidump_process_rddfe(struct scsi_qla_host *vha, | ||
2989 | struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) | ||
2990 | { | ||
2991 | int loop_cnt; | ||
2992 | uint32_t addr1, addr2, value, data, temp, wrVal; | ||
2993 | uint8_t stride, stride2; | ||
2994 | uint16_t count; | ||
2995 | uint32_t poll, mask, data_size, modify_mask; | ||
2996 | uint32_t wait_count = 0; | ||
2997 | |||
2998 | uint32_t *data_ptr = *d_ptr; | ||
2999 | |||
3000 | struct qla8044_minidump_entry_rddfe *rddfe; | ||
3001 | rddfe = (struct qla8044_minidump_entry_rddfe *) entry_hdr; | ||
3002 | |||
3003 | addr1 = rddfe->addr_1; | ||
3004 | value = rddfe->value; | ||
3005 | stride = rddfe->stride; | ||
3006 | stride2 = rddfe->stride2; | ||
3007 | count = rddfe->count; | ||
3008 | |||
3009 | poll = rddfe->poll; | ||
3010 | mask = rddfe->mask; | ||
3011 | modify_mask = rddfe->modify_mask; | ||
3012 | data_size = rddfe->data_size; | ||
3013 | |||
3014 | addr2 = addr1 + stride; | ||
3015 | |||
3016 | for (loop_cnt = 0x0; loop_cnt < count; loop_cnt++) { | ||
3017 | qla8044_wr_reg_indirect(vha, addr1, (0x40000000 | value)); | ||
3018 | |||
3019 | wait_count = 0; | ||
3020 | while (wait_count < poll) { | ||
3021 | qla8044_rd_reg_indirect(vha, addr1, &temp); | ||
3022 | if ((temp & mask) != 0) | ||
3023 | break; | ||
3024 | wait_count++; | ||
3025 | } | ||
3026 | |||
3027 | if (wait_count == poll) { | ||
3028 | ql_log(ql_log_warn, vha, 0xb153, | ||
3029 | "%s: TIMEOUT\n", __func__); | ||
3030 | goto error; | ||
3031 | } else { | ||
3032 | qla8044_rd_reg_indirect(vha, addr2, &temp); | ||
3033 | temp = temp & modify_mask; | ||
3034 | temp = (temp | ((loop_cnt << 16) | loop_cnt)); | ||
3035 | wrVal = ((temp << 16) | temp); | ||
3036 | |||
3037 | qla8044_wr_reg_indirect(vha, addr2, wrVal); | ||
3038 | qla8044_wr_reg_indirect(vha, addr1, value); | ||
3039 | |||
3040 | wait_count = 0; | ||
3041 | while (wait_count < poll) { | ||
3042 | qla8044_rd_reg_indirect(vha, addr1, &temp); | ||
3043 | if ((temp & mask) != 0) | ||
3044 | break; | ||
3045 | wait_count++; | ||
3046 | } | ||
3047 | if (wait_count == poll) { | ||
3048 | ql_log(ql_log_warn, vha, 0xb154, | ||
3049 | "%s: TIMEOUT\n", __func__); | ||
3050 | goto error; | ||
3051 | } | ||
3052 | |||
3053 | qla8044_wr_reg_indirect(vha, addr1, | ||
3054 | ((0x40000000 | value) + stride2)); | ||
3055 | wait_count = 0; | ||
3056 | while (wait_count < poll) { | ||
3057 | qla8044_rd_reg_indirect(vha, addr1, &temp); | ||
3058 | if ((temp & mask) != 0) | ||
3059 | break; | ||
3060 | wait_count++; | ||
3061 | } | ||
3062 | |||
3063 | if (wait_count == poll) { | ||
3064 | ql_log(ql_log_warn, vha, 0xb155, | ||
3065 | "%s: TIMEOUT\n", __func__); | ||
3066 | goto error; | ||
3067 | } | ||
3068 | |||
3069 | qla8044_rd_reg_indirect(vha, addr2, &data); | ||
3070 | |||
3071 | *data_ptr++ = wrVal; | ||
3072 | *data_ptr++ = data; | ||
3073 | } | ||
3074 | |||
3075 | } | ||
3076 | |||
3077 | *d_ptr = data_ptr; | ||
3078 | return QLA_SUCCESS; | ||
3079 | |||
3080 | error: | ||
3081 | return -1; | ||
3082 | |||
3083 | } | ||
3084 | |||
3085 | static uint32_t | ||
3086 | qla8044_minidump_process_rdmdio(struct scsi_qla_host *vha, | ||
3087 | struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) | ||
3088 | { | ||
3089 | int ret = 0; | ||
3090 | uint32_t addr1, addr2, value1, value2, data, selVal; | ||
3091 | uint8_t stride1, stride2; | ||
3092 | uint32_t addr3, addr4, addr5, addr6, addr7; | ||
3093 | uint16_t count, loop_cnt; | ||
3094 | uint32_t poll, mask; | ||
3095 | uint32_t *data_ptr = *d_ptr; | ||
3096 | |||
3097 | struct qla8044_minidump_entry_rdmdio *rdmdio; | ||
3098 | |||
3099 | rdmdio = (struct qla8044_minidump_entry_rdmdio *) entry_hdr; | ||
3100 | |||
3101 | addr1 = rdmdio->addr_1; | ||
3102 | addr2 = rdmdio->addr_2; | ||
3103 | value1 = rdmdio->value_1; | ||
3104 | stride1 = rdmdio->stride_1; | ||
3105 | stride2 = rdmdio->stride_2; | ||
3106 | count = rdmdio->count; | ||
3107 | |||
3108 | poll = rdmdio->poll; | ||
3109 | mask = rdmdio->mask; | ||
3110 | value2 = rdmdio->value_2; | ||
3111 | |||
3112 | addr3 = addr1 + stride1; | ||
3113 | |||
3114 | for (loop_cnt = 0; loop_cnt < count; loop_cnt++) { | ||
3115 | ret = qla8044_poll_wait_ipmdio_bus_idle(vha, addr1, addr2, | ||
3116 | addr3, mask); | ||
3117 | if (ret == -1) | ||
3118 | goto error; | ||
3119 | |||
3120 | addr4 = addr2 - stride1; | ||
3121 | ret = qla8044_ipmdio_wr_reg(vha, addr1, addr3, mask, addr4, | ||
3122 | value2); | ||
3123 | if (ret == -1) | ||
3124 | goto error; | ||
3125 | |||
3126 | addr5 = addr2 - (2 * stride1); | ||
3127 | ret = qla8044_ipmdio_wr_reg(vha, addr1, addr3, mask, addr5, | ||
3128 | value1); | ||
3129 | if (ret == -1) | ||
3130 | goto error; | ||
3131 | |||
3132 | addr6 = addr2 - (3 * stride1); | ||
3133 | ret = qla8044_ipmdio_wr_reg(vha, addr1, addr3, mask, | ||
3134 | addr6, 0x2); | ||
3135 | if (ret == -1) | ||
3136 | goto error; | ||
3137 | |||
3138 | ret = qla8044_poll_wait_ipmdio_bus_idle(vha, addr1, addr2, | ||
3139 | addr3, mask); | ||
3140 | if (ret == -1) | ||
3141 | goto error; | ||
3142 | |||
3143 | addr7 = addr2 - (4 * stride1); | ||
3144 | data = qla8044_ipmdio_rd_reg(vha, addr1, addr3, | ||
3145 | mask, addr7); | ||
3146 | if (data == -1) | ||
3147 | goto error; | ||
3148 | |||
3149 | selVal = (value2 << 18) | (value1 << 2) | 2; | ||
3150 | |||
3151 | stride2 = rdmdio->stride_2; | ||
3152 | *data_ptr++ = selVal; | ||
3153 | *data_ptr++ = data; | ||
3154 | |||
3155 | value1 = value1 + stride2; | ||
3156 | *d_ptr = data_ptr; | ||
3157 | } | ||
3158 | |||
3159 | return 0; | ||
3160 | |||
3161 | error: | ||
3162 | return -1; | ||
3163 | } | ||
3164 | |||
3165 | static uint32_t qla8044_minidump_process_pollwr(struct scsi_qla_host *vha, | ||
3166 | struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) | ||
3167 | { | ||
3168 | uint32_t addr1, addr2, value1, value2, poll, mask, r_value; | ||
3169 | uint32_t wait_count = 0; | ||
3170 | struct qla8044_minidump_entry_pollwr *pollwr_hdr; | ||
3171 | |||
3172 | pollwr_hdr = (struct qla8044_minidump_entry_pollwr *)entry_hdr; | ||
3173 | addr1 = pollwr_hdr->addr_1; | ||
3174 | addr2 = pollwr_hdr->addr_2; | ||
3175 | value1 = pollwr_hdr->value_1; | ||
3176 | value2 = pollwr_hdr->value_2; | ||
3177 | |||
3178 | poll = pollwr_hdr->poll; | ||
3179 | mask = pollwr_hdr->mask; | ||
3180 | |||
3181 | while (wait_count < poll) { | ||
3182 | qla8044_rd_reg_indirect(vha, addr1, &r_value); | ||
3183 | |||
3184 | if ((r_value & poll) != 0) | ||
3185 | break; | ||
3186 | wait_count++; | ||
3187 | } | ||
3188 | |||
3189 | if (wait_count == poll) { | ||
3190 | ql_log(ql_log_warn, vha, 0xb156, "%s: TIMEOUT\n", __func__); | ||
3191 | goto error; | ||
3192 | } | ||
3193 | |||
3194 | qla8044_wr_reg_indirect(vha, addr2, value2); | ||
3195 | qla8044_wr_reg_indirect(vha, addr1, value1); | ||
3196 | |||
3197 | wait_count = 0; | ||
3198 | while (wait_count < poll) { | ||
3199 | qla8044_rd_reg_indirect(vha, addr1, &r_value); | ||
3200 | |||
3201 | if ((r_value & poll) != 0) | ||
3202 | break; | ||
3203 | wait_count++; | ||
3204 | } | ||
3205 | |||
3206 | return QLA_SUCCESS; | ||
3207 | |||
3208 | error: | ||
3209 | return -1; | ||
3210 | } | ||
3211 | |||
2885 | /* | 3212 | /* |
2886 | * | 3213 | * |
2887 | * qla8044_collect_md_data - Retrieve firmware minidump data. | 3214 | * qla8044_collect_md_data - Retrieve firmware minidump data. |
@@ -3089,6 +3416,24 @@ qla8044_collect_md_data(struct scsi_qla_host *vha) | |||
3089 | if (rval != QLA_SUCCESS) | 3416 | if (rval != QLA_SUCCESS) |
3090 | qla8044_mark_entry_skipped(vha, entry_hdr, i); | 3417 | qla8044_mark_entry_skipped(vha, entry_hdr, i); |
3091 | break; | 3418 | break; |
3419 | case QLA8044_RDDFE: | ||
3420 | rval = qla8044_minidump_process_rddfe(vha, entry_hdr, | ||
3421 | &data_ptr); | ||
3422 | if (rval != QLA_SUCCESS) | ||
3423 | qla8044_mark_entry_skipped(vha, entry_hdr, i); | ||
3424 | break; | ||
3425 | case QLA8044_RDMDIO: | ||
3426 | rval = qla8044_minidump_process_rdmdio(vha, entry_hdr, | ||
3427 | &data_ptr); | ||
3428 | if (rval != QLA_SUCCESS) | ||
3429 | qla8044_mark_entry_skipped(vha, entry_hdr, i); | ||
3430 | break; | ||
3431 | case QLA8044_POLLWR: | ||
3432 | rval = qla8044_minidump_process_pollwr(vha, entry_hdr, | ||
3433 | &data_ptr); | ||
3434 | if (rval != QLA_SUCCESS) | ||
3435 | qla8044_mark_entry_skipped(vha, entry_hdr, i); | ||
3436 | break; | ||
3092 | case QLA82XX_RDNOP: | 3437 | case QLA82XX_RDNOP: |
3093 | default: | 3438 | default: |
3094 | qla8044_mark_entry_skipped(vha, entry_hdr, i); | 3439 | qla8044_mark_entry_skipped(vha, entry_hdr, i); |
@@ -3110,6 +3455,7 @@ skip_nxt_entry: | |||
3110 | "Dump data mismatch: Data collected: " | 3455 | "Dump data mismatch: Data collected: " |
3111 | "[0x%x], total_data_size:[0x%x]\n", | 3456 | "[0x%x], total_data_size:[0x%x]\n", |
3112 | data_collected, ha->md_dump_size); | 3457 | data_collected, ha->md_dump_size); |
3458 | rval = QLA_FUNCTION_FAILED; | ||
3113 | goto md_failed; | 3459 | goto md_failed; |
3114 | } | 3460 | } |
3115 | 3461 | ||
@@ -3134,10 +3480,12 @@ qla8044_get_minidump(struct scsi_qla_host *vha) | |||
3134 | 3480 | ||
3135 | if (!qla8044_collect_md_data(vha)) { | 3481 | if (!qla8044_collect_md_data(vha)) { |
3136 | ha->fw_dumped = 1; | 3482 | ha->fw_dumped = 1; |
3483 | ha->prev_minidump_failed = 0; | ||
3137 | } else { | 3484 | } else { |
3138 | ql_log(ql_log_fatal, vha, 0xb0db, | 3485 | ql_log(ql_log_fatal, vha, 0xb0db, |
3139 | "%s: Unable to collect minidump\n", | 3486 | "%s: Unable to collect minidump\n", |
3140 | __func__); | 3487 | __func__); |
3488 | ha->prev_minidump_failed = 1; | ||
3141 | } | 3489 | } |
3142 | } | 3490 | } |
3143 | 3491 | ||