diff options
author | Vikas Chaudhary <vikas.chaudhary@qlogic.com> | 2012-08-22 07:55:08 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-09-24 04:11:08 -0400 |
commit | 6e7b429259fc0b7f2d9b1147466656b34d114815 (patch) | |
tree | b5bc8dc7e7e803f6589c9cdd4e71c8dc7a9932ab | |
parent | aec07caedbb769535e78adca30c851c977fd5741 (diff) |
[SCSI] qla4xxx: Added support for ISP83XX
Signed-off-by: Poornima Vonti <poornima.vonti@qlogic.com>
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r-- | drivers/scsi/qla4xxx/Kconfig | 4 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/Makefile | 2 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_83xx.c | 1468 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_83xx.h | 262 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_attr.c | 2 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_dbg.c | 28 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_def.h | 27 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_fw.h | 38 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_glbl.h | 41 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_init.c | 15 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_iocb.c | 12 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_isr.c | 202 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 6 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_nx.c | 488 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_nx.h | 17 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 262 |
16 files changed, 2689 insertions, 185 deletions
diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig index f1ad02ea212..e4dc7c733c2 100644 --- a/drivers/scsi/qla4xxx/Kconfig +++ b/drivers/scsi/qla4xxx/Kconfig | |||
@@ -4,5 +4,5 @@ config SCSI_QLA_ISCSI | |||
4 | select SCSI_ISCSI_ATTRS | 4 | select SCSI_ISCSI_ATTRS |
5 | select ISCSI_BOOT_SYSFS | 5 | select ISCSI_BOOT_SYSFS |
6 | ---help--- | 6 | ---help--- |
7 | This driver supports the QLogic 40xx (ISP4XXX) and 8022 (ISP82XX) | 7 | This driver supports the QLogic 40xx (ISP4XXX), 8022 (ISP82XX) |
8 | iSCSI host adapter family. | 8 | and 8032 (ISP83XX) iSCSI host adapter family. |
diff --git a/drivers/scsi/qla4xxx/Makefile b/drivers/scsi/qla4xxx/Makefile index 5b44139ff43..4230977748c 100644 --- a/drivers/scsi/qla4xxx/Makefile +++ b/drivers/scsi/qla4xxx/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \ | 1 | qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \ |
2 | ql4_nx.o ql4_nvram.o ql4_dbg.o ql4_attr.o ql4_bsg.o | 2 | ql4_nx.o ql4_nvram.o ql4_dbg.o ql4_attr.o ql4_bsg.o ql4_83xx.o |
3 | 3 | ||
4 | obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o | 4 | obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o |
5 | 5 | ||
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c new file mode 100644 index 00000000000..f963b06a158 --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_83xx.c | |||
@@ -0,0 +1,1468 @@ | |||
1 | /* | ||
2 | * QLogic iSCSI HBA Driver | ||
3 | * Copyright (c) 2003-2012 QLogic Corporation | ||
4 | * | ||
5 | * See LICENSE.qla4xxx for copyright and licensing details. | ||
6 | */ | ||
7 | |||
8 | #include <linux/ratelimit.h> | ||
9 | |||
10 | #include "ql4_def.h" | ||
11 | #include "ql4_version.h" | ||
12 | #include "ql4_glbl.h" | ||
13 | #include "ql4_dbg.h" | ||
14 | #include "ql4_inline.h" | ||
15 | |||
16 | uint32_t qla4_83xx_rd_reg(struct scsi_qla_host *ha, ulong addr) | ||
17 | { | ||
18 | return readl((void __iomem *)(ha->nx_pcibase + addr)); | ||
19 | } | ||
20 | |||
21 | void qla4_83xx_wr_reg(struct scsi_qla_host *ha, ulong addr, uint32_t val) | ||
22 | { | ||
23 | writel(val, (void __iomem *)(ha->nx_pcibase + addr)); | ||
24 | } | ||
25 | |||
26 | static int qla4_83xx_set_win_base(struct scsi_qla_host *ha, uint32_t addr) | ||
27 | { | ||
28 | uint32_t val; | ||
29 | int ret_val = QLA_SUCCESS; | ||
30 | |||
31 | qla4_83xx_wr_reg(ha, QLA83XX_CRB_WIN_FUNC(ha->func_num), addr); | ||
32 | val = qla4_83xx_rd_reg(ha, QLA83XX_CRB_WIN_FUNC(ha->func_num)); | ||
33 | if (val != addr) { | ||
34 | ql4_printk(KERN_ERR, ha, "%s: Failed to set register window : addr written 0x%x, read 0x%x!\n", | ||
35 | __func__, addr, val); | ||
36 | ret_val = QLA_ERROR; | ||
37 | } | ||
38 | |||
39 | return ret_val; | ||
40 | } | ||
41 | |||
42 | int qla4_83xx_rd_reg_indirect(struct scsi_qla_host *ha, uint32_t addr, | ||
43 | uint32_t *data) | ||
44 | { | ||
45 | int ret_val; | ||
46 | |||
47 | ret_val = qla4_83xx_set_win_base(ha, addr); | ||
48 | |||
49 | if (ret_val == QLA_SUCCESS) | ||
50 | *data = qla4_83xx_rd_reg(ha, QLA83XX_WILDCARD); | ||
51 | else | ||
52 | ql4_printk(KERN_ERR, ha, "%s: failed read of addr 0x%x!\n", | ||
53 | __func__, addr); | ||
54 | |||
55 | return ret_val; | ||
56 | } | ||
57 | |||
58 | int qla4_83xx_wr_reg_indirect(struct scsi_qla_host *ha, uint32_t addr, | ||
59 | uint32_t data) | ||
60 | { | ||
61 | int ret_val; | ||
62 | |||
63 | ret_val = qla4_83xx_set_win_base(ha, addr); | ||
64 | |||
65 | if (ret_val == QLA_SUCCESS) | ||
66 | qla4_83xx_wr_reg(ha, QLA83XX_WILDCARD, data); | ||
67 | else | ||
68 | ql4_printk(KERN_ERR, ha, "%s: failed wrt to addr 0x%x, data 0x%x\n", | ||
69 | __func__, addr, data); | ||
70 | |||
71 | return ret_val; | ||
72 | } | ||
73 | |||
74 | static int qla4_83xx_flash_lock(struct scsi_qla_host *ha) | ||
75 | { | ||
76 | int lock_owner; | ||
77 | int timeout = 0; | ||
78 | uint32_t lock_status = 0; | ||
79 | int ret_val = QLA_SUCCESS; | ||
80 | |||
81 | while (lock_status == 0) { | ||
82 | lock_status = qla4_83xx_rd_reg(ha, QLA83XX_FLASH_LOCK); | ||
83 | if (lock_status) | ||
84 | break; | ||
85 | |||
86 | if (++timeout >= QLA83XX_FLASH_LOCK_TIMEOUT / 20) { | ||
87 | lock_owner = qla4_83xx_rd_reg(ha, | ||
88 | QLA83XX_FLASH_LOCK_ID); | ||
89 | ql4_printk(KERN_ERR, ha, "%s: flash lock by func %d failed, held by func %d\n", | ||
90 | __func__, ha->func_num, lock_owner); | ||
91 | ret_val = QLA_ERROR; | ||
92 | break; | ||
93 | } | ||
94 | msleep(20); | ||
95 | } | ||
96 | |||
97 | qla4_83xx_wr_reg(ha, QLA83XX_FLASH_LOCK_ID, ha->func_num); | ||
98 | return ret_val; | ||
99 | } | ||
100 | |||
101 | static void qla4_83xx_flash_unlock(struct scsi_qla_host *ha) | ||
102 | { | ||
103 | /* Reading FLASH_UNLOCK register unlocks the Flash */ | ||
104 | qla4_83xx_wr_reg(ha, QLA83XX_FLASH_LOCK_ID, 0xFF); | ||
105 | qla4_83xx_rd_reg(ha, QLA83XX_FLASH_UNLOCK); | ||
106 | } | ||
107 | |||
108 | int qla4_83xx_flash_read_u32(struct scsi_qla_host *ha, uint32_t flash_addr, | ||
109 | uint8_t *p_data, int u32_word_count) | ||
110 | { | ||
111 | int i; | ||
112 | uint32_t u32_word; | ||
113 | uint32_t addr = flash_addr; | ||
114 | int ret_val = QLA_SUCCESS; | ||
115 | |||
116 | ret_val = qla4_83xx_flash_lock(ha); | ||
117 | if (ret_val == QLA_ERROR) | ||
118 | goto exit_lock_error; | ||
119 | |||
120 | if (addr & 0x03) { | ||
121 | ql4_printk(KERN_ERR, ha, "%s: Illegal addr = 0x%x\n", | ||
122 | __func__, addr); | ||
123 | ret_val = QLA_ERROR; | ||
124 | goto exit_flash_read; | ||
125 | } | ||
126 | |||
127 | for (i = 0; i < u32_word_count; i++) { | ||
128 | ret_val = qla4_83xx_wr_reg_indirect(ha, | ||
129 | QLA83XX_FLASH_DIRECT_WINDOW, | ||
130 | (addr & 0xFFFF0000)); | ||
131 | if (ret_val == QLA_ERROR) { | ||
132 | ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW\n!", | ||
133 | __func__, addr); | ||
134 | goto exit_flash_read; | ||
135 | } | ||
136 | |||
137 | ret_val = qla4_83xx_rd_reg_indirect(ha, | ||
138 | QLA83XX_FLASH_DIRECT_DATA(addr), | ||
139 | &u32_word); | ||
140 | if (ret_val == QLA_ERROR) { | ||
141 | ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n", | ||
142 | __func__, addr); | ||
143 | goto exit_flash_read; | ||
144 | } | ||
145 | |||
146 | *(__le32 *)p_data = le32_to_cpu(u32_word); | ||
147 | p_data = p_data + 4; | ||
148 | addr = addr + 4; | ||
149 | } | ||
150 | |||
151 | exit_flash_read: | ||
152 | qla4_83xx_flash_unlock(ha); | ||
153 | |||
154 | exit_lock_error: | ||
155 | return ret_val; | ||
156 | } | ||
157 | |||
158 | int qla4_83xx_lockless_flash_read_u32(struct scsi_qla_host *ha, | ||
159 | uint32_t flash_addr, uint8_t *p_data, | ||
160 | int u32_word_count) | ||
161 | { | ||
162 | uint32_t i; | ||
163 | uint32_t u32_word; | ||
164 | uint32_t flash_offset; | ||
165 | uint32_t addr = flash_addr; | ||
166 | int ret_val = QLA_SUCCESS; | ||
167 | |||
168 | flash_offset = addr & (QLA83XX_FLASH_SECTOR_SIZE - 1); | ||
169 | |||
170 | if (addr & 0x3) { | ||
171 | ql4_printk(KERN_ERR, ha, "%s: Illegal addr = 0x%x\n", | ||
172 | __func__, addr); | ||
173 | ret_val = QLA_ERROR; | ||
174 | goto exit_lockless_read; | ||
175 | } | ||
176 | |||
177 | ret_val = qla4_83xx_wr_reg_indirect(ha, QLA83XX_FLASH_DIRECT_WINDOW, | ||
178 | addr); | ||
179 | if (ret_val == QLA_ERROR) { | ||
180 | ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n", | ||
181 | __func__, addr); | ||
182 | goto exit_lockless_read; | ||
183 | } | ||
184 | |||
185 | /* Check if data is spread across multiple sectors */ | ||
186 | if ((flash_offset + (u32_word_count * sizeof(uint32_t))) > | ||
187 | (QLA83XX_FLASH_SECTOR_SIZE - 1)) { | ||
188 | |||
189 | /* Multi sector read */ | ||
190 | for (i = 0; i < u32_word_count; i++) { | ||
191 | ret_val = qla4_83xx_rd_reg_indirect(ha, | ||
192 | QLA83XX_FLASH_DIRECT_DATA(addr), | ||
193 | &u32_word); | ||
194 | if (ret_val == QLA_ERROR) { | ||
195 | ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n", | ||
196 | __func__, addr); | ||
197 | goto exit_lockless_read; | ||
198 | } | ||
199 | |||
200 | *(__le32 *)p_data = le32_to_cpu(u32_word); | ||
201 | p_data = p_data + 4; | ||
202 | addr = addr + 4; | ||
203 | flash_offset = flash_offset + 4; | ||
204 | |||
205 | if (flash_offset > (QLA83XX_FLASH_SECTOR_SIZE - 1)) { | ||
206 | /* This write is needed once for each sector */ | ||
207 | ret_val = qla4_83xx_wr_reg_indirect(ha, | ||
208 | QLA83XX_FLASH_DIRECT_WINDOW, | ||
209 | addr); | ||
210 | if (ret_val == QLA_ERROR) { | ||
211 | ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n", | ||
212 | __func__, addr); | ||
213 | goto exit_lockless_read; | ||
214 | } | ||
215 | flash_offset = 0; | ||
216 | } | ||
217 | } | ||
218 | } else { | ||
219 | /* Single sector read */ | ||
220 | for (i = 0; i < u32_word_count; i++) { | ||
221 | ret_val = qla4_83xx_rd_reg_indirect(ha, | ||
222 | QLA83XX_FLASH_DIRECT_DATA(addr), | ||
223 | &u32_word); | ||
224 | if (ret_val == QLA_ERROR) { | ||
225 | ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n", | ||
226 | __func__, addr); | ||
227 | goto exit_lockless_read; | ||
228 | } | ||
229 | |||
230 | *(__le32 *)p_data = le32_to_cpu(u32_word); | ||
231 | p_data = p_data + 4; | ||
232 | addr = addr + 4; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | exit_lockless_read: | ||
237 | return ret_val; | ||
238 | } | ||
239 | |||
240 | void qla4_83xx_rom_lock_recovery(struct scsi_qla_host *ha) | ||
241 | { | ||
242 | if (qla4_83xx_flash_lock(ha)) | ||
243 | ql4_printk(KERN_INFO, ha, "%s: Resetting rom lock\n", __func__); | ||
244 | |||
245 | /* | ||
246 | * We got the lock, or someone else is holding the lock | ||
247 | * since we are restting, forcefully unlock | ||
248 | */ | ||
249 | qla4_83xx_flash_unlock(ha); | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * qla4_83xx_ms_mem_write_128b - Writes data to MS/off-chip memory | ||
254 | * @ha: Pointer to adapter structure | ||
255 | * @addr: Flash address to write to | ||
256 | * @data: Data to be written | ||
257 | * @count: word_count to be written | ||
258 | * | ||
259 | * Return: On success return QLA_SUCCESS | ||
260 | * On error return QLA_ERROR | ||
261 | **/ | ||
262 | static int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha, uint64_t addr, | ||
263 | uint32_t *data, uint32_t count) | ||
264 | { | ||
265 | int i, j; | ||
266 | uint32_t agt_ctrl; | ||
267 | unsigned long flags; | ||
268 | int ret_val = QLA_SUCCESS; | ||
269 | |||
270 | /* Only 128-bit aligned access */ | ||
271 | if (addr & 0xF) { | ||
272 | ret_val = QLA_ERROR; | ||
273 | goto exit_ms_mem_write; | ||
274 | } | ||
275 | |||
276 | write_lock_irqsave(&ha->hw_lock, flags); | ||
277 | |||
278 | /* Write address */ | ||
279 | ret_val = qla4_83xx_wr_reg_indirect(ha, MD_MIU_TEST_AGT_ADDR_HI, 0); | ||
280 | if (ret_val == QLA_ERROR) { | ||
281 | ql4_printk(KERN_ERR, ha, "%s: write to AGT_ADDR_HI failed\n", | ||
282 | __func__); | ||
283 | goto exit_ms_mem_write_unlock; | ||
284 | } | ||
285 | |||
286 | for (i = 0; i < count; i++, addr += 16) { | ||
287 | if (!((QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_QDR_NET, | ||
288 | QLA8XXX_ADDR_QDR_NET_MAX)) || | ||
289 | (QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_DDR_NET, | ||
290 | QLA8XXX_ADDR_DDR_NET_MAX)))) { | ||
291 | ret_val = QLA_ERROR; | ||
292 | goto exit_ms_mem_write_unlock; | ||
293 | } | ||
294 | |||
295 | ret_val = qla4_83xx_wr_reg_indirect(ha, MD_MIU_TEST_AGT_ADDR_LO, | ||
296 | addr); | ||
297 | /* Write data */ | ||
298 | ret_val |= qla4_83xx_wr_reg_indirect(ha, | ||
299 | MD_MIU_TEST_AGT_WRDATA_LO, | ||
300 | *data++); | ||
301 | ret_val |= qla4_83xx_wr_reg_indirect(ha, | ||
302 | MD_MIU_TEST_AGT_WRDATA_HI, | ||
303 | *data++); | ||
304 | ret_val |= qla4_83xx_wr_reg_indirect(ha, | ||
305 | MD_MIU_TEST_AGT_WRDATA_ULO, | ||
306 | *data++); | ||
307 | ret_val |= qla4_83xx_wr_reg_indirect(ha, | ||
308 | MD_MIU_TEST_AGT_WRDATA_UHI, | ||
309 | *data++); | ||
310 | if (ret_val == QLA_ERROR) { | ||
311 | ql4_printk(KERN_ERR, ha, "%s: write to AGT_WRDATA failed\n", | ||
312 | __func__); | ||
313 | goto exit_ms_mem_write_unlock; | ||
314 | } | ||
315 | |||
316 | /* Check write status */ | ||
317 | ret_val = qla4_83xx_wr_reg_indirect(ha, MD_MIU_TEST_AGT_CTRL, | ||
318 | MIU_TA_CTL_WRITE_ENABLE); | ||
319 | ret_val |= qla4_83xx_wr_reg_indirect(ha, MD_MIU_TEST_AGT_CTRL, | ||
320 | MIU_TA_CTL_WRITE_START); | ||
321 | if (ret_val == QLA_ERROR) { | ||
322 | ql4_printk(KERN_ERR, ha, "%s: write to AGT_CTRL failed\n", | ||
323 | __func__); | ||
324 | goto exit_ms_mem_write_unlock; | ||
325 | } | ||
326 | |||
327 | for (j = 0; j < MAX_CTL_CHECK; j++) { | ||
328 | ret_val = qla4_83xx_rd_reg_indirect(ha, | ||
329 | MD_MIU_TEST_AGT_CTRL, | ||
330 | &agt_ctrl); | ||
331 | if (ret_val == QLA_ERROR) { | ||
332 | ql4_printk(KERN_ERR, ha, "%s: failed to read MD_MIU_TEST_AGT_CTRL\n", | ||
333 | __func__); | ||
334 | goto exit_ms_mem_write_unlock; | ||
335 | } | ||
336 | if ((agt_ctrl & MIU_TA_CTL_BUSY) == 0) | ||
337 | break; | ||
338 | } | ||
339 | |||
340 | /* Status check failed */ | ||
341 | if (j >= MAX_CTL_CHECK) { | ||
342 | printk_ratelimited(KERN_ERR "%s: MS memory write failed!\n", | ||
343 | __func__); | ||
344 | ret_val = QLA_ERROR; | ||
345 | goto exit_ms_mem_write_unlock; | ||
346 | } | ||
347 | } | ||
348 | |||
349 | exit_ms_mem_write_unlock: | ||
350 | write_unlock_irqrestore(&ha->hw_lock, flags); | ||
351 | |||
352 | exit_ms_mem_write: | ||
353 | return ret_val; | ||
354 | } | ||
355 | |||
356 | #define INTENT_TO_RECOVER 0x01 | ||
357 | #define PROCEED_TO_RECOVER 0x02 | ||
358 | |||
359 | static int qla4_83xx_lock_recovery(struct scsi_qla_host *ha) | ||
360 | { | ||
361 | |||
362 | uint32_t lock = 0, lockid; | ||
363 | int ret_val = QLA_ERROR; | ||
364 | |||
365 | lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY); | ||
366 | |||
367 | /* Check for other Recovery in progress, go wait */ | ||
368 | if ((lockid & 0x3) != 0) | ||
369 | goto exit_lock_recovery; | ||
370 | |||
371 | /* Intent to Recover */ | ||
372 | ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY, | ||
373 | (ha->func_num << 2) | INTENT_TO_RECOVER); | ||
374 | |||
375 | msleep(200); | ||
376 | |||
377 | /* Check Intent to Recover is advertised */ | ||
378 | lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY); | ||
379 | if ((lockid & 0x3C) != (ha->func_num << 2)) | ||
380 | goto exit_lock_recovery; | ||
381 | |||
382 | ql4_printk(KERN_INFO, ha, "%s: IDC Lock recovery initiated for func %d\n", | ||
383 | __func__, ha->func_num); | ||
384 | |||
385 | /* Proceed to Recover */ | ||
386 | ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY, | ||
387 | (ha->func_num << 2) | PROCEED_TO_RECOVER); | ||
388 | |||
389 | /* Force Unlock */ | ||
390 | ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCK_ID, 0xFF); | ||
391 | ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_UNLOCK); | ||
392 | |||
393 | /* Clear bits 0-5 in IDC_RECOVERY register*/ | ||
394 | ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY, 0); | ||
395 | |||
396 | /* Get lock */ | ||
397 | lock = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCK); | ||
398 | if (lock) { | ||
399 | lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCK_ID); | ||
400 | lockid = ((lockid + (1 << 8)) & ~0xFF) | ha->func_num; | ||
401 | ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCK_ID, lockid); | ||
402 | ret_val = QLA_SUCCESS; | ||
403 | } | ||
404 | |||
405 | exit_lock_recovery: | ||
406 | return ret_val; | ||
407 | } | ||
408 | |||
409 | #define QLA83XX_DRV_LOCK_MSLEEP 200 | ||
410 | |||
411 | int qla4_83xx_drv_lock(struct scsi_qla_host *ha) | ||
412 | { | ||
413 | int timeout = 0; | ||
414 | uint32_t status = 0; | ||
415 | int ret_val = QLA_SUCCESS; | ||
416 | uint32_t first_owner = 0; | ||
417 | uint32_t tmo_owner = 0; | ||
418 | uint32_t lock_id; | ||
419 | uint32_t func_num; | ||
420 | uint32_t lock_cnt; | ||
421 | |||
422 | while (status == 0) { | ||
423 | status = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK); | ||
424 | if (status) { | ||
425 | /* Increment Counter (8-31) and update func_num (0-7) on | ||
426 | * getting a successful lock */ | ||
427 | lock_id = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID); | ||
428 | lock_id = ((lock_id + (1 << 8)) & ~0xFF) | ha->func_num; | ||
429 | qla4_83xx_wr_reg(ha, QLA83XX_DRV_LOCK_ID, lock_id); | ||
430 | break; | ||
431 | } | ||
432 | |||
433 | if (timeout == 0) | ||
434 | /* Save counter + ID of function holding the lock for | ||
435 | * first failure */ | ||
436 | first_owner = ha->isp_ops->rd_reg_direct(ha, | ||
437 | QLA83XX_DRV_LOCK_ID); | ||
438 | |||
439 | if (++timeout >= | ||
440 | (QLA83XX_DRV_LOCK_TIMEOUT / QLA83XX_DRV_LOCK_MSLEEP)) { | ||
441 | tmo_owner = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID); | ||
442 | func_num = tmo_owner & 0xFF; | ||
443 | lock_cnt = tmo_owner >> 8; | ||
444 | ql4_printk(KERN_INFO, ha, "%s: Lock by func %d failed after 2s, lock held by func %d, lock count %d, first_owner %d\n", | ||
445 | __func__, ha->func_num, func_num, lock_cnt, | ||
446 | (first_owner & 0xFF)); | ||
447 | |||
448 | if (first_owner != tmo_owner) { | ||
449 | /* Some other driver got lock, OR same driver | ||
450 | * got lock again (counter value changed), when | ||
451 | * we were waiting for lock. | ||
452 | * Retry for another 2 sec */ | ||
453 | ql4_printk(KERN_INFO, ha, "%s: IDC lock failed for func %d\n", | ||
454 | __func__, ha->func_num); | ||
455 | timeout = 0; | ||
456 | } else { | ||
457 | /* Same driver holding lock > 2sec. | ||
458 | * Force Recovery */ | ||
459 | ret_val = qla4_83xx_lock_recovery(ha); | ||
460 | if (ret_val == QLA_SUCCESS) { | ||
461 | /* Recovered and got lock */ | ||
462 | ql4_printk(KERN_INFO, ha, "%s: IDC lock Recovery by %d successful\n", | ||
463 | __func__, ha->func_num); | ||
464 | break; | ||
465 | } | ||
466 | /* Recovery Failed, some other function | ||
467 | * has the lock, wait for 2secs and retry */ | ||
468 | ql4_printk(KERN_INFO, ha, "%s: IDC lock Recovery by %d failed, Retrying timout\n", | ||
469 | __func__, ha->func_num); | ||
470 | timeout = 0; | ||
471 | } | ||
472 | } | ||
473 | msleep(QLA83XX_DRV_LOCK_MSLEEP); | ||
474 | } | ||
475 | |||
476 | return ret_val; | ||
477 | } | ||
478 | |||
479 | void qla4_83xx_drv_unlock(struct scsi_qla_host *ha) | ||
480 | { | ||
481 | int id; | ||
482 | |||
483 | id = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID); | ||
484 | |||
485 | if ((id & 0xFF) != ha->func_num) { | ||
486 | ql4_printk(KERN_ERR, ha, "%s: IDC Unlock by %d failed, lock owner is %d\n", | ||
487 | __func__, ha->func_num, (id & 0xFF)); | ||
488 | return; | ||
489 | } | ||
490 | |||
491 | /* Keep lock counter value, update the ha->func_num to 0xFF */ | ||
492 | qla4_83xx_wr_reg(ha, QLA83XX_DRV_LOCK_ID, (id | 0xFF)); | ||
493 | qla4_83xx_rd_reg(ha, QLA83XX_DRV_UNLOCK); | ||
494 | } | ||
495 | |||
496 | void qla4_83xx_set_idc_dontreset(struct scsi_qla_host *ha) | ||
497 | { | ||
498 | uint32_t idc_ctrl; | ||
499 | |||
500 | idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL); | ||
501 | idc_ctrl |= DONTRESET_BIT0; | ||
502 | qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, idc_ctrl); | ||
503 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: idc_ctrl = %d\n", __func__, | ||
504 | idc_ctrl)); | ||
505 | } | ||
506 | |||
507 | void qla4_83xx_clear_idc_dontreset(struct scsi_qla_host *ha) | ||
508 | { | ||
509 | uint32_t idc_ctrl; | ||
510 | |||
511 | idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL); | ||
512 | idc_ctrl &= ~DONTRESET_BIT0; | ||
513 | qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, idc_ctrl); | ||
514 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: idc_ctrl = %d\n", __func__, | ||
515 | idc_ctrl)); | ||
516 | } | ||
517 | |||
518 | int qla4_83xx_idc_dontreset(struct scsi_qla_host *ha) | ||
519 | { | ||
520 | uint32_t idc_ctrl; | ||
521 | |||
522 | idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL); | ||
523 | return idc_ctrl & DONTRESET_BIT0; | ||
524 | } | ||
525 | |||
526 | /*-------------------------IDC State Machine ---------------------*/ | ||
527 | |||
528 | enum { | ||
529 | UNKNOWN_CLASS = 0, | ||
530 | NIC_CLASS, | ||
531 | FCOE_CLASS, | ||
532 | ISCSI_CLASS | ||
533 | }; | ||
534 | |||
535 | struct device_info { | ||
536 | int func_num; | ||
537 | int device_type; | ||
538 | int port_num; | ||
539 | }; | ||
540 | |||
541 | static int qla4_83xx_can_perform_reset(struct scsi_qla_host *ha) | ||
542 | { | ||
543 | uint32_t drv_active; | ||
544 | uint32_t dev_part, dev_part1, dev_part2; | ||
545 | int i; | ||
546 | struct device_info device_map[16]; | ||
547 | int func_nibble; | ||
548 | int nibble; | ||
549 | int nic_present = 0; | ||
550 | int iscsi_present = 0; | ||
551 | int iscsi_func_low = 0; | ||
552 | |||
553 | /* Use the dev_partition register to determine the PCI function number | ||
554 | * and then check drv_active register to see which driver is loaded */ | ||
555 | dev_part1 = qla4_83xx_rd_reg(ha, | ||
556 | ha->reg_tbl[QLA8XXX_CRB_DEV_PART_INFO]); | ||
557 | dev_part2 = qla4_83xx_rd_reg(ha, QLA83XX_CRB_DEV_PART_INFO2); | ||
558 | drv_active = qla4_83xx_rd_reg(ha, ha->reg_tbl[QLA8XXX_CRB_DRV_ACTIVE]); | ||
559 | |||
560 | /* Each function has 4 bits in dev_partition Info register, | ||
561 | * Lower 2 bits - device type, Upper 2 bits - physical port number */ | ||
562 | dev_part = dev_part1; | ||
563 | for (i = nibble = 0; i <= 15; i++, nibble++) { | ||
564 | func_nibble = dev_part & (0xF << (nibble * 4)); | ||
565 | func_nibble >>= (nibble * 4); | ||
566 | device_map[i].func_num = i; | ||
567 | device_map[i].device_type = func_nibble & 0x3; | ||
568 | device_map[i].port_num = func_nibble & 0xC; | ||
569 | |||
570 | if (device_map[i].device_type == NIC_CLASS) { | ||
571 | if (drv_active & (1 << device_map[i].func_num)) { | ||
572 | nic_present++; | ||
573 | break; | ||
574 | } | ||
575 | } else if (device_map[i].device_type == ISCSI_CLASS) { | ||
576 | if (drv_active & (1 << device_map[i].func_num)) { | ||
577 | if (!iscsi_present || | ||
578 | (iscsi_present && | ||
579 | (iscsi_func_low > device_map[i].func_num))) | ||
580 | iscsi_func_low = device_map[i].func_num; | ||
581 | |||
582 | iscsi_present++; | ||
583 | } | ||
584 | } | ||
585 | |||
586 | /* For function_num[8..15] get info from dev_part2 register */ | ||
587 | if (nibble == 7) { | ||
588 | nibble = 0; | ||
589 | dev_part = dev_part2; | ||
590 | } | ||
591 | } | ||
592 | |||
593 | /* NIC, iSCSI and FCOE are the Reset owners based on order, NIC gets | ||
594 | * precedence over iSCSI and FCOE and iSCSI over FCOE, based on drivers | ||
595 | * present. */ | ||
596 | if (!nic_present && (ha->func_num == iscsi_func_low)) { | ||
597 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
598 | "%s: can reset - NIC not present and lower iSCSI function is %d\n", | ||
599 | __func__, ha->func_num)); | ||
600 | return 1; | ||
601 | } | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | /** | ||
607 | * qla4_83xx_need_reset_handler - Code to start reset sequence | ||
608 | * @ha: pointer to adapter structure | ||
609 | * | ||
610 | * Note: IDC lock must be held upon entry | ||
611 | **/ | ||
612 | void qla4_83xx_need_reset_handler(struct scsi_qla_host *ha) | ||
613 | { | ||
614 | uint32_t dev_state, drv_state, drv_active; | ||
615 | unsigned long reset_timeout, dev_init_timeout; | ||
616 | |||
617 | ql4_printk(KERN_INFO, ha, "%s: Performing ISP error recovery\n", | ||
618 | __func__); | ||
619 | |||
620 | if (!test_bit(AF_8XXX_RST_OWNER, &ha->flags)) { | ||
621 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: reset acknowledged\n", | ||
622 | __func__)); | ||
623 | qla4_8xxx_set_rst_ready(ha); | ||
624 | |||
625 | /* Non-reset owners ACK Reset and wait for device INIT state | ||
626 | * as part of Reset Recovery by Reset Owner */ | ||
627 | dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); | ||
628 | |||
629 | do { | ||
630 | if (time_after_eq(jiffies, dev_init_timeout)) { | ||
631 | ql4_printk(KERN_INFO, ha, "%s: Non Reset owner dev init timeout\n", | ||
632 | __func__); | ||
633 | break; | ||
634 | } | ||
635 | |||
636 | ha->isp_ops->idc_unlock(ha); | ||
637 | msleep(1000); | ||
638 | ha->isp_ops->idc_lock(ha); | ||
639 | |||
640 | dev_state = qla4_8xxx_rd_direct(ha, | ||
641 | QLA8XXX_CRB_DEV_STATE); | ||
642 | } while (dev_state == QLA8XXX_DEV_NEED_RESET); | ||
643 | } else { | ||
644 | qla4_8xxx_set_rst_ready(ha); | ||
645 | reset_timeout = jiffies + (ha->nx_reset_timeout * HZ); | ||
646 | drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE); | ||
647 | drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE); | ||
648 | |||
649 | ql4_printk(KERN_INFO, ha, "%s: drv_state = 0x%x, drv_active = 0x%x\n", | ||
650 | __func__, drv_state, drv_active); | ||
651 | |||
652 | while (drv_state != drv_active) { | ||
653 | if (time_after_eq(jiffies, reset_timeout)) { | ||
654 | ql4_printk(KERN_INFO, ha, "%s: %s: RESET TIMEOUT! drv_state: 0x%08x, drv_active: 0x%08x\n", | ||
655 | __func__, DRIVER_NAME, drv_state, | ||
656 | drv_active); | ||
657 | break; | ||
658 | } | ||
659 | |||
660 | ha->isp_ops->idc_unlock(ha); | ||
661 | msleep(1000); | ||
662 | ha->isp_ops->idc_lock(ha); | ||
663 | |||
664 | drv_state = qla4_8xxx_rd_direct(ha, | ||
665 | QLA8XXX_CRB_DRV_STATE); | ||
666 | drv_active = qla4_8xxx_rd_direct(ha, | ||
667 | QLA8XXX_CRB_DRV_ACTIVE); | ||
668 | } | ||
669 | |||
670 | if (drv_state != drv_active) { | ||
671 | ql4_printk(KERN_INFO, ha, "%s: Reset_owner turning off drv_active of non-acking function 0x%x\n", | ||
672 | __func__, (drv_active ^ drv_state)); | ||
673 | drv_active = drv_active & drv_state; | ||
674 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE, | ||
675 | drv_active); | ||
676 | } | ||
677 | |||
678 | clear_bit(AF_8XXX_RST_OWNER, &ha->flags); | ||
679 | /* Start Reset Recovery */ | ||
680 | qla4_8xxx_device_bootstrap(ha); | ||
681 | } | ||
682 | } | ||
683 | |||
684 | void qla4_83xx_get_idc_param(struct scsi_qla_host *ha) | ||
685 | { | ||
686 | uint32_t idc_params, ret_val; | ||
687 | |||
688 | ret_val = qla4_83xx_flash_read_u32(ha, QLA83XX_IDC_PARAM_ADDR, | ||
689 | (uint8_t *)&idc_params, 1); | ||
690 | if (ret_val == QLA_SUCCESS) { | ||
691 | ha->nx_dev_init_timeout = idc_params & 0xFFFF; | ||
692 | ha->nx_reset_timeout = (idc_params >> 16) & 0xFFFF; | ||
693 | } else { | ||
694 | ha->nx_dev_init_timeout = ROM_DEV_INIT_TIMEOUT; | ||
695 | ha->nx_reset_timeout = ROM_DRV_RESET_ACK_TIMEOUT; | ||
696 | } | ||
697 | |||
698 | DEBUG2(ql4_printk(KERN_DEBUG, ha, | ||
699 | "%s: ha->nx_dev_init_timeout = %d, ha->nx_reset_timeout = %d\n", | ||
700 | __func__, ha->nx_dev_init_timeout, | ||
701 | ha->nx_reset_timeout)); | ||
702 | } | ||
703 | |||
704 | /*-------------------------Reset Sequence Functions-----------------------*/ | ||
705 | |||
706 | static void qla4_83xx_dump_reset_seq_hdr(struct scsi_qla_host *ha) | ||
707 | { | ||
708 | uint8_t *phdr; | ||
709 | |||
710 | if (!ha->reset_tmplt.buff) { | ||
711 | ql4_printk(KERN_ERR, ha, "%s: Error: Invalid reset_seq_template\n", | ||
712 | __func__); | ||
713 | return; | ||
714 | } | ||
715 | |||
716 | phdr = ha->reset_tmplt.buff; | ||
717 | |||
718 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
719 | "Reset Template: 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n", | ||
720 | *phdr, *(phdr+1), *(phdr+2), *(phdr+3), *(phdr+4), | ||
721 | *(phdr+5), *(phdr+6), *(phdr+7), *(phdr + 8), | ||
722 | *(phdr+9), *(phdr+10), *(phdr+11), *(phdr+12), | ||
723 | *(phdr+13), *(phdr+14), *(phdr+15))); | ||
724 | } | ||
725 | |||
726 | static int qla4_83xx_copy_bootloader(struct scsi_qla_host *ha) | ||
727 | { | ||
728 | uint8_t *p_cache; | ||
729 | uint32_t src, count, size; | ||
730 | uint64_t dest; | ||
731 | int ret_val = QLA_SUCCESS; | ||
732 | |||
733 | src = QLA83XX_BOOTLOADER_FLASH_ADDR; | ||
734 | dest = qla4_83xx_rd_reg(ha, QLA83XX_BOOTLOADER_ADDR); | ||
735 | size = qla4_83xx_rd_reg(ha, QLA83XX_BOOTLOADER_SIZE); | ||
736 | |||
737 | /* 128 bit alignment check */ | ||
738 | if (size & 0xF) | ||
739 | size = (size + 16) & ~0xF; | ||
740 | |||
741 | /* 16 byte count */ | ||
742 | count = size/16; | ||
743 | |||
744 | p_cache = vmalloc(size); | ||
745 | if (p_cache == NULL) { | ||
746 | ql4_printk(KERN_ERR, ha, "%s: Failed to allocate memory for boot loader cache\n", | ||
747 | __func__); | ||
748 | ret_val = QLA_ERROR; | ||
749 | goto exit_copy_bootloader; | ||
750 | } | ||
751 | |||
752 | ret_val = qla4_83xx_lockless_flash_read_u32(ha, src, p_cache, | ||
753 | size / sizeof(uint32_t)); | ||
754 | if (ret_val == QLA_ERROR) { | ||
755 | ql4_printk(KERN_ERR, ha, "%s: Error reading firmware from flash\n", | ||
756 | __func__); | ||
757 | goto exit_copy_error; | ||
758 | } | ||
759 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Read firmware from flash\n", | ||
760 | __func__)); | ||
761 | |||
762 | /* 128 bit/16 byte write to MS memory */ | ||
763 | ret_val = qla4_83xx_ms_mem_write_128b(ha, dest, (uint32_t *)p_cache, | ||
764 | count); | ||
765 | if (ret_val == QLA_ERROR) { | ||
766 | ql4_printk(KERN_ERR, ha, "%s: Error writing firmware to MS\n", | ||
767 | __func__); | ||
768 | goto exit_copy_error; | ||
769 | } | ||
770 | |||
771 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Wrote firmware size %d to MS\n", | ||
772 | __func__, size)); | ||
773 | |||
774 | exit_copy_error: | ||
775 | vfree(p_cache); | ||
776 | |||
777 | exit_copy_bootloader: | ||
778 | return ret_val; | ||
779 | } | ||
780 | |||
781 | static int qla4_83xx_check_cmd_peg_status(struct scsi_qla_host *ha) | ||
782 | { | ||
783 | uint32_t val, ret_val = QLA_ERROR; | ||
784 | int retries = CRB_CMDPEG_CHECK_RETRY_COUNT; | ||
785 | |||
786 | do { | ||
787 | val = qla4_83xx_rd_reg(ha, QLA83XX_CMDPEG_STATE); | ||
788 | if (val == PHAN_INITIALIZE_COMPLETE) { | ||
789 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
790 | "%s: Command Peg initialization complete. State=0x%x\n", | ||
791 | __func__, val)); | ||
792 | ret_val = QLA_SUCCESS; | ||
793 | break; | ||
794 | } | ||
795 | msleep(CRB_CMDPEG_CHECK_DELAY); | ||
796 | } while (--retries); | ||
797 | |||
798 | return ret_val; | ||
799 | } | ||
800 | |||
801 | /** | ||
802 | * qla4_83xx_poll_reg - Poll the given CRB addr for duration msecs till | ||
803 | * value read ANDed with test_mask is equal to test_result. | ||
804 | * | ||
805 | * @ha : Pointer to adapter structure | ||
806 | * @addr : CRB register address | ||
807 | * @duration : Poll for total of "duration" msecs | ||
808 | * @test_mask : Mask value read with "test_mask" | ||
809 | * @test_result : Compare (value&test_mask) with test_result. | ||
810 | **/ | ||
811 | static int qla4_83xx_poll_reg(struct scsi_qla_host *ha, uint32_t addr, | ||
812 | int duration, uint32_t test_mask, | ||
813 | uint32_t test_result) | ||
814 | { | ||
815 | uint32_t value; | ||
816 | uint8_t retries; | ||
817 | int ret_val = QLA_SUCCESS; | ||
818 | |||
819 | ret_val = qla4_83xx_rd_reg_indirect(ha, addr, &value); | ||
820 | if (ret_val == QLA_ERROR) | ||
821 | goto exit_poll_reg; | ||
822 | |||
823 | retries = duration / 10; | ||
824 | do { | ||
825 | if ((value & test_mask) != test_result) { | ||
826 | msleep(duration / 10); | ||
827 | ret_val = qla4_83xx_rd_reg_indirect(ha, addr, &value); | ||
828 | if (ret_val == QLA_ERROR) | ||
829 | goto exit_poll_reg; | ||
830 | |||
831 | ret_val = QLA_ERROR; | ||
832 | } else { | ||
833 | ret_val = QLA_SUCCESS; | ||
834 | break; | ||
835 | } | ||
836 | } while (retries--); | ||
837 | |||
838 | exit_poll_reg: | ||
839 | if (ret_val == QLA_ERROR) { | ||
840 | ha->reset_tmplt.seq_error++; | ||
841 | ql4_printk(KERN_ERR, ha, "%s: Poll Failed: 0x%08x 0x%08x 0x%08x\n", | ||
842 | __func__, value, test_mask, test_result); | ||
843 | } | ||
844 | |||
845 | return ret_val; | ||
846 | } | ||
847 | |||
848 | static int qla4_83xx_reset_seq_checksum_test(struct scsi_qla_host *ha) | ||
849 | { | ||
850 | uint32_t sum = 0; | ||
851 | uint16_t *buff = (uint16_t *)ha->reset_tmplt.buff; | ||
852 | int u16_count = ha->reset_tmplt.hdr->size / sizeof(uint16_t); | ||
853 | int ret_val; | ||
854 | |||
855 | while (u16_count-- > 0) | ||
856 | sum += *buff++; | ||
857 | |||
858 | while (sum >> 16) | ||
859 | sum = (sum & 0xFFFF) + (sum >> 16); | ||
860 | |||
861 | /* checksum of 0 indicates a valid template */ | ||
862 | if (~sum) { | ||
863 | ret_val = QLA_SUCCESS; | ||
864 | } else { | ||
865 | ql4_printk(KERN_ERR, ha, "%s: Reset seq checksum failed\n", | ||
866 | __func__); | ||
867 | ret_val = QLA_ERROR; | ||
868 | } | ||
869 | |||
870 | return ret_val; | ||
871 | } | ||
872 | |||
873 | /** | ||
874 | * qla4_83xx_read_reset_template - Read Reset Template from Flash | ||
875 | * @ha: Pointer to adapter structure | ||
876 | **/ | ||
877 | void qla4_83xx_read_reset_template(struct scsi_qla_host *ha) | ||
878 | { | ||
879 | uint8_t *p_buff; | ||
880 | uint32_t addr, tmplt_hdr_def_size, tmplt_hdr_size; | ||
881 | uint32_t ret_val; | ||
882 | |||
883 | ha->reset_tmplt.seq_error = 0; | ||
884 | ha->reset_tmplt.buff = vmalloc(QLA83XX_RESTART_TEMPLATE_SIZE); | ||
885 | if (ha->reset_tmplt.buff == NULL) { | ||
886 | ql4_printk(KERN_ERR, ha, "%s: Failed to allocate reset template resources\n", | ||
887 | __func__); | ||
888 | goto exit_read_reset_template; | ||
889 | } | ||
890 | |||
891 | p_buff = ha->reset_tmplt.buff; | ||
892 | addr = QLA83XX_RESET_TEMPLATE_ADDR; | ||
893 | |||
894 | tmplt_hdr_def_size = sizeof(struct qla4_83xx_reset_template_hdr) / | ||
895 | sizeof(uint32_t); | ||
896 | |||
897 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
898 | "%s: Read template hdr size %d from Flash\n", | ||
899 | __func__, tmplt_hdr_def_size)); | ||
900 | |||
901 | /* Copy template header from flash */ | ||
902 | ret_val = qla4_83xx_flash_read_u32(ha, addr, p_buff, | ||
903 | tmplt_hdr_def_size); | ||
904 | if (ret_val != QLA_SUCCESS) { | ||
905 | ql4_printk(KERN_ERR, ha, "%s: Failed to read reset template\n", | ||
906 | __func__); | ||
907 | goto exit_read_template_error; | ||
908 | } | ||
909 | |||
910 | ha->reset_tmplt.hdr = | ||
911 | (struct qla4_83xx_reset_template_hdr *)ha->reset_tmplt.buff; | ||
912 | |||
913 | /* Validate the template header size and signature */ | ||
914 | tmplt_hdr_size = ha->reset_tmplt.hdr->hdr_size/sizeof(uint32_t); | ||
915 | if ((tmplt_hdr_size != tmplt_hdr_def_size) || | ||
916 | (ha->reset_tmplt.hdr->signature != RESET_TMPLT_HDR_SIGNATURE)) { | ||
917 | ql4_printk(KERN_ERR, ha, "%s: Template Header size %d is invalid, tmplt_hdr_def_size %d\n", | ||
918 | __func__, tmplt_hdr_size, tmplt_hdr_def_size); | ||
919 | goto exit_read_template_error; | ||
920 | } | ||
921 | |||
922 | addr = QLA83XX_RESET_TEMPLATE_ADDR + ha->reset_tmplt.hdr->hdr_size; | ||
923 | p_buff = ha->reset_tmplt.buff + ha->reset_tmplt.hdr->hdr_size; | ||
924 | tmplt_hdr_def_size = (ha->reset_tmplt.hdr->size - | ||
925 | ha->reset_tmplt.hdr->hdr_size) / sizeof(uint32_t); | ||
926 | |||
927 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
928 | "%s: Read rest of the template size %d\n", | ||
929 | __func__, ha->reset_tmplt.hdr->size)); | ||
930 | |||
931 | /* Copy rest of the template */ | ||
932 | ret_val = qla4_83xx_flash_read_u32(ha, addr, p_buff, | ||
933 | tmplt_hdr_def_size); | ||
934 | if (ret_val != QLA_SUCCESS) { | ||
935 | ql4_printk(KERN_ERR, ha, "%s: Failed to read reset tempelate\n", | ||
936 | __func__); | ||
937 | goto exit_read_template_error; | ||
938 | } | ||
939 | |||
940 | /* Integrity check */ | ||
941 | if (qla4_83xx_reset_seq_checksum_test(ha)) { | ||
942 | ql4_printk(KERN_ERR, ha, "%s: Reset Seq checksum failed!\n", | ||
943 | __func__); | ||
944 | goto exit_read_template_error; | ||
945 | } | ||
946 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
947 | "%s: Reset Seq checksum passed, Get stop, start and init seq offsets\n", | ||
948 | __func__)); | ||
949 | |||
950 | /* Get STOP, START, INIT sequence offsets */ | ||
951 | ha->reset_tmplt.init_offset = ha->reset_tmplt.buff + | ||
952 | ha->reset_tmplt.hdr->init_seq_offset; | ||
953 | ha->reset_tmplt.start_offset = ha->reset_tmplt.buff + | ||
954 | ha->reset_tmplt.hdr->start_seq_offset; | ||
955 | ha->reset_tmplt.stop_offset = ha->reset_tmplt.buff + | ||
956 | ha->reset_tmplt.hdr->hdr_size; | ||
957 | qla4_83xx_dump_reset_seq_hdr(ha); | ||
958 | |||
959 | goto exit_read_reset_template; | ||
960 | |||
961 | exit_read_template_error: | ||
962 | vfree(ha->reset_tmplt.buff); | ||
963 | |||
964 | exit_read_reset_template: | ||
965 | return; | ||
966 | } | ||
967 | |||
968 | /** | ||
969 | * qla4_83xx_read_write_crb_reg - Read from raddr and write value to waddr. | ||
970 | * | ||
971 | * @ha : Pointer to adapter structure | ||
972 | * @raddr : CRB address to read from | ||
973 | * @waddr : CRB address to write to | ||
974 | **/ | ||
975 | static void qla4_83xx_read_write_crb_reg(struct scsi_qla_host *ha, | ||
976 | uint32_t raddr, uint32_t waddr) | ||
977 | { | ||
978 | uint32_t value; | ||
979 | |||
980 | qla4_83xx_rd_reg_indirect(ha, raddr, &value); | ||
981 | qla4_83xx_wr_reg_indirect(ha, waddr, value); | ||
982 | } | ||
983 | |||
984 | /** | ||
985 | * qla4_83xx_rmw_crb_reg - Read Modify Write crb register | ||
986 | * | ||
987 | * This function read value from raddr, AND with test_mask, | ||
988 | * Shift Left,Right/OR/XOR with values RMW header and write value to waddr. | ||
989 | * | ||
990 | * @ha : Pointer to adapter structure | ||
991 | * @raddr : CRB address to read from | ||
992 | * @waddr : CRB address to write to | ||
993 | * @p_rmw_hdr : header with shift/or/xor values. | ||
994 | **/ | ||
995 | static void qla4_83xx_rmw_crb_reg(struct scsi_qla_host *ha, uint32_t raddr, | ||
996 | uint32_t waddr, | ||
997 | struct qla4_83xx_rmw *p_rmw_hdr) | ||
998 | { | ||
999 | uint32_t value; | ||
1000 | |||
1001 | if (p_rmw_hdr->index_a) | ||
1002 | value = ha->reset_tmplt.array[p_rmw_hdr->index_a]; | ||
1003 | else | ||
1004 | qla4_83xx_rd_reg_indirect(ha, raddr, &value); | ||
1005 | |||
1006 | value &= p_rmw_hdr->test_mask; | ||
1007 | value <<= p_rmw_hdr->shl; | ||
1008 | value >>= p_rmw_hdr->shr; | ||
1009 | value |= p_rmw_hdr->or_value; | ||
1010 | value ^= p_rmw_hdr->xor_value; | ||
1011 | |||
1012 | qla4_83xx_wr_reg_indirect(ha, waddr, value); | ||
1013 | |||
1014 | return; | ||
1015 | } | ||
1016 | |||
1017 | static void qla4_83xx_write_list(struct scsi_qla_host *ha, | ||
1018 | struct qla4_83xx_reset_entry_hdr *p_hdr) | ||
1019 | { | ||
1020 | struct qla4_83xx_entry *p_entry; | ||
1021 | uint32_t i; | ||
1022 | |||
1023 | p_entry = (struct qla4_83xx_entry *) | ||
1024 | ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr)); | ||
1025 | |||
1026 | for (i = 0; i < p_hdr->count; i++, p_entry++) { | ||
1027 | qla4_83xx_wr_reg_indirect(ha, p_entry->arg1, p_entry->arg2); | ||
1028 | if (p_hdr->delay) | ||
1029 | udelay((uint32_t)(p_hdr->delay)); | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | static void qla4_83xx_read_write_list(struct scsi_qla_host *ha, | ||
1034 | struct qla4_83xx_reset_entry_hdr *p_hdr) | ||
1035 | { | ||
1036 | struct qla4_83xx_entry *p_entry; | ||
1037 | uint32_t i; | ||
1038 | |||
1039 | p_entry = (struct qla4_83xx_entry *) | ||
1040 | ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr)); | ||
1041 | |||
1042 | for (i = 0; i < p_hdr->count; i++, p_entry++) { | ||
1043 | qla4_83xx_read_write_crb_reg(ha, p_entry->arg1, p_entry->arg2); | ||
1044 | if (p_hdr->delay) | ||
1045 | udelay((uint32_t)(p_hdr->delay)); | ||
1046 | } | ||
1047 | } | ||
1048 | |||
1049 | static void qla4_83xx_poll_list(struct scsi_qla_host *ha, | ||
1050 | struct qla4_83xx_reset_entry_hdr *p_hdr) | ||
1051 | { | ||
1052 | long delay; | ||
1053 | struct qla4_83xx_entry *p_entry; | ||
1054 | struct qla4_83xx_poll *p_poll; | ||
1055 | uint32_t i; | ||
1056 | uint32_t value; | ||
1057 | |||
1058 | p_poll = (struct qla4_83xx_poll *) | ||
1059 | ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr)); | ||
1060 | |||
1061 | /* Entries start after 8 byte qla4_83xx_poll, poll header contains | ||
1062 | * the test_mask, test_value. */ | ||
1063 | p_entry = (struct qla4_83xx_entry *)((char *)p_poll + | ||
1064 | sizeof(struct qla4_83xx_poll)); | ||
1065 | |||
1066 | delay = (long)p_hdr->delay; | ||
1067 | if (!delay) { | ||
1068 | for (i = 0; i < p_hdr->count; i++, p_entry++) { | ||
1069 | qla4_83xx_poll_reg(ha, p_entry->arg1, delay, | ||
1070 | p_poll->test_mask, | ||
1071 | p_poll->test_value); | ||
1072 | } | ||
1073 | } else { | ||
1074 | for (i = 0; i < p_hdr->count; i++, p_entry++) { | ||
1075 | if (qla4_83xx_poll_reg(ha, p_entry->arg1, delay, | ||
1076 | p_poll->test_mask, | ||
1077 | p_poll->test_value)) { | ||
1078 | qla4_83xx_rd_reg_indirect(ha, p_entry->arg1, | ||
1079 | &value); | ||
1080 | qla4_83xx_rd_reg_indirect(ha, p_entry->arg2, | ||
1081 | &value); | ||
1082 | } | ||
1083 | } | ||
1084 | } | ||
1085 | } | ||
1086 | |||
1087 | static void qla4_83xx_poll_write_list(struct scsi_qla_host *ha, | ||
1088 | struct qla4_83xx_reset_entry_hdr *p_hdr) | ||
1089 | { | ||
1090 | long delay; | ||
1091 | struct qla4_83xx_quad_entry *p_entry; | ||
1092 | struct qla4_83xx_poll *p_poll; | ||
1093 | uint32_t i; | ||
1094 | |||
1095 | p_poll = (struct qla4_83xx_poll *) | ||
1096 | ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr)); | ||
1097 | p_entry = (struct qla4_83xx_quad_entry *) | ||
1098 | ((char *)p_poll + sizeof(struct qla4_83xx_poll)); | ||
1099 | delay = (long)p_hdr->delay; | ||
1100 | |||
1101 | for (i = 0; i < p_hdr->count; i++, p_entry++) { | ||
1102 | qla4_83xx_wr_reg_indirect(ha, p_entry->dr_addr, | ||
1103 | p_entry->dr_value); | ||
1104 | qla4_83xx_wr_reg_indirect(ha, p_entry->ar_addr, | ||
1105 | p_entry->ar_value); | ||
1106 | if (delay) { | ||
1107 | if (qla4_83xx_poll_reg(ha, p_entry->ar_addr, delay, | ||
1108 | p_poll->test_mask, | ||
1109 | p_poll->test_value)) { | ||
1110 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
1111 | "%s: Timeout Error: poll list, item_num %d, entry_num %d\n", | ||
1112 | __func__, i, | ||
1113 | ha->reset_tmplt.seq_index)); | ||
1114 | } | ||
1115 | } | ||
1116 | } | ||
1117 | } | ||
1118 | |||
1119 | static void qla4_83xx_read_modify_write(struct scsi_qla_host *ha, | ||
1120 | struct qla4_83xx_reset_entry_hdr *p_hdr) | ||
1121 | { | ||
1122 | struct qla4_83xx_entry *p_entry; | ||
1123 | struct qla4_83xx_rmw *p_rmw_hdr; | ||
1124 | uint32_t i; | ||
1125 | |||
1126 | p_rmw_hdr = (struct qla4_83xx_rmw *) | ||
1127 | ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr)); | ||
1128 | p_entry = (struct qla4_83xx_entry *) | ||
1129 | ((char *)p_rmw_hdr + sizeof(struct qla4_83xx_rmw)); | ||
1130 | |||
1131 | for (i = 0; i < p_hdr->count; i++, p_entry++) { | ||
1132 | qla4_83xx_rmw_crb_reg(ha, p_entry->arg1, p_entry->arg2, | ||
1133 | p_rmw_hdr); | ||
1134 | if (p_hdr->delay) | ||
1135 | udelay((uint32_t)(p_hdr->delay)); | ||
1136 | } | ||
1137 | } | ||
1138 | |||
1139 | static void qla4_83xx_pause(struct scsi_qla_host *ha, | ||
1140 | struct qla4_83xx_reset_entry_hdr *p_hdr) | ||
1141 | { | ||
1142 | if (p_hdr->delay) | ||
1143 | mdelay((uint32_t)((long)p_hdr->delay)); | ||
1144 | } | ||
1145 | |||
1146 | static void qla4_83xx_poll_read_list(struct scsi_qla_host *ha, | ||
1147 | struct qla4_83xx_reset_entry_hdr *p_hdr) | ||
1148 | { | ||
1149 | long delay; | ||
1150 | int index; | ||
1151 | struct qla4_83xx_quad_entry *p_entry; | ||
1152 | struct qla4_83xx_poll *p_poll; | ||
1153 | uint32_t i; | ||
1154 | uint32_t value; | ||
1155 | |||
1156 | p_poll = (struct qla4_83xx_poll *) | ||
1157 | ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr)); | ||
1158 | p_entry = (struct qla4_83xx_quad_entry *) | ||
1159 | ((char *)p_poll + sizeof(struct qla4_83xx_poll)); | ||
1160 | delay = (long)p_hdr->delay; | ||
1161 | |||
1162 | for (i = 0; i < p_hdr->count; i++, p_entry++) { | ||
1163 | qla4_83xx_wr_reg_indirect(ha, p_entry->ar_addr, | ||
1164 | p_entry->ar_value); | ||
1165 | if (delay) { | ||
1166 | if (qla4_83xx_poll_reg(ha, p_entry->ar_addr, delay, | ||
1167 | p_poll->test_mask, | ||
1168 | p_poll->test_value)) { | ||
1169 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
1170 | "%s: Timeout Error: poll list, Item_num %d, entry_num %d\n", | ||
1171 | __func__, i, | ||
1172 | ha->reset_tmplt.seq_index)); | ||
1173 | } else { | ||
1174 | index = ha->reset_tmplt.array_index; | ||
1175 | qla4_83xx_rd_reg_indirect(ha, p_entry->dr_addr, | ||
1176 | &value); | ||
1177 | ha->reset_tmplt.array[index++] = value; | ||
1178 | |||
1179 | if (index == QLA83XX_MAX_RESET_SEQ_ENTRIES) | ||
1180 | ha->reset_tmplt.array_index = 1; | ||
1181 | } | ||
1182 | } | ||
1183 | } | ||
1184 | } | ||
1185 | |||
1186 | static void qla4_83xx_seq_end(struct scsi_qla_host *ha, | ||
1187 | struct qla4_83xx_reset_entry_hdr *p_hdr) | ||
1188 | { | ||
1189 | ha->reset_tmplt.seq_end = 1; | ||
1190 | } | ||
1191 | |||
1192 | static void qla4_83xx_template_end(struct scsi_qla_host *ha, | ||
1193 | struct qla4_83xx_reset_entry_hdr *p_hdr) | ||
1194 | { | ||
1195 | ha->reset_tmplt.template_end = 1; | ||
1196 | |||
1197 | if (ha->reset_tmplt.seq_error == 0) { | ||
1198 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
1199 | "%s: Reset sequence completed SUCCESSFULLY.\n", | ||
1200 | __func__)); | ||
1201 | } else { | ||
1202 | ql4_printk(KERN_ERR, ha, "%s: Reset sequence completed with some timeout errors.\n", | ||
1203 | __func__); | ||
1204 | } | ||
1205 | } | ||
1206 | |||
1207 | /** | ||
1208 | * qla4_83xx_process_reset_template - Process reset template. | ||
1209 | * | ||
1210 | * Process all entries in reset template till entry with SEQ_END opcode, | ||
1211 | * which indicates end of the reset template processing. Each entry has a | ||
1212 | * Reset Entry header, entry opcode/command, with size of the entry, number | ||
1213 | * of entries in sub-sequence and delay in microsecs or timeout in millisecs. | ||
1214 | * | ||
1215 | * @ha : Pointer to adapter structure | ||
1216 | * @p_buff : Common reset entry header. | ||
1217 | **/ | ||
1218 | static void qla4_83xx_process_reset_template(struct scsi_qla_host *ha, | ||
1219 | char *p_buff) | ||
1220 | { | ||
1221 | int index, entries; | ||
1222 | struct qla4_83xx_reset_entry_hdr *p_hdr; | ||
1223 | char *p_entry = p_buff; | ||
1224 | |||
1225 | ha->reset_tmplt.seq_end = 0; | ||
1226 | ha->reset_tmplt.template_end = 0; | ||
1227 | entries = ha->reset_tmplt.hdr->entries; | ||
1228 | index = ha->reset_tmplt.seq_index; | ||
1229 | |||
1230 | for (; (!ha->reset_tmplt.seq_end) && (index < entries); index++) { | ||
1231 | |||
1232 | p_hdr = (struct qla4_83xx_reset_entry_hdr *)p_entry; | ||
1233 | switch (p_hdr->cmd) { | ||
1234 | case OPCODE_NOP: | ||
1235 | break; | ||
1236 | case OPCODE_WRITE_LIST: | ||
1237 | qla4_83xx_write_list(ha, p_hdr); | ||
1238 | break; | ||
1239 | case OPCODE_READ_WRITE_LIST: | ||
1240 | qla4_83xx_read_write_list(ha, p_hdr); | ||
1241 | break; | ||
1242 | case OPCODE_POLL_LIST: | ||
1243 | qla4_83xx_poll_list(ha, p_hdr); | ||
1244 | break; | ||
1245 | case OPCODE_POLL_WRITE_LIST: | ||
1246 | qla4_83xx_poll_write_list(ha, p_hdr); | ||
1247 | break; | ||
1248 | case OPCODE_READ_MODIFY_WRITE: | ||
1249 | qla4_83xx_read_modify_write(ha, p_hdr); | ||
1250 | break; | ||
1251 | case OPCODE_SEQ_PAUSE: | ||
1252 | qla4_83xx_pause(ha, p_hdr); | ||
1253 | break; | ||
1254 | case OPCODE_SEQ_END: | ||
1255 | qla4_83xx_seq_end(ha, p_hdr); | ||
1256 | break; | ||
1257 | case OPCODE_TMPL_END: | ||
1258 | qla4_83xx_template_end(ha, p_hdr); | ||
1259 | break; | ||
1260 | case OPCODE_POLL_READ_LIST: | ||
1261 | qla4_83xx_poll_read_list(ha, p_hdr); | ||
1262 | break; | ||
1263 | default: | ||
1264 | ql4_printk(KERN_ERR, ha, "%s: Unknown command ==> 0x%04x on entry = %d\n", | ||
1265 | __func__, p_hdr->cmd, index); | ||
1266 | break; | ||
1267 | } | ||
1268 | |||
1269 | /* Set pointer to next entry in the sequence. */ | ||
1270 | p_entry += p_hdr->size; | ||
1271 | } | ||
1272 | |||
1273 | ha->reset_tmplt.seq_index = index; | ||
1274 | } | ||
1275 | |||
1276 | static void qla4_83xx_process_stop_seq(struct scsi_qla_host *ha) | ||
1277 | { | ||
1278 | ha->reset_tmplt.seq_index = 0; | ||
1279 | qla4_83xx_process_reset_template(ha, ha->reset_tmplt.stop_offset); | ||
1280 | |||
1281 | if (ha->reset_tmplt.seq_end != 1) | ||
1282 | ql4_printk(KERN_ERR, ha, "%s: Abrupt STOP Sub-Sequence end.\n", | ||
1283 | __func__); | ||
1284 | } | ||
1285 | |||
1286 | static void qla4_83xx_process_start_seq(struct scsi_qla_host *ha) | ||
1287 | { | ||
1288 | qla4_83xx_process_reset_template(ha, ha->reset_tmplt.start_offset); | ||
1289 | |||
1290 | if (ha->reset_tmplt.template_end != 1) | ||
1291 | ql4_printk(KERN_ERR, ha, "%s: Abrupt START Sub-Sequence end.\n", | ||
1292 | __func__); | ||
1293 | } | ||
1294 | |||
1295 | static void qla4_83xx_process_init_seq(struct scsi_qla_host *ha) | ||
1296 | { | ||
1297 | qla4_83xx_process_reset_template(ha, ha->reset_tmplt.init_offset); | ||
1298 | |||
1299 | if (ha->reset_tmplt.seq_end != 1) | ||
1300 | ql4_printk(KERN_ERR, ha, "%s: Abrupt INIT Sub-Sequence end.\n", | ||
1301 | __func__); | ||
1302 | } | ||
1303 | |||
1304 | static int qla4_83xx_restart(struct scsi_qla_host *ha) | ||
1305 | { | ||
1306 | int ret_val = QLA_SUCCESS; | ||
1307 | |||
1308 | qla4_83xx_process_stop_seq(ha); | ||
1309 | |||
1310 | /* Collect minidump*/ | ||
1311 | if (!test_and_clear_bit(AF_83XX_NO_FW_DUMP, &ha->flags)) | ||
1312 | qla4_8xxx_get_minidump(ha); | ||
1313 | |||
1314 | qla4_83xx_process_init_seq(ha); | ||
1315 | |||
1316 | if (qla4_83xx_copy_bootloader(ha)) { | ||
1317 | ql4_printk(KERN_ERR, ha, "%s: Copy bootloader, firmware restart failed!\n", | ||
1318 | __func__); | ||
1319 | ret_val = QLA_ERROR; | ||
1320 | goto exit_restart; | ||
1321 | } | ||
1322 | |||
1323 | qla4_83xx_wr_reg(ha, QLA83XX_FW_IMAGE_VALID, QLA83XX_BOOT_FROM_FLASH); | ||
1324 | qla4_83xx_process_start_seq(ha); | ||
1325 | |||
1326 | exit_restart: | ||
1327 | return ret_val; | ||
1328 | } | ||
1329 | |||
1330 | int qla4_83xx_start_firmware(struct scsi_qla_host *ha) | ||
1331 | { | ||
1332 | int ret_val = QLA_SUCCESS; | ||
1333 | |||
1334 | ret_val = qla4_83xx_restart(ha); | ||
1335 | if (ret_val == QLA_ERROR) { | ||
1336 | ql4_printk(KERN_ERR, ha, "%s: Restart error\n", __func__); | ||
1337 | goto exit_start_fw; | ||
1338 | } else { | ||
1339 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Restart done\n", | ||
1340 | __func__)); | ||
1341 | } | ||
1342 | |||
1343 | ret_val = qla4_83xx_check_cmd_peg_status(ha); | ||
1344 | if (ret_val == QLA_ERROR) | ||
1345 | ql4_printk(KERN_ERR, ha, "%s: Peg not initialized\n", | ||
1346 | __func__); | ||
1347 | |||
1348 | exit_start_fw: | ||
1349 | return ret_val; | ||
1350 | } | ||
1351 | |||
1352 | /*----------------------Interrupt Related functions ---------------------*/ | ||
1353 | |||
1354 | void qla4_83xx_disable_intrs(struct scsi_qla_host *ha) | ||
1355 | { | ||
1356 | uint32_t mb_int, ret; | ||
1357 | |||
1358 | if (test_and_clear_bit(AF_INTERRUPTS_ON, &ha->flags)) | ||
1359 | qla4_8xxx_mbx_intr_disable(ha); | ||
1360 | |||
1361 | ret = readl(&ha->qla4_83xx_reg->mbox_int); | ||
1362 | mb_int = ret & ~INT_ENABLE_FW_MB; | ||
1363 | writel(mb_int, &ha->qla4_83xx_reg->mbox_int); | ||
1364 | writel(1, &ha->qla4_83xx_reg->leg_int_mask); | ||
1365 | } | ||
1366 | |||
1367 | void qla4_83xx_enable_intrs(struct scsi_qla_host *ha) | ||
1368 | { | ||
1369 | uint32_t mb_int; | ||
1370 | |||
1371 | qla4_8xxx_mbx_intr_enable(ha); | ||
1372 | mb_int = INT_ENABLE_FW_MB; | ||
1373 | writel(mb_int, &ha->qla4_83xx_reg->mbox_int); | ||
1374 | writel(0, &ha->qla4_83xx_reg->leg_int_mask); | ||
1375 | |||
1376 | set_bit(AF_INTERRUPTS_ON, &ha->flags); | ||
1377 | } | ||
1378 | |||
1379 | void qla4_83xx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd, | ||
1380 | int incount) | ||
1381 | { | ||
1382 | int i; | ||
1383 | |||
1384 | /* Load all mailbox registers, except mailbox 0. */ | ||
1385 | for (i = 1; i < incount; i++) | ||
1386 | writel(mbx_cmd[i], &ha->qla4_83xx_reg->mailbox_in[i]); | ||
1387 | |||
1388 | writel(mbx_cmd[0], &ha->qla4_83xx_reg->mailbox_in[0]); | ||
1389 | |||
1390 | /* Set Host Interrupt register to 1, to tell the firmware that | ||
1391 | * a mailbox command is pending. Firmware after reading the | ||
1392 | * mailbox command, clears the host interrupt register */ | ||
1393 | writel(HINT_MBX_INT_PENDING, &ha->qla4_83xx_reg->host_intr); | ||
1394 | } | ||
1395 | |||
1396 | void qla4_83xx_process_mbox_intr(struct scsi_qla_host *ha, int outcount) | ||
1397 | { | ||
1398 | int intr_status; | ||
1399 | |||
1400 | intr_status = readl(&ha->qla4_83xx_reg->risc_intr); | ||
1401 | if (intr_status) { | ||
1402 | ha->mbox_status_count = outcount; | ||
1403 | ha->isp_ops->interrupt_service_routine(ha, intr_status); | ||
1404 | } | ||
1405 | writel(0, &ha->qla4_83xx_reg->risc_intr); | ||
1406 | } | ||
1407 | |||
1408 | /** | ||
1409 | * qla4_83xx_isp_reset - Resets ISP and aborts all outstanding commands. | ||
1410 | * @ha: pointer to host adapter structure. | ||
1411 | **/ | ||
1412 | int qla4_83xx_isp_reset(struct scsi_qla_host *ha) | ||
1413 | { | ||
1414 | int rval; | ||
1415 | uint32_t dev_state; | ||
1416 | |||
1417 | ha->isp_ops->idc_lock(ha); | ||
1418 | dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE); | ||
1419 | |||
1420 | if (ql4xdontresethba) | ||
1421 | qla4_83xx_set_idc_dontreset(ha); | ||
1422 | |||
1423 | if (dev_state == QLA8XXX_DEV_READY) { | ||
1424 | /* If IDC_CTRL DONTRESETHBA_BIT0 is set dont do reset | ||
1425 | * recovery */ | ||
1426 | if (qla4_83xx_idc_dontreset(ha) == DONTRESET_BIT0) { | ||
1427 | ql4_printk(KERN_ERR, ha, "%s: Reset recovery disabled\n", | ||
1428 | __func__); | ||
1429 | rval = QLA_ERROR; | ||
1430 | goto exit_isp_reset; | ||
1431 | } | ||
1432 | |||
1433 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET\n", | ||
1434 | __func__)); | ||
1435 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, | ||
1436 | QLA8XXX_DEV_NEED_RESET); | ||
1437 | |||
1438 | } else { | ||
1439 | /* If device_state is NEED_RESET, go ahead with | ||
1440 | * Reset,irrespective of ql4xdontresethba. This is to allow a | ||
1441 | * non-reset-owner to force a reset. Non-reset-owner sets | ||
1442 | * the IDC_CTRL BIT0 to prevent Reset-owner from doing a Reset | ||
1443 | * and then forces a Reset by setting device_state to | ||
1444 | * NEED_RESET. */ | ||
1445 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
1446 | "%s: HW state already set to NEED_RESET\n", | ||
1447 | __func__)); | ||
1448 | } | ||
1449 | |||
1450 | /* For ISP8324, Reset owner is NIC, iSCSI or FCOE based on priority | ||
1451 | * and which drivers are present. Unlike ISP8022, the function setting | ||
1452 | * NEED_RESET, may not be the Reset owner. */ | ||
1453 | if (qla4_83xx_can_perform_reset(ha)) | ||
1454 | set_bit(AF_8XXX_RST_OWNER, &ha->flags); | ||
1455 | |||
1456 | ha->isp_ops->idc_unlock(ha); | ||
1457 | rval = qla4_8xxx_device_state_handler(ha); | ||
1458 | |||
1459 | ha->isp_ops->idc_lock(ha); | ||
1460 | qla4_8xxx_clear_rst_ready(ha); | ||
1461 | exit_isp_reset: | ||
1462 | ha->isp_ops->idc_unlock(ha); | ||
1463 | |||
1464 | if (rval == QLA_SUCCESS) | ||
1465 | clear_bit(AF_FW_RECOVERY, &ha->flags); | ||
1466 | |||
1467 | return rval; | ||
1468 | } | ||
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.h b/drivers/scsi/qla4xxx/ql4_83xx.h new file mode 100644 index 00000000000..a6792638394 --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_83xx.h | |||
@@ -0,0 +1,262 @@ | |||
1 | /* | ||
2 | * QLogic iSCSI HBA Driver | ||
3 | * Copyright (c) 2003-2012 QLogic Corporation | ||
4 | * | ||
5 | * See LICENSE.qla4xxx for copyright and licensing details. | ||
6 | */ | ||
7 | |||
8 | #ifndef __QL483XX_H | ||
9 | #define __QL483XX_H | ||
10 | |||
11 | /* Indirectly Mapped Registers */ | ||
12 | #define QLA83XX_FLASH_SPI_STATUS 0x2808E010 | ||
13 | #define QLA83XX_FLASH_SPI_CONTROL 0x2808E014 | ||
14 | #define QLA83XX_FLASH_STATUS 0x42100004 | ||
15 | #define QLA83XX_FLASH_CONTROL 0x42110004 | ||
16 | #define QLA83XX_FLASH_ADDR 0x42110008 | ||
17 | #define QLA83XX_FLASH_WRDATA 0x4211000C | ||
18 | #define QLA83XX_FLASH_RDDATA 0x42110018 | ||
19 | #define QLA83XX_FLASH_DIRECT_WINDOW 0x42110030 | ||
20 | #define QLA83XX_FLASH_DIRECT_DATA(DATA) (0x42150000 | (0x0000FFFF&DATA)) | ||
21 | |||
22 | /* Directly Mapped Registers in 83xx register table */ | ||
23 | |||
24 | /* Flash access regs */ | ||
25 | #define QLA83XX_FLASH_LOCK 0x3850 | ||
26 | #define QLA83XX_FLASH_UNLOCK 0x3854 | ||
27 | #define QLA83XX_FLASH_LOCK_ID 0x3500 | ||
28 | |||
29 | /* Driver Lock regs */ | ||
30 | #define QLA83XX_DRV_LOCK 0x3868 | ||
31 | #define QLA83XX_DRV_UNLOCK 0x386C | ||
32 | #define QLA83XX_DRV_LOCK_ID 0x3504 | ||
33 | #define QLA83XX_DRV_LOCKRECOVERY 0x379C | ||
34 | |||
35 | /* IDC version */ | ||
36 | #define QLA83XX_IDC_VER_MAJ_VALUE 0x1 | ||
37 | #define QLA83XX_IDC_VER_MIN_VALUE 0x0 | ||
38 | |||
39 | /* IDC Registers : Driver Coexistence Defines */ | ||
40 | #define QLA83XX_CRB_IDC_VER_MAJOR 0x3780 | ||
41 | #define QLA83XX_CRB_IDC_VER_MINOR 0x3798 | ||
42 | #define QLA83XX_IDC_DRV_CTRL 0x3790 | ||
43 | #define QLA83XX_IDC_DRV_AUDIT 0x3794 | ||
44 | |||
45 | /* qla_83xx_reg_tbl registers */ | ||
46 | #define QLA83XX_PEG_HALT_STATUS1 0x34A8 | ||
47 | #define QLA83XX_PEG_HALT_STATUS2 0x34AC | ||
48 | #define QLA83XX_PEG_ALIVE_COUNTER 0x34B0 /* FW_HEARTBEAT */ | ||
49 | #define QLA83XX_FW_CAPABILITIES 0x3528 | ||
50 | #define QLA83XX_CRB_DRV_ACTIVE 0x3788 /* IDC_DRV_PRESENCE */ | ||
51 | #define QLA83XX_CRB_DEV_STATE 0x3784 /* IDC_DEV_STATE */ | ||
52 | #define QLA83XX_CRB_DRV_STATE 0x378C /* IDC_DRV_ACK */ | ||
53 | #define QLA83XX_CRB_DRV_SCRATCH 0x3548 | ||
54 | #define QLA83XX_CRB_DEV_PART_INFO1 0x37E0 | ||
55 | #define QLA83XX_CRB_DEV_PART_INFO2 0x37E4 | ||
56 | |||
57 | #define QLA83XX_FW_VER_MAJOR 0x3550 | ||
58 | #define QLA83XX_FW_VER_MINOR 0x3554 | ||
59 | #define QLA83XX_FW_VER_SUB 0x3558 | ||
60 | #define QLA83XX_NPAR_STATE 0x359C | ||
61 | #define QLA83XX_FW_IMAGE_VALID 0x35FC | ||
62 | #define QLA83XX_CMDPEG_STATE 0x3650 | ||
63 | #define QLA83XX_ASIC_TEMP 0x37B4 | ||
64 | #define QLA83XX_FW_API 0x356C | ||
65 | #define QLA83XX_DRV_OP_MODE 0x3570 | ||
66 | |||
67 | static const uint32_t qla4_83xx_reg_tbl[] = { | ||
68 | QLA83XX_PEG_HALT_STATUS1, | ||
69 | QLA83XX_PEG_HALT_STATUS2, | ||
70 | QLA83XX_PEG_ALIVE_COUNTER, | ||
71 | QLA83XX_CRB_DRV_ACTIVE, | ||
72 | QLA83XX_CRB_DEV_STATE, | ||
73 | QLA83XX_CRB_DRV_STATE, | ||
74 | QLA83XX_CRB_DRV_SCRATCH, | ||
75 | QLA83XX_CRB_DEV_PART_INFO1, | ||
76 | QLA83XX_CRB_IDC_VER_MAJOR, | ||
77 | QLA83XX_FW_VER_MAJOR, | ||
78 | QLA83XX_FW_VER_MINOR, | ||
79 | QLA83XX_FW_VER_SUB, | ||
80 | QLA83XX_CMDPEG_STATE, | ||
81 | QLA83XX_ASIC_TEMP, | ||
82 | }; | ||
83 | |||
84 | #define QLA83XX_CRB_WIN_BASE 0x3800 | ||
85 | #define QLA83XX_CRB_WIN_FUNC(f) (QLA83XX_CRB_WIN_BASE+((f)*4)) | ||
86 | #define QLA83XX_SEM_LOCK_BASE 0x3840 | ||
87 | #define QLA83XX_SEM_UNLOCK_BASE 0x3844 | ||
88 | #define QLA83XX_SEM_LOCK_FUNC(f) (QLA83XX_SEM_LOCK_BASE+((f)*8)) | ||
89 | #define QLA83XX_SEM_UNLOCK_FUNC(f) (QLA83XX_SEM_UNLOCK_BASE+((f)*8)) | ||
90 | #define QLA83XX_LINK_STATE(f) (0x3698+((f) > 7 ? 4 : 0)) | ||
91 | #define QLA83XX_LINK_SPEED(f) (0x36E0+(((f) >> 2) * 4)) | ||
92 | #define QLA83XX_MAX_LINK_SPEED(f) (0x36F0+(((f) / 4) * 4)) | ||
93 | #define QLA83XX_LINK_SPEED_FACTOR 10 | ||
94 | |||
95 | /* FLASH API Defines */ | ||
96 | #define QLA83xx_FLASH_MAX_WAIT_USEC 100 | ||
97 | #define QLA83XX_FLASH_LOCK_TIMEOUT 10000 | ||
98 | #define QLA83XX_FLASH_SECTOR_SIZE 65536 | ||
99 | #define QLA83XX_DRV_LOCK_TIMEOUT 2000 | ||
100 | #define QLA83XX_FLASH_SECTOR_ERASE_CMD 0xdeadbeef | ||
101 | #define QLA83XX_FLASH_WRITE_CMD 0xdacdacda | ||
102 | #define QLA83XX_FLASH_BUFFER_WRITE_CMD 0xcadcadca | ||
103 | #define QLA83XX_FLASH_READ_RETRY_COUNT 2000 | ||
104 | #define QLA83XX_FLASH_STATUS_READY 0x6 | ||
105 | #define QLA83XX_FLASH_BUFFER_WRITE_MIN 2 | ||
106 | #define QLA83XX_FLASH_BUFFER_WRITE_MAX 64 | ||
107 | #define QLA83XX_FLASH_STATUS_REG_POLL_DELAY 1 | ||
108 | #define QLA83XX_ERASE_MODE 1 | ||
109 | #define QLA83XX_WRITE_MODE 2 | ||
110 | #define QLA83XX_DWORD_WRITE_MODE 3 | ||
111 | |||
112 | #define QLA83XX_GLOBAL_RESET 0x38CC | ||
113 | #define QLA83XX_WILDCARD 0x38F0 | ||
114 | #define QLA83XX_INFORMANT 0x38FC | ||
115 | #define QLA83XX_HOST_MBX_CTRL 0x3038 | ||
116 | #define QLA83XX_FW_MBX_CTRL 0x303C | ||
117 | #define QLA83XX_BOOTLOADER_ADDR 0x355C | ||
118 | #define QLA83XX_BOOTLOADER_SIZE 0x3560 | ||
119 | #define QLA83XX_FW_IMAGE_ADDR 0x3564 | ||
120 | #define QLA83XX_MBX_INTR_ENABLE 0x1000 | ||
121 | #define QLA83XX_MBX_INTR_MASK 0x1200 | ||
122 | |||
123 | /* IDC Control Register bit defines */ | ||
124 | #define DONTRESET_BIT0 0x1 | ||
125 | #define GRACEFUL_RESET_BIT1 0x2 | ||
126 | |||
127 | #define QLA83XX_HALT_STATUS_INFORMATIONAL (0x1 << 29) | ||
128 | #define QLA83XX_HALT_STATUS_FW_RESET (0x2 << 29) | ||
129 | #define QLA83XX_HALT_STATUS_UNRECOVERABLE (0x4 << 29) | ||
130 | |||
131 | /* Firmware image definitions */ | ||
132 | #define QLA83XX_BOOTLOADER_FLASH_ADDR 0x10000 | ||
133 | #define QLA83XX_BOOT_FROM_FLASH 0 | ||
134 | |||
135 | #define QLA83XX_IDC_PARAM_ADDR 0x3e8020 | ||
136 | /* Reset template definitions */ | ||
137 | #define QLA83XX_MAX_RESET_SEQ_ENTRIES 16 | ||
138 | #define QLA83XX_RESTART_TEMPLATE_SIZE 0x2000 | ||
139 | #define QLA83XX_RESET_TEMPLATE_ADDR 0x4F0000 | ||
140 | #define QLA83XX_RESET_SEQ_VERSION 0x0101 | ||
141 | |||
142 | /* Reset template entry opcodes */ | ||
143 | #define OPCODE_NOP 0x0000 | ||
144 | #define OPCODE_WRITE_LIST 0x0001 | ||
145 | #define OPCODE_READ_WRITE_LIST 0x0002 | ||
146 | #define OPCODE_POLL_LIST 0x0004 | ||
147 | #define OPCODE_POLL_WRITE_LIST 0x0008 | ||
148 | #define OPCODE_READ_MODIFY_WRITE 0x0010 | ||
149 | #define OPCODE_SEQ_PAUSE 0x0020 | ||
150 | #define OPCODE_SEQ_END 0x0040 | ||
151 | #define OPCODE_TMPL_END 0x0080 | ||
152 | #define OPCODE_POLL_READ_LIST 0x0100 | ||
153 | |||
154 | /* Template Header */ | ||
155 | #define RESET_TMPLT_HDR_SIGNATURE 0xCAFE | ||
156 | struct qla4_83xx_reset_template_hdr { | ||
157 | __le16 version; | ||
158 | __le16 signature; | ||
159 | __le16 size; | ||
160 | __le16 entries; | ||
161 | __le16 hdr_size; | ||
162 | __le16 checksum; | ||
163 | __le16 init_seq_offset; | ||
164 | __le16 start_seq_offset; | ||
165 | } __packed; | ||
166 | |||
167 | /* Common Entry Header. */ | ||
168 | struct qla4_83xx_reset_entry_hdr { | ||
169 | __le16 cmd; | ||
170 | __le16 size; | ||
171 | __le16 count; | ||
172 | __le16 delay; | ||
173 | } __packed; | ||
174 | |||
175 | /* Generic poll entry type. */ | ||
176 | struct qla4_83xx_poll { | ||
177 | __le32 test_mask; | ||
178 | __le32 test_value; | ||
179 | } __packed; | ||
180 | |||
181 | /* Read modify write entry type. */ | ||
182 | struct qla4_83xx_rmw { | ||
183 | __le32 test_mask; | ||
184 | __le32 xor_value; | ||
185 | __le32 or_value; | ||
186 | uint8_t shl; | ||
187 | uint8_t shr; | ||
188 | uint8_t index_a; | ||
189 | uint8_t rsvd; | ||
190 | } __packed; | ||
191 | |||
192 | /* Generic Entry Item with 2 DWords. */ | ||
193 | struct qla4_83xx_entry { | ||
194 | __le32 arg1; | ||
195 | __le32 arg2; | ||
196 | } __packed; | ||
197 | |||
198 | /* Generic Entry Item with 4 DWords.*/ | ||
199 | struct qla4_83xx_quad_entry { | ||
200 | __le32 dr_addr; | ||
201 | __le32 dr_value; | ||
202 | __le32 ar_addr; | ||
203 | __le32 ar_value; | ||
204 | } __packed; | ||
205 | |||
206 | struct qla4_83xx_reset_template { | ||
207 | int seq_index; | ||
208 | int seq_error; | ||
209 | int array_index; | ||
210 | uint32_t array[QLA83XX_MAX_RESET_SEQ_ENTRIES]; | ||
211 | uint8_t *buff; | ||
212 | uint8_t *stop_offset; | ||
213 | uint8_t *start_offset; | ||
214 | uint8_t *init_offset; | ||
215 | struct qla4_83xx_reset_template_hdr *hdr; | ||
216 | uint8_t seq_end; | ||
217 | uint8_t template_end; | ||
218 | }; | ||
219 | |||
220 | /* POLLRD Entry */ | ||
221 | struct qla83xx_minidump_entry_pollrd { | ||
222 | struct qla8xxx_minidump_entry_hdr h; | ||
223 | uint32_t select_addr; | ||
224 | uint32_t read_addr; | ||
225 | uint32_t select_value; | ||
226 | uint16_t select_value_stride; | ||
227 | uint16_t op_count; | ||
228 | uint32_t poll_wait; | ||
229 | uint32_t poll_mask; | ||
230 | uint32_t data_size; | ||
231 | uint32_t rsvd_1; | ||
232 | }; | ||
233 | |||
234 | /* RDMUX2 Entry */ | ||
235 | struct qla83xx_minidump_entry_rdmux2 { | ||
236 | struct qla8xxx_minidump_entry_hdr h; | ||
237 | uint32_t select_addr_1; | ||
238 | uint32_t select_addr_2; | ||
239 | uint32_t select_value_1; | ||
240 | uint32_t select_value_2; | ||
241 | uint32_t op_count; | ||
242 | uint32_t select_value_mask; | ||
243 | uint32_t read_addr; | ||
244 | uint8_t select_value_stride; | ||
245 | uint8_t data_size; | ||
246 | uint8_t rsvd[2]; | ||
247 | }; | ||
248 | |||
249 | /* POLLRDMWR Entry */ | ||
250 | struct qla83xx_minidump_entry_pollrdmwr { | ||
251 | struct qla8xxx_minidump_entry_hdr h; | ||
252 | uint32_t addr_1; | ||
253 | uint32_t addr_2; | ||
254 | uint32_t value_1; | ||
255 | uint32_t value_2; | ||
256 | uint32_t poll_wait; | ||
257 | uint32_t poll_mask; | ||
258 | uint32_t modify_mask; | ||
259 | uint32_t data_size; | ||
260 | }; | ||
261 | |||
262 | #endif | ||
diff --git a/drivers/scsi/qla4xxx/ql4_attr.c b/drivers/scsi/qla4xxx/ql4_attr.c index a24008f1853..76819b71ada 100644 --- a/drivers/scsi/qla4xxx/ql4_attr.c +++ b/drivers/scsi/qla4xxx/ql4_attr.c | |||
@@ -150,7 +150,7 @@ qla4xxx_fw_version_show(struct device *dev, | |||
150 | { | 150 | { |
151 | struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev)); | 151 | struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev)); |
152 | 152 | ||
153 | if (is_qla8022(ha)) | 153 | if (is_qla80XX(ha)) |
154 | return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n", | 154 | return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n", |
155 | ha->firmware_version[0], | 155 | ha->firmware_version[0], |
156 | ha->firmware_version[1], | 156 | ha->firmware_version[1], |
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c index ea6af8ca6b3..f2a841f6971 100644 --- a/drivers/scsi/qla4xxx/ql4_dbg.c +++ b/drivers/scsi/qla4xxx/ql4_dbg.c | |||
@@ -131,3 +131,31 @@ void qla4xxx_dump_registers(struct scsi_qla_host *ha) | |||
131 | &ha->reg->ctrl_status); | 131 | &ha->reg->ctrl_status); |
132 | } | 132 | } |
133 | } | 133 | } |
134 | |||
135 | void qla4_8xxx_dump_peg_reg(struct scsi_qla_host *ha) | ||
136 | { | ||
137 | uint32_t halt_status1, halt_status2; | ||
138 | |||
139 | halt_status1 = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS1); | ||
140 | halt_status2 = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS2); | ||
141 | |||
142 | if (is_qla8022(ha)) { | ||
143 | ql4_printk(KERN_INFO, ha, | ||
144 | "scsi(%ld): %s, ISP8022 Dumping hw/fw registers:\n" | ||
145 | " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n" | ||
146 | " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n" | ||
147 | " PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n" | ||
148 | " PEG_NET_4_PC: 0x%x\n", ha->host_no, | ||
149 | __func__, halt_status1, halt_status2, | ||
150 | qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c), | ||
151 | qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 + 0x3c), | ||
152 | qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c), | ||
153 | qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c), | ||
154 | qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c)); | ||
155 | } else if (is_qla8032(ha)) { | ||
156 | ql4_printk(KERN_INFO, ha, | ||
157 | "scsi(%ld): %s, ISP8324 Dumping hw/fw registers:\n" | ||
158 | " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n", | ||
159 | ha->host_no, __func__, halt_status1, halt_status2); | ||
160 | } | ||
161 | } | ||
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 11271a2f551..58b52cffebe 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h | |||
@@ -42,6 +42,7 @@ | |||
42 | #include "ql4_nx.h" | 42 | #include "ql4_nx.h" |
43 | #include "ql4_fw.h" | 43 | #include "ql4_fw.h" |
44 | #include "ql4_nvram.h" | 44 | #include "ql4_nvram.h" |
45 | #include "ql4_83xx.h" | ||
45 | 46 | ||
46 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP4010 | 47 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP4010 |
47 | #define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010 | 48 | #define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010 |
@@ -59,6 +60,10 @@ | |||
59 | #define PCI_DEVICE_ID_QLOGIC_ISP8022 0x8022 | 60 | #define PCI_DEVICE_ID_QLOGIC_ISP8022 0x8022 |
60 | #endif | 61 | #endif |
61 | 62 | ||
63 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP8324 | ||
64 | #define PCI_DEVICE_ID_QLOGIC_ISP8324 0x8032 | ||
65 | #endif | ||
66 | |||
62 | #define ISP4XXX_PCI_FN_1 0x1 | 67 | #define ISP4XXX_PCI_FN_1 0x1 |
63 | #define ISP4XXX_PCI_FN_2 0x3 | 68 | #define ISP4XXX_PCI_FN_2 0x3 |
64 | 69 | ||
@@ -510,6 +515,7 @@ struct scsi_qla_host { | |||
510 | #define AF_82XX_FW_DUMPED 24 /* 0x01000000 */ | 515 | #define AF_82XX_FW_DUMPED 24 /* 0x01000000 */ |
511 | #define AF_8XXX_RST_OWNER 25 /* 0x02000000 */ | 516 | #define AF_8XXX_RST_OWNER 25 /* 0x02000000 */ |
512 | #define AF_82XX_DUMP_READING 26 /* 0x04000000 */ | 517 | #define AF_82XX_DUMP_READING 26 /* 0x04000000 */ |
518 | #define AF_83XX_NO_FW_DUMP 27 /* 0x08000000 */ | ||
513 | 519 | ||
514 | unsigned long dpc_flags; | 520 | unsigned long dpc_flags; |
515 | 521 | ||
@@ -746,6 +752,10 @@ struct scsi_qla_host { | |||
746 | uint32_t mrb_index; | 752 | uint32_t mrb_index; |
747 | 753 | ||
748 | uint32_t *reg_tbl; | 754 | uint32_t *reg_tbl; |
755 | struct qla4_83xx_reset_template reset_tmplt; | ||
756 | struct device_reg_83xx __iomem *qla4_83xx_reg; /* Base I/O address | ||
757 | for ISP8324 */ | ||
758 | uint32_t pf_bit; | ||
749 | }; | 759 | }; |
750 | 760 | ||
751 | struct ql4_task_data { | 761 | struct ql4_task_data { |
@@ -808,13 +818,20 @@ static inline int is_qla8022(struct scsi_qla_host *ha) | |||
808 | return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022; | 818 | return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022; |
809 | } | 819 | } |
810 | 820 | ||
811 | /* Note: Currently AER/EEH is now supported only for 8022 cards | 821 | static inline int is_qla8032(struct scsi_qla_host *ha) |
812 | * This function needs to be updated when AER/EEH is enabled | 822 | { |
813 | * for other cards. | 823 | return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8324; |
814 | */ | 824 | } |
825 | |||
826 | static inline int is_qla80XX(struct scsi_qla_host *ha) | ||
827 | { | ||
828 | return is_qla8022(ha) || is_qla8032(ha); | ||
829 | } | ||
830 | |||
815 | static inline int is_aer_supported(struct scsi_qla_host *ha) | 831 | static inline int is_aer_supported(struct scsi_qla_host *ha) |
816 | { | 832 | { |
817 | return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022; | 833 | return ((ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022) || |
834 | (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8324)); | ||
818 | } | 835 | } |
819 | 836 | ||
820 | static inline int adapter_up(struct scsi_qla_host *ha) | 837 | static inline int adapter_up(struct scsi_qla_host *ha) |
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index 037d38016c0..3f36950ec86 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h | |||
@@ -65,6 +65,40 @@ struct device_reg_82xx { | |||
65 | #define ISRX_82XX_RISC_INT BIT_0 /* RISC interrupt. */ | 65 | #define ISRX_82XX_RISC_INT BIT_0 /* RISC interrupt. */ |
66 | }; | 66 | }; |
67 | 67 | ||
68 | /* ISP 83xx I/O Register Set structure */ | ||
69 | struct device_reg_83xx { | ||
70 | __le32 mailbox_in[16]; /* 0x0000 */ | ||
71 | __le32 reserve1[496]; /* 0x0040 */ | ||
72 | __le32 mailbox_out[16]; /* 0x0800 */ | ||
73 | __le32 reserve2[496]; | ||
74 | __le32 mbox_int; /* 0x1000 */ | ||
75 | __le32 reserve3[63]; | ||
76 | __le32 req_q_out; /* 0x1100 */ | ||
77 | __le32 reserve4[63]; | ||
78 | |||
79 | __le32 rsp_q_in; /* 0x1200 */ | ||
80 | __le32 reserve5[1919]; | ||
81 | |||
82 | __le32 req_q_in; /* 0x3000 */ | ||
83 | __le32 reserve6[3]; | ||
84 | __le32 iocb_int_mask; /* 0x3010 */ | ||
85 | __le32 reserve7[3]; | ||
86 | __le32 rsp_q_out; /* 0x3020 */ | ||
87 | __le32 reserve8[3]; | ||
88 | __le32 anonymousbuff; /* 0x3030 */ | ||
89 | __le32 mb_int_mask; /* 0x3034 */ | ||
90 | |||
91 | __le32 host_intr; /* 0x3038 - Host Interrupt Register */ | ||
92 | __le32 risc_intr; /* 0x303C - RISC Interrupt Register */ | ||
93 | __le32 reserve9[544]; | ||
94 | __le32 leg_int_ptr; /* 0x38C0 - Legacy Interrupt Pointer Register */ | ||
95 | __le32 leg_int_trig; /* 0x38C4 - Legacy Interrupt Trigger Control */ | ||
96 | __le32 leg_int_mask; /* 0x38C8 - Legacy Interrupt Mask Register */ | ||
97 | }; | ||
98 | |||
99 | #define INT_ENABLE_FW_MB (1 << 2) | ||
100 | #define INT_MASK_FW_MB (1 << 2) | ||
101 | |||
68 | /* remote register set (access via PCI memory read/write) */ | 102 | /* remote register set (access via PCI memory read/write) */ |
69 | struct isp_reg { | 103 | struct isp_reg { |
70 | #define MBOX_REG_COUNT 8 | 104 | #define MBOX_REG_COUNT 8 |
@@ -1198,6 +1232,9 @@ struct ql_iscsi_stats { | |||
1198 | #define QLA8XXX_DBG_STATE_ARRAY_LEN 16 | 1232 | #define QLA8XXX_DBG_STATE_ARRAY_LEN 16 |
1199 | #define QLA8XXX_DBG_CAP_SIZE_ARRAY_LEN 8 | 1233 | #define QLA8XXX_DBG_CAP_SIZE_ARRAY_LEN 8 |
1200 | #define QLA8XXX_DBG_RSVD_ARRAY_LEN 8 | 1234 | #define QLA8XXX_DBG_RSVD_ARRAY_LEN 8 |
1235 | #define QLA83XX_DBG_OCM_WNDREG_ARRAY_LEN 16 | ||
1236 | #define QLA83XX_SS_OCM_WNDREG_INDEX 3 | ||
1237 | #define QLA83XX_SS_PCI_INDEX 0 | ||
1201 | 1238 | ||
1202 | struct qla4_8xxx_minidump_template_hdr { | 1239 | struct qla4_8xxx_minidump_template_hdr { |
1203 | uint32_t entry_type; | 1240 | uint32_t entry_type; |
@@ -1216,6 +1253,7 @@ struct qla4_8xxx_minidump_template_hdr { | |||
1216 | 1253 | ||
1217 | uint32_t saved_state_array[QLA8XXX_DBG_STATE_ARRAY_LEN]; | 1254 | uint32_t saved_state_array[QLA8XXX_DBG_STATE_ARRAY_LEN]; |
1218 | uint32_t capture_size_array[QLA8XXX_DBG_CAP_SIZE_ARRAY_LEN]; | 1255 | uint32_t capture_size_array[QLA8XXX_DBG_CAP_SIZE_ARRAY_LEN]; |
1256 | uint32_t ocm_window_reg[QLA83XX_DBG_OCM_WNDREG_ARRAY_LEN]; | ||
1219 | }; | 1257 | }; |
1220 | 1258 | ||
1221 | #endif /* _QLA4X_FW_H */ | 1259 | #endif /* _QLA4X_FW_H */ |
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 1010d717b7d..0c6acad2a51 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h | |||
@@ -214,6 +214,47 @@ void qla4_82xx_process_mbox_intr(struct scsi_qla_host *ha, int outcount); | |||
214 | void qla4xxx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd, | 214 | void qla4xxx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd, |
215 | int incount); | 215 | int incount); |
216 | void qla4xxx_process_mbox_intr(struct scsi_qla_host *ha, int outcount); | 216 | void qla4xxx_process_mbox_intr(struct scsi_qla_host *ha, int outcount); |
217 | void qla4_8xxx_dump_peg_reg(struct scsi_qla_host *ha); | ||
218 | void qla4_83xx_disable_intrs(struct scsi_qla_host *ha); | ||
219 | void qla4_83xx_enable_intrs(struct scsi_qla_host *ha); | ||
220 | int qla4_83xx_start_firmware(struct scsi_qla_host *ha); | ||
221 | irqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id); | ||
222 | void qla4_83xx_interrupt_service_routine(struct scsi_qla_host *ha, | ||
223 | uint32_t intr_status); | ||
224 | int qla4_83xx_isp_reset(struct scsi_qla_host *ha); | ||
225 | void qla4_83xx_queue_iocb(struct scsi_qla_host *ha); | ||
226 | void qla4_83xx_complete_iocb(struct scsi_qla_host *ha); | ||
227 | uint16_t qla4_83xx_rd_shdw_req_q_out(struct scsi_qla_host *ha); | ||
228 | uint16_t qla4_83xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha); | ||
229 | uint32_t qla4_83xx_rd_reg(struct scsi_qla_host *ha, ulong addr); | ||
230 | void qla4_83xx_wr_reg(struct scsi_qla_host *ha, ulong addr, uint32_t val); | ||
231 | int qla4_83xx_rd_reg_indirect(struct scsi_qla_host *ha, uint32_t addr, | ||
232 | uint32_t *data); | ||
233 | int qla4_83xx_wr_reg_indirect(struct scsi_qla_host *ha, uint32_t addr, | ||
234 | uint32_t data); | ||
235 | int qla4_83xx_drv_lock(struct scsi_qla_host *ha); | ||
236 | void qla4_83xx_drv_unlock(struct scsi_qla_host *ha); | ||
237 | void qla4_83xx_rom_lock_recovery(struct scsi_qla_host *ha); | ||
238 | void qla4_83xx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd, | ||
239 | int incount); | ||
240 | void qla4_83xx_process_mbox_intr(struct scsi_qla_host *ha, int outcount); | ||
241 | void qla4_83xx_read_reset_template(struct scsi_qla_host *ha); | ||
242 | void qla4_83xx_set_idc_dontreset(struct scsi_qla_host *ha); | ||
243 | int qla4_83xx_idc_dontreset(struct scsi_qla_host *ha); | ||
244 | int qla4_83xx_lockless_flash_read_u32(struct scsi_qla_host *ha, | ||
245 | uint32_t flash_addr, uint8_t *p_data, | ||
246 | int u32_word_count); | ||
247 | void qla4_83xx_clear_idc_dontreset(struct scsi_qla_host *ha); | ||
248 | void qla4_83xx_need_reset_handler(struct scsi_qla_host *ha); | ||
249 | int qla4_83xx_flash_read_u32(struct scsi_qla_host *ha, uint32_t flash_addr, | ||
250 | uint8_t *p_data, int u32_word_count); | ||
251 | void qla4_83xx_get_idc_param(struct scsi_qla_host *ha); | ||
252 | void qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha); | ||
253 | void qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha); | ||
254 | int qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha); | ||
255 | void qla4_8xxx_get_minidump(struct scsi_qla_host *ha); | ||
256 | int qla4_8xxx_mbx_intr_disable(struct scsi_qla_host *ha); | ||
257 | int qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha); | ||
217 | 258 | ||
218 | extern int ql4xextended_error_logging; | 259 | extern int ql4xextended_error_logging; |
219 | extern int ql4xdontresethba; | 260 | extern int ql4xdontresethba; |
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 6bc983df9d9..a1881d014be 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c | |||
@@ -107,6 +107,13 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha) | |||
107 | (unsigned long __iomem *)&ha->qla4_82xx_reg->rsp_q_in); | 107 | (unsigned long __iomem *)&ha->qla4_82xx_reg->rsp_q_in); |
108 | writel(0, | 108 | writel(0, |
109 | (unsigned long __iomem *)&ha->qla4_82xx_reg->rsp_q_out); | 109 | (unsigned long __iomem *)&ha->qla4_82xx_reg->rsp_q_out); |
110 | } else if (is_qla8032(ha)) { | ||
111 | writel(0, | ||
112 | (unsigned long __iomem *)&ha->qla4_83xx_reg->req_q_in); | ||
113 | writel(0, | ||
114 | (unsigned long __iomem *)&ha->qla4_83xx_reg->rsp_q_in); | ||
115 | writel(0, | ||
116 | (unsigned long __iomem *)&ha->qla4_83xx_reg->rsp_q_out); | ||
110 | } else { | 117 | } else { |
111 | /* | 118 | /* |
112 | * Initialize DMA Shadow registers. The firmware is really | 119 | * Initialize DMA Shadow registers. The firmware is really |
@@ -524,7 +531,7 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha) | |||
524 | /* For 82xx, stop firmware before initializing because if BIOS | 531 | /* For 82xx, stop firmware before initializing because if BIOS |
525 | * has previously initialized firmware, then driver's initialize | 532 | * has previously initialized firmware, then driver's initialize |
526 | * firmware will fail. */ | 533 | * firmware will fail. */ |
527 | if (is_qla8022(ha)) | 534 | if (is_qla80XX(ha)) |
528 | qla4_8xxx_stop_firmware(ha); | 535 | qla4_8xxx_stop_firmware(ha); |
529 | 536 | ||
530 | ql4_printk(KERN_INFO, ha, "Initializing firmware..\n"); | 537 | ql4_printk(KERN_INFO, ha, "Initializing firmware..\n"); |
@@ -537,7 +544,7 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha) | |||
537 | if (!qla4xxx_fw_ready(ha)) | 544 | if (!qla4xxx_fw_ready(ha)) |
538 | return status; | 545 | return status; |
539 | 546 | ||
540 | if (is_qla8022(ha) && !test_bit(AF_INIT_DONE, &ha->flags)) | 547 | if (is_qla80XX(ha) && !test_bit(AF_INIT_DONE, &ha->flags)) |
541 | qla4xxx_alloc_fw_dump(ha); | 548 | qla4xxx_alloc_fw_dump(ha); |
542 | 549 | ||
543 | return qla4xxx_get_firmware_status(ha); | 550 | return qla4xxx_get_firmware_status(ha); |
@@ -946,9 +953,9 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset) | |||
946 | 953 | ||
947 | set_bit(AF_ONLINE, &ha->flags); | 954 | set_bit(AF_ONLINE, &ha->flags); |
948 | exit_init_hba: | 955 | exit_init_hba: |
949 | if (is_qla8022(ha) && (status == QLA_ERROR)) { | 956 | if (is_qla80XX(ha) && (status == QLA_ERROR)) { |
950 | /* Since interrupts are registered in start_firmware for | 957 | /* Since interrupts are registered in start_firmware for |
951 | * 82xx, release them here if initialize_adapter fails */ | 958 | * 80XX, release them here if initialize_adapter fails */ |
952 | qla4xxx_free_irqs(ha); | 959 | qla4xxx_free_irqs(ha); |
953 | } | 960 | } |
954 | 961 | ||
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c index 1def68879f9..b6a4e36b79d 100644 --- a/drivers/scsi/qla4xxx/ql4_iocb.c +++ b/drivers/scsi/qla4xxx/ql4_iocb.c | |||
@@ -192,6 +192,18 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb, | |||
192 | } | 192 | } |
193 | } | 193 | } |
194 | 194 | ||
195 | void qla4_83xx_queue_iocb(struct scsi_qla_host *ha) | ||
196 | { | ||
197 | writel(ha->request_in, &ha->qla4_83xx_reg->req_q_in); | ||
198 | readl(&ha->qla4_83xx_reg->req_q_in); | ||
199 | } | ||
200 | |||
201 | void qla4_83xx_complete_iocb(struct scsi_qla_host *ha) | ||
202 | { | ||
203 | writel(ha->response_out, &ha->qla4_83xx_reg->rsp_q_out); | ||
204 | readl(&ha->qla4_83xx_reg->rsp_q_out); | ||
205 | } | ||
206 | |||
195 | /** | 207 | /** |
196 | * qla4_82xx_queue_iocb - Tell ISP it's got new request(s) | 208 | * qla4_82xx_queue_iocb - Tell ISP it's got new request(s) |
197 | * @ha: pointer to host adapter structure. | 209 | * @ha: pointer to host adapter structure. |
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 55d366b14a5..cb78e9c1674 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c | |||
@@ -126,7 +126,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, | |||
126 | ql4_printk(KERN_WARNING, ha, "%s invalid status entry: " | 126 | ql4_printk(KERN_WARNING, ha, "%s invalid status entry: " |
127 | "handle=0x%0x, srb=%p\n", __func__, | 127 | "handle=0x%0x, srb=%p\n", __func__, |
128 | sts_entry->handle, srb); | 128 | sts_entry->handle, srb); |
129 | if (is_qla8022(ha)) | 129 | if (is_qla80XX(ha)) |
130 | set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); | 130 | set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); |
131 | else | 131 | else |
132 | set_bit(DPC_RESET_HA, &ha->dpc_flags); | 132 | set_bit(DPC_RESET_HA, &ha->dpc_flags); |
@@ -594,6 +594,14 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
594 | { | 594 | { |
595 | int i; | 595 | int i; |
596 | uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; | 596 | uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; |
597 | __le32 __iomem *mailbox_out; | ||
598 | |||
599 | if (is_qla8032(ha)) | ||
600 | mailbox_out = &ha->qla4_83xx_reg->mailbox_out[0]; | ||
601 | else if (is_qla8022(ha)) | ||
602 | mailbox_out = &ha->qla4_82xx_reg->mailbox_out[0]; | ||
603 | else | ||
604 | mailbox_out = &ha->reg->mailbox[0]; | ||
597 | 605 | ||
598 | if ((mbox_status == MBOX_STS_BUSY) || | 606 | if ((mbox_status == MBOX_STS_BUSY) || |
599 | (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) || | 607 | (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) || |
@@ -606,9 +614,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
606 | * location and set mailbox command done flag | 614 | * location and set mailbox command done flag |
607 | */ | 615 | */ |
608 | for (i = 0; i < ha->mbox_status_count; i++) | 616 | for (i = 0; i < ha->mbox_status_count; i++) |
609 | ha->mbox_status[i] = is_qla8022(ha) | 617 | ha->mbox_status[i] = readl(&mailbox_out[i]); |
610 | ? readl(&ha->qla4_82xx_reg->mailbox_out[i]) | ||
611 | : readl(&ha->reg->mailbox[i]); | ||
612 | 618 | ||
613 | set_bit(AF_MBOX_COMMAND_DONE, &ha->flags); | 619 | set_bit(AF_MBOX_COMMAND_DONE, &ha->flags); |
614 | 620 | ||
@@ -617,9 +623,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
617 | } | 623 | } |
618 | } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) { | 624 | } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) { |
619 | for (i = 0; i < MBOX_AEN_REG_COUNT; i++) | 625 | for (i = 0; i < MBOX_AEN_REG_COUNT; i++) |
620 | mbox_sts[i] = is_qla8022(ha) | 626 | mbox_sts[i] = readl(&mailbox_out[i]); |
621 | ? readl(&ha->qla4_82xx_reg->mailbox_out[i]) | ||
622 | : readl(&ha->reg->mailbox[i]); | ||
623 | 627 | ||
624 | /* Immediately process the AENs that don't require much work. | 628 | /* Immediately process the AENs that don't require much work. |
625 | * Only queue the database_changed AENs */ | 629 | * Only queue the database_changed AENs */ |
@@ -635,7 +639,8 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
635 | ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__); | 639 | ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__); |
636 | qla4xxx_dump_registers(ha); | 640 | qla4xxx_dump_registers(ha); |
637 | 641 | ||
638 | if (ql4xdontresethba) { | 642 | if ((is_qla8022(ha) && ql4xdontresethba) || |
643 | (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) { | ||
639 | DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n", | 644 | DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n", |
640 | ha->host_no, __func__)); | 645 | ha->host_no, __func__)); |
641 | } else { | 646 | } else { |
@@ -651,7 +656,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
651 | case MBOX_ASTS_DHCP_LEASE_EXPIRED: | 656 | case MBOX_ASTS_DHCP_LEASE_EXPIRED: |
652 | DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, " | 657 | DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, " |
653 | "Reset HA\n", ha->host_no, mbox_status)); | 658 | "Reset HA\n", ha->host_no, mbox_status)); |
654 | if (is_qla8022(ha)) | 659 | if (is_qla80XX(ha)) |
655 | set_bit(DPC_RESET_HA_FW_CONTEXT, | 660 | set_bit(DPC_RESET_HA_FW_CONTEXT, |
656 | &ha->dpc_flags); | 661 | &ha->dpc_flags); |
657 | else | 662 | else |
@@ -716,7 +721,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
716 | set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); | 721 | set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); |
717 | else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) && | 722 | else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) && |
718 | (mbox_sts[2] == ACB_STATE_VALID)) { | 723 | (mbox_sts[2] == ACB_STATE_VALID)) { |
719 | if (is_qla8022(ha)) | 724 | if (is_qla80XX(ha)) |
720 | set_bit(DPC_RESET_HA_FW_CONTEXT, | 725 | set_bit(DPC_RESET_HA_FW_CONTEXT, |
721 | &ha->dpc_flags); | 726 | &ha->dpc_flags); |
722 | else | 727 | else |
@@ -815,6 +820,23 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, | |||
815 | } | 820 | } |
816 | } | 821 | } |
817 | 822 | ||
823 | void qla4_83xx_interrupt_service_routine(struct scsi_qla_host *ha, | ||
824 | uint32_t intr_status) | ||
825 | { | ||
826 | /* Process mailbox/asynch event interrupt.*/ | ||
827 | if (intr_status) { | ||
828 | qla4xxx_isr_decode_mailbox(ha, | ||
829 | readl(&ha->qla4_83xx_reg->mailbox_out[0])); | ||
830 | /* clear the interrupt */ | ||
831 | writel(0, &ha->qla4_83xx_reg->risc_intr); | ||
832 | } else { | ||
833 | qla4xxx_process_response_queue(ha); | ||
834 | } | ||
835 | |||
836 | /* clear the interrupt */ | ||
837 | writel(0, &ha->qla4_83xx_reg->mb_int_mask); | ||
838 | } | ||
839 | |||
818 | /** | 840 | /** |
819 | * qla4_82xx_interrupt_service_routine - isr | 841 | * qla4_82xx_interrupt_service_routine - isr |
820 | * @ha: pointer to host adapter structure. | 842 | * @ha: pointer to host adapter structure. |
@@ -1045,6 +1067,59 @@ irqreturn_t qla4_82xx_intr_handler(int irq, void *dev_id) | |||
1045 | return IRQ_HANDLED; | 1067 | return IRQ_HANDLED; |
1046 | } | 1068 | } |
1047 | 1069 | ||
1070 | #define LEG_INT_PTR_B31 (1 << 31) | ||
1071 | #define LEG_INT_PTR_B30 (1 << 30) | ||
1072 | #define PF_BITS_MASK (0xF << 16) | ||
1073 | |||
1074 | /** | ||
1075 | * qla4_83xx_intr_handler - hardware interrupt handler. | ||
1076 | * @irq: Unused | ||
1077 | * @dev_id: Pointer to host adapter structure | ||
1078 | **/ | ||
1079 | irqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id) | ||
1080 | { | ||
1081 | struct scsi_qla_host *ha = dev_id; | ||
1082 | uint32_t leg_int_ptr = 0; | ||
1083 | unsigned long flags = 0; | ||
1084 | |||
1085 | ha->isr_count++; | ||
1086 | leg_int_ptr = readl(&ha->qla4_83xx_reg->leg_int_ptr); | ||
1087 | |||
1088 | /* Legacy interrupt is valid if bit31 of leg_int_ptr is set */ | ||
1089 | if (!(leg_int_ptr & LEG_INT_PTR_B31)) { | ||
1090 | ql4_printk(KERN_ERR, ha, | ||
1091 | "%s: Legacy Interrupt Bit 31 not set, spurious interrupt!\n", | ||
1092 | __func__); | ||
1093 | return IRQ_NONE; | ||
1094 | } | ||
1095 | |||
1096 | /* Validate the PCIE function ID set in leg_int_ptr bits [19..16] */ | ||
1097 | if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit) { | ||
1098 | ql4_printk(KERN_ERR, ha, | ||
1099 | "%s: Incorrect function ID 0x%x in legacy interrupt register, ha->pf_bit = 0x%x\n", | ||
1100 | __func__, (leg_int_ptr & PF_BITS_MASK), ha->pf_bit); | ||
1101 | return IRQ_NONE; | ||
1102 | } | ||
1103 | |||
1104 | /* To de-assert legacy interrupt, write 0 to Legacy Interrupt Trigger | ||
1105 | * Control register and poll till Legacy Interrupt Pointer register | ||
1106 | * bit30 is 0. | ||
1107 | */ | ||
1108 | writel(0, &ha->qla4_83xx_reg->leg_int_trig); | ||
1109 | do { | ||
1110 | leg_int_ptr = readl(&ha->qla4_83xx_reg->leg_int_ptr); | ||
1111 | if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit) | ||
1112 | break; | ||
1113 | } while (leg_int_ptr & LEG_INT_PTR_B30); | ||
1114 | |||
1115 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
1116 | leg_int_ptr = readl(&ha->qla4_83xx_reg->risc_intr); | ||
1117 | ha->isp_ops->interrupt_service_routine(ha, leg_int_ptr); | ||
1118 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1119 | |||
1120 | return IRQ_HANDLED; | ||
1121 | } | ||
1122 | |||
1048 | irqreturn_t | 1123 | irqreturn_t |
1049 | qla4_8xxx_msi_handler(int irq, void *dev_id) | 1124 | qla4_8xxx_msi_handler(int irq, void *dev_id) |
1050 | { | 1125 | { |
@@ -1068,6 +1143,37 @@ qla4_8xxx_msi_handler(int irq, void *dev_id) | |||
1068 | return qla4_8xxx_default_intr_handler(irq, dev_id); | 1143 | return qla4_8xxx_default_intr_handler(irq, dev_id); |
1069 | } | 1144 | } |
1070 | 1145 | ||
1146 | static irqreturn_t qla4_83xx_mailbox_intr_handler(int irq, void *dev_id) | ||
1147 | { | ||
1148 | struct scsi_qla_host *ha = dev_id; | ||
1149 | unsigned long flags; | ||
1150 | uint32_t ival = 0; | ||
1151 | |||
1152 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
1153 | |||
1154 | ival = readl(&ha->qla4_83xx_reg->risc_intr); | ||
1155 | if (ival == 0) { | ||
1156 | ql4_printk(KERN_INFO, ha, | ||
1157 | "%s: It is a spurious mailbox interrupt!\n", | ||
1158 | __func__); | ||
1159 | ival = readl(&ha->qla4_83xx_reg->mb_int_mask); | ||
1160 | ival &= ~INT_MASK_FW_MB; | ||
1161 | writel(ival, &ha->qla4_83xx_reg->mb_int_mask); | ||
1162 | goto exit; | ||
1163 | } | ||
1164 | |||
1165 | qla4xxx_isr_decode_mailbox(ha, | ||
1166 | readl(&ha->qla4_83xx_reg->mailbox_out[0])); | ||
1167 | writel(0, &ha->qla4_83xx_reg->risc_intr); | ||
1168 | ival = readl(&ha->qla4_83xx_reg->mb_int_mask); | ||
1169 | ival &= ~INT_MASK_FW_MB; | ||
1170 | writel(ival, &ha->qla4_83xx_reg->mb_int_mask); | ||
1171 | ha->isr_count++; | ||
1172 | exit: | ||
1173 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1174 | return IRQ_HANDLED; | ||
1175 | } | ||
1176 | |||
1071 | /** | 1177 | /** |
1072 | * qla4_8xxx_default_intr_handler - hardware interrupt handler. | 1178 | * qla4_8xxx_default_intr_handler - hardware interrupt handler. |
1073 | * @irq: Unused | 1179 | * @irq: Unused |
@@ -1084,29 +1190,32 @@ qla4_8xxx_default_intr_handler(int irq, void *dev_id) | |||
1084 | uint32_t intr_status; | 1190 | uint32_t intr_status; |
1085 | uint8_t reqs_count = 0; | 1191 | uint8_t reqs_count = 0; |
1086 | 1192 | ||
1087 | spin_lock_irqsave(&ha->hardware_lock, flags); | 1193 | if (is_qla8032(ha)) { |
1088 | while (1) { | 1194 | qla4_83xx_mailbox_intr_handler(irq, dev_id); |
1089 | if (!(readl(&ha->qla4_82xx_reg->host_int) & | 1195 | } else { |
1090 | ISRX_82XX_RISC_INT)) { | 1196 | spin_lock_irqsave(&ha->hardware_lock, flags); |
1091 | qla4_82xx_spurious_interrupt(ha, reqs_count); | 1197 | while (1) { |
1092 | break; | 1198 | if (!(readl(&ha->qla4_82xx_reg->host_int) & |
1093 | } | 1199 | ISRX_82XX_RISC_INT)) { |
1200 | qla4_82xx_spurious_interrupt(ha, reqs_count); | ||
1201 | break; | ||
1202 | } | ||
1094 | 1203 | ||
1095 | intr_status = readl(&ha->qla4_82xx_reg->host_status); | 1204 | intr_status = readl(&ha->qla4_82xx_reg->host_status); |
1096 | if ((intr_status & | 1205 | if ((intr_status & |
1097 | (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) { | 1206 | (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) { |
1098 | qla4_82xx_spurious_interrupt(ha, reqs_count); | 1207 | qla4_82xx_spurious_interrupt(ha, reqs_count); |
1099 | break; | 1208 | break; |
1100 | } | 1209 | } |
1101 | 1210 | ||
1102 | ha->isp_ops->interrupt_service_routine(ha, intr_status); | 1211 | ha->isp_ops->interrupt_service_routine(ha, intr_status); |
1103 | 1212 | ||
1104 | if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) | 1213 | if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) |
1105 | break; | 1214 | break; |
1215 | } | ||
1216 | ha->isr_count++; | ||
1217 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1106 | } | 1218 | } |
1107 | |||
1108 | ha->isr_count++; | ||
1109 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1110 | return IRQ_HANDLED; | 1219 | return IRQ_HANDLED; |
1111 | } | 1220 | } |
1112 | 1221 | ||
@@ -1115,13 +1224,25 @@ qla4_8xxx_msix_rsp_q(int irq, void *dev_id) | |||
1115 | { | 1224 | { |
1116 | struct scsi_qla_host *ha = dev_id; | 1225 | struct scsi_qla_host *ha = dev_id; |
1117 | unsigned long flags; | 1226 | unsigned long flags; |
1227 | uint32_t ival = 0; | ||
1118 | 1228 | ||
1119 | spin_lock_irqsave(&ha->hardware_lock, flags); | 1229 | spin_lock_irqsave(&ha->hardware_lock, flags); |
1120 | qla4xxx_process_response_queue(ha); | 1230 | if (is_qla8032(ha)) { |
1121 | writel(0, &ha->qla4_82xx_reg->host_int); | 1231 | ival = readl(&ha->qla4_83xx_reg->iocb_int_mask); |
1122 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 1232 | if (ival == 0) { |
1123 | 1233 | ql4_printk(KERN_INFO, ha, "%s: It is a spurious iocb interrupt!\n", | |
1234 | __func__); | ||
1235 | goto exit_msix_rsp_q; | ||
1236 | } | ||
1237 | qla4xxx_process_response_queue(ha); | ||
1238 | writel(0, &ha->qla4_83xx_reg->iocb_int_mask); | ||
1239 | } else { | ||
1240 | qla4xxx_process_response_queue(ha); | ||
1241 | writel(0, &ha->qla4_82xx_reg->host_int); | ||
1242 | } | ||
1124 | ha->isr_count++; | 1243 | ha->isr_count++; |
1244 | exit_msix_rsp_q: | ||
1245 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1125 | return IRQ_HANDLED; | 1246 | return IRQ_HANDLED; |
1126 | } | 1247 | } |
1127 | 1248 | ||
@@ -1196,8 +1317,15 @@ int qla4xxx_request_irqs(struct scsi_qla_host *ha) | |||
1196 | if (is_qla40XX(ha)) | 1317 | if (is_qla40XX(ha)) |
1197 | goto try_intx; | 1318 | goto try_intx; |
1198 | 1319 | ||
1199 | if (ql4xenablemsix == 2) | 1320 | if (ql4xenablemsix == 2) { |
1321 | /* Note: MSI Interrupts not supported for ISP8324 */ | ||
1322 | if (is_qla8032(ha)) { | ||
1323 | ql4_printk(KERN_INFO, ha, "%s: MSI Interrupts not supported for ISP8324, Falling back-to INTx mode\n", | ||
1324 | __func__); | ||
1325 | goto try_intx; | ||
1326 | } | ||
1200 | goto try_msi; | 1327 | goto try_msi; |
1328 | } | ||
1201 | 1329 | ||
1202 | if (ql4xenablemsix == 0 || ql4xenablemsix != 1) | 1330 | if (ql4xenablemsix == 0 || ql4xenablemsix != 1) |
1203 | goto try_intx; | 1331 | goto try_intx; |
@@ -1208,6 +1336,12 @@ int qla4xxx_request_irqs(struct scsi_qla_host *ha) | |||
1208 | DEBUG2(ql4_printk(KERN_INFO, ha, | 1336 | DEBUG2(ql4_printk(KERN_INFO, ha, |
1209 | "MSI-X: Enabled (0x%X).\n", ha->revision_id)); | 1337 | "MSI-X: Enabled (0x%X).\n", ha->revision_id)); |
1210 | goto irq_attached; | 1338 | goto irq_attached; |
1339 | } else { | ||
1340 | if (is_qla8032(ha)) { | ||
1341 | ql4_printk(KERN_INFO, ha, "%s: ISP8324: MSI-X: Falling back-to INTx mode. ret = %d\n", | ||
1342 | __func__, ret); | ||
1343 | goto try_intx; | ||
1344 | } | ||
1211 | } | 1345 | } |
1212 | 1346 | ||
1213 | ql4_printk(KERN_WARNING, ha, | 1347 | ql4_printk(KERN_WARNING, ha, |
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 73324fba64b..80fa20d6908 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c | |||
@@ -107,7 +107,7 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, | |||
107 | msleep(10); | 107 | msleep(10); |
108 | } | 108 | } |
109 | 109 | ||
110 | if (is_qla8022(ha)) { | 110 | if (is_qla80XX(ha)) { |
111 | if (test_bit(AF_FW_RECOVERY, &ha->flags)) { | 111 | if (test_bit(AF_FW_RECOVERY, &ha->flags)) { |
112 | DEBUG2(ql4_printk(KERN_WARNING, ha, | 112 | DEBUG2(ql4_printk(KERN_WARNING, ha, |
113 | "scsi%ld: %s: prematurely completing mbx cmd as firmware recovery detected\n", | 113 | "scsi%ld: %s: prematurely completing mbx cmd as firmware recovery detected\n", |
@@ -183,7 +183,7 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, | |||
183 | 183 | ||
184 | /* Check for mailbox timeout. */ | 184 | /* Check for mailbox timeout. */ |
185 | if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) { | 185 | if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) { |
186 | if (is_qla8022(ha) && | 186 | if (is_qla80XX(ha) && |
187 | test_bit(AF_FW_RECOVERY, &ha->flags)) { | 187 | test_bit(AF_FW_RECOVERY, &ha->flags)) { |
188 | DEBUG2(ql4_printk(KERN_INFO, ha, | 188 | DEBUG2(ql4_printk(KERN_INFO, ha, |
189 | "scsi%ld: %s: prematurely completing mbx cmd as " | 189 | "scsi%ld: %s: prematurely completing mbx cmd as " |
@@ -544,7 +544,7 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) | |||
544 | __constant_cpu_to_le16(FWOPT_SESSION_MODE | | 544 | __constant_cpu_to_le16(FWOPT_SESSION_MODE | |
545 | FWOPT_INITIATOR_MODE); | 545 | FWOPT_INITIATOR_MODE); |
546 | 546 | ||
547 | if (is_qla8022(ha)) | 547 | if (is_qla80XX(ha)) |
548 | init_fw_cb->fw_options |= | 548 | init_fw_cb->fw_options |= |
549 | __constant_cpu_to_le16(FWOPT_ENABLE_CRBDB); | 549 | __constant_cpu_to_le16(FWOPT_ENABLE_CRBDB); |
550 | 550 | ||
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 6daa25c50a9..3e556084036 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/ratelimit.h> | 10 | #include <linux/ratelimit.h> |
11 | #include "ql4_def.h" | 11 | #include "ql4_def.h" |
12 | #include "ql4_glbl.h" | 12 | #include "ql4_glbl.h" |
13 | #include "ql4_inline.h" | ||
13 | 14 | ||
14 | #include <asm-generic/io-64-nonatomic-lo-hi.h> | 15 | #include <asm-generic/io-64-nonatomic-lo-hi.h> |
15 | 16 | ||
@@ -1511,7 +1512,17 @@ qla4_8xxx_set_drv_active(struct scsi_qla_host *ha) | |||
1511 | uint32_t drv_active; | 1512 | uint32_t drv_active; |
1512 | 1513 | ||
1513 | drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE); | 1514 | drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE); |
1514 | drv_active |= (1 << (ha->func_num * 4)); | 1515 | |
1516 | /* | ||
1517 | * For ISP8324, drv_active register has 1 bit per function, | ||
1518 | * shift 1 by func_num to set a bit for the function. | ||
1519 | * For ISP8022, drv_active has 4 bits per function | ||
1520 | */ | ||
1521 | if (is_qla8032(ha)) | ||
1522 | drv_active |= (1 << ha->func_num); | ||
1523 | else | ||
1524 | drv_active |= (1 << (ha->func_num * 4)); | ||
1525 | |||
1515 | ql4_printk(KERN_INFO, ha, "%s(%ld): drv_active: 0x%08x\n", | 1526 | ql4_printk(KERN_INFO, ha, "%s(%ld): drv_active: 0x%08x\n", |
1516 | __func__, ha->host_no, drv_active); | 1527 | __func__, ha->host_no, drv_active); |
1517 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE, drv_active); | 1528 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE, drv_active); |
@@ -1523,7 +1534,17 @@ qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha) | |||
1523 | uint32_t drv_active; | 1534 | uint32_t drv_active; |
1524 | 1535 | ||
1525 | drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE); | 1536 | drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE); |
1526 | drv_active &= ~(1 << (ha->func_num * 4)); | 1537 | |
1538 | /* | ||
1539 | * For ISP8324, drv_active register has 1 bit per function, | ||
1540 | * shift 1 by func_num to set a bit for the function. | ||
1541 | * For ISP8022, drv_active has 4 bits per function | ||
1542 | */ | ||
1543 | if (is_qla8032(ha)) | ||
1544 | drv_active &= ~(1 << (ha->func_num)); | ||
1545 | else | ||
1546 | drv_active &= ~(1 << (ha->func_num * 4)); | ||
1547 | |||
1527 | ql4_printk(KERN_INFO, ha, "%s(%ld): drv_active: 0x%08x\n", | 1548 | ql4_printk(KERN_INFO, ha, "%s(%ld): drv_active: 0x%08x\n", |
1528 | __func__, ha->host_no, drv_active); | 1549 | __func__, ha->host_no, drv_active); |
1529 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE, drv_active); | 1550 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE, drv_active); |
@@ -1536,32 +1557,60 @@ inline int qla4_8xxx_need_reset(struct scsi_qla_host *ha) | |||
1536 | 1557 | ||
1537 | drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE); | 1558 | drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE); |
1538 | drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE); | 1559 | drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE); |
1539 | rval = drv_state & (1 << (ha->func_num * 4)); | 1560 | |
1561 | /* | ||
1562 | * For ISP8324, drv_active register has 1 bit per function, | ||
1563 | * shift 1 by func_num to set a bit for the function. | ||
1564 | * For ISP8022, drv_active has 4 bits per function | ||
1565 | */ | ||
1566 | if (is_qla8032(ha)) | ||
1567 | rval = drv_state & (1 << ha->func_num); | ||
1568 | else | ||
1569 | rval = drv_state & (1 << (ha->func_num * 4)); | ||
1570 | |||
1540 | if ((test_bit(AF_EEH_BUSY, &ha->flags)) && drv_active) | 1571 | if ((test_bit(AF_EEH_BUSY, &ha->flags)) && drv_active) |
1541 | rval = 1; | 1572 | rval = 1; |
1542 | 1573 | ||
1543 | return rval; | 1574 | return rval; |
1544 | } | 1575 | } |
1545 | 1576 | ||
1546 | static inline void | 1577 | void qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha) |
1547 | qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha) | ||
1548 | { | 1578 | { |
1549 | uint32_t drv_state; | 1579 | uint32_t drv_state; |
1550 | 1580 | ||
1551 | drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE); | 1581 | drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE); |
1552 | drv_state |= (1 << (ha->func_num * 4)); | 1582 | |
1583 | /* | ||
1584 | * For ISP8324, drv_active register has 1 bit per function, | ||
1585 | * shift 1 by func_num to set a bit for the function. | ||
1586 | * For ISP8022, drv_active has 4 bits per function | ||
1587 | */ | ||
1588 | if (is_qla8032(ha)) | ||
1589 | drv_state |= (1 << ha->func_num); | ||
1590 | else | ||
1591 | drv_state |= (1 << (ha->func_num * 4)); | ||
1592 | |||
1553 | ql4_printk(KERN_INFO, ha, "%s(%ld): drv_state: 0x%08x\n", | 1593 | ql4_printk(KERN_INFO, ha, "%s(%ld): drv_state: 0x%08x\n", |
1554 | __func__, ha->host_no, drv_state); | 1594 | __func__, ha->host_no, drv_state); |
1555 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, drv_state); | 1595 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, drv_state); |
1556 | } | 1596 | } |
1557 | 1597 | ||
1558 | static inline void | 1598 | void qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha) |
1559 | qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha) | ||
1560 | { | 1599 | { |
1561 | uint32_t drv_state; | 1600 | uint32_t drv_state; |
1562 | 1601 | ||
1563 | drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE); | 1602 | drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE); |
1564 | drv_state &= ~(1 << (ha->func_num * 4)); | 1603 | |
1604 | /* | ||
1605 | * For ISP8324, drv_active register has 1 bit per function, | ||
1606 | * shift 1 by func_num to set a bit for the function. | ||
1607 | * For ISP8022, drv_active has 4 bits per function | ||
1608 | */ | ||
1609 | if (is_qla8032(ha)) | ||
1610 | drv_state &= ~(1 << ha->func_num); | ||
1611 | else | ||
1612 | drv_state &= ~(1 << (ha->func_num * 4)); | ||
1613 | |||
1565 | ql4_printk(KERN_INFO, ha, "%s(%ld): drv_state: 0x%08x\n", | 1614 | ql4_printk(KERN_INFO, ha, "%s(%ld): drv_state: 0x%08x\n", |
1566 | __func__, ha->host_no, drv_state); | 1615 | __func__, ha->host_no, drv_state); |
1567 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, drv_state); | 1616 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, drv_state); |
@@ -1573,7 +1622,17 @@ qla4_8xxx_set_qsnt_ready(struct scsi_qla_host *ha) | |||
1573 | uint32_t qsnt_state; | 1622 | uint32_t qsnt_state; |
1574 | 1623 | ||
1575 | qsnt_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE); | 1624 | qsnt_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE); |
1576 | qsnt_state |= (2 << (ha->func_num * 4)); | 1625 | |
1626 | /* | ||
1627 | * For ISP8324, drv_active register has 1 bit per function, | ||
1628 | * shift 1 by func_num to set a bit for the function. | ||
1629 | * For ISP8022, drv_active has 4 bits per function. | ||
1630 | */ | ||
1631 | if (is_qla8032(ha)) | ||
1632 | qsnt_state |= (1 << ha->func_num); | ||
1633 | else | ||
1634 | qsnt_state |= (2 << (ha->func_num * 4)); | ||
1635 | |||
1577 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, qsnt_state); | 1636 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, qsnt_state); |
1578 | } | 1637 | } |
1579 | 1638 | ||
@@ -2104,6 +2163,196 @@ static void qla4_8xxx_mark_entry_skipped(struct scsi_qla_host *ha, | |||
2104 | entry_hdr->d_ctrl.entry_capture_mask)); | 2163 | entry_hdr->d_ctrl.entry_capture_mask)); |
2105 | } | 2164 | } |
2106 | 2165 | ||
2166 | /* ISP83xx functions to process new minidump entries... */ | ||
2167 | static uint32_t qla83xx_minidump_process_pollrd(struct scsi_qla_host *ha, | ||
2168 | struct qla8xxx_minidump_entry_hdr *entry_hdr, | ||
2169 | uint32_t **d_ptr) | ||
2170 | { | ||
2171 | uint32_t r_addr, s_addr, s_value, r_value, poll_wait, poll_mask; | ||
2172 | uint16_t s_stride, i; | ||
2173 | uint32_t *data_ptr = *d_ptr; | ||
2174 | uint32_t rval = QLA_SUCCESS; | ||
2175 | struct qla83xx_minidump_entry_pollrd *pollrd_hdr; | ||
2176 | |||
2177 | pollrd_hdr = (struct qla83xx_minidump_entry_pollrd *)entry_hdr; | ||
2178 | s_addr = le32_to_cpu(pollrd_hdr->select_addr); | ||
2179 | r_addr = le32_to_cpu(pollrd_hdr->read_addr); | ||
2180 | s_value = le32_to_cpu(pollrd_hdr->select_value); | ||
2181 | s_stride = le32_to_cpu(pollrd_hdr->select_value_stride); | ||
2182 | |||
2183 | poll_wait = le32_to_cpu(pollrd_hdr->poll_wait); | ||
2184 | poll_mask = le32_to_cpu(pollrd_hdr->poll_mask); | ||
2185 | |||
2186 | for (i = 0; i < le32_to_cpu(pollrd_hdr->op_count); i++) { | ||
2187 | ha->isp_ops->wr_reg_indirect(ha, s_addr, s_value); | ||
2188 | poll_wait = le32_to_cpu(pollrd_hdr->poll_wait); | ||
2189 | while (1) { | ||
2190 | ha->isp_ops->rd_reg_indirect(ha, s_addr, &r_value); | ||
2191 | |||
2192 | if ((r_value & poll_mask) != 0) { | ||
2193 | break; | ||
2194 | } else { | ||
2195 | msleep(1); | ||
2196 | if (--poll_wait == 0) { | ||
2197 | ql4_printk(KERN_ERR, ha, "%s: TIMEOUT\n", | ||
2198 | __func__); | ||
2199 | rval = QLA_ERROR; | ||
2200 | goto exit_process_pollrd; | ||
2201 | } | ||
2202 | } | ||
2203 | } | ||
2204 | ha->isp_ops->rd_reg_indirect(ha, r_addr, &r_value); | ||
2205 | *data_ptr++ = cpu_to_le32(s_value); | ||
2206 | *data_ptr++ = cpu_to_le32(r_value); | ||
2207 | s_value += s_stride; | ||
2208 | } | ||
2209 | |||
2210 | *d_ptr = data_ptr; | ||
2211 | |||
2212 | exit_process_pollrd: | ||
2213 | return rval; | ||
2214 | } | ||
2215 | |||
2216 | static void qla83xx_minidump_process_rdmux2(struct scsi_qla_host *ha, | ||
2217 | struct qla8xxx_minidump_entry_hdr *entry_hdr, | ||
2218 | uint32_t **d_ptr) | ||
2219 | { | ||
2220 | uint32_t sel_val1, sel_val2, t_sel_val, data, i; | ||
2221 | uint32_t sel_addr1, sel_addr2, sel_val_mask, read_addr; | ||
2222 | struct qla83xx_minidump_entry_rdmux2 *rdmux2_hdr; | ||
2223 | uint32_t *data_ptr = *d_ptr; | ||
2224 | |||
2225 | rdmux2_hdr = (struct qla83xx_minidump_entry_rdmux2 *)entry_hdr; | ||
2226 | sel_val1 = le32_to_cpu(rdmux2_hdr->select_value_1); | ||
2227 | sel_val2 = le32_to_cpu(rdmux2_hdr->select_value_2); | ||
2228 | sel_addr1 = le32_to_cpu(rdmux2_hdr->select_addr_1); | ||
2229 | sel_addr2 = le32_to_cpu(rdmux2_hdr->select_addr_2); | ||
2230 | sel_val_mask = le32_to_cpu(rdmux2_hdr->select_value_mask); | ||
2231 | read_addr = le32_to_cpu(rdmux2_hdr->read_addr); | ||
2232 | |||
2233 | for (i = 0; i < rdmux2_hdr->op_count; i++) { | ||
2234 | ha->isp_ops->wr_reg_indirect(ha, sel_addr1, sel_val1); | ||
2235 | t_sel_val = sel_val1 & sel_val_mask; | ||
2236 | *data_ptr++ = cpu_to_le32(t_sel_val); | ||
2237 | |||
2238 | ha->isp_ops->wr_reg_indirect(ha, sel_addr2, t_sel_val); | ||
2239 | ha->isp_ops->rd_reg_indirect(ha, read_addr, &data); | ||
2240 | |||
2241 | *data_ptr++ = cpu_to_le32(data); | ||
2242 | |||
2243 | ha->isp_ops->wr_reg_indirect(ha, sel_addr1, sel_val2); | ||
2244 | t_sel_val = sel_val2 & sel_val_mask; | ||
2245 | *data_ptr++ = cpu_to_le32(t_sel_val); | ||
2246 | |||
2247 | ha->isp_ops->wr_reg_indirect(ha, sel_addr2, t_sel_val); | ||
2248 | ha->isp_ops->rd_reg_indirect(ha, read_addr, &data); | ||
2249 | |||
2250 | *data_ptr++ = cpu_to_le32(data); | ||
2251 | |||
2252 | sel_val1 += rdmux2_hdr->select_value_stride; | ||
2253 | sel_val2 += rdmux2_hdr->select_value_stride; | ||
2254 | } | ||
2255 | |||
2256 | *d_ptr = data_ptr; | ||
2257 | } | ||
2258 | |||
2259 | static uint32_t qla83xx_minidump_process_pollrdmwr(struct scsi_qla_host *ha, | ||
2260 | struct qla8xxx_minidump_entry_hdr *entry_hdr, | ||
2261 | uint32_t **d_ptr) | ||
2262 | { | ||
2263 | uint32_t poll_wait, poll_mask, r_value, data; | ||
2264 | uint32_t addr_1, addr_2, value_1, value_2; | ||
2265 | uint32_t *data_ptr = *d_ptr; | ||
2266 | uint32_t rval = QLA_SUCCESS; | ||
2267 | struct qla83xx_minidump_entry_pollrdmwr *poll_hdr; | ||
2268 | |||
2269 | poll_hdr = (struct qla83xx_minidump_entry_pollrdmwr *)entry_hdr; | ||
2270 | addr_1 = le32_to_cpu(poll_hdr->addr_1); | ||
2271 | addr_2 = le32_to_cpu(poll_hdr->addr_2); | ||
2272 | value_1 = le32_to_cpu(poll_hdr->value_1); | ||
2273 | value_2 = le32_to_cpu(poll_hdr->value_2); | ||
2274 | poll_mask = le32_to_cpu(poll_hdr->poll_mask); | ||
2275 | |||
2276 | ha->isp_ops->wr_reg_indirect(ha, addr_1, value_1); | ||
2277 | |||
2278 | poll_wait = le32_to_cpu(poll_hdr->poll_wait); | ||
2279 | while (1) { | ||
2280 | ha->isp_ops->rd_reg_indirect(ha, addr_1, &r_value); | ||
2281 | |||
2282 | if ((r_value & poll_mask) != 0) { | ||
2283 | break; | ||
2284 | } else { | ||
2285 | msleep(1); | ||
2286 | if (--poll_wait == 0) { | ||
2287 | ql4_printk(KERN_ERR, ha, "%s: TIMEOUT_1\n", | ||
2288 | __func__); | ||
2289 | rval = QLA_ERROR; | ||
2290 | goto exit_process_pollrdmwr; | ||
2291 | } | ||
2292 | } | ||
2293 | } | ||
2294 | |||
2295 | ha->isp_ops->rd_reg_indirect(ha, addr_2, &data); | ||
2296 | data &= le32_to_cpu(poll_hdr->modify_mask); | ||
2297 | ha->isp_ops->wr_reg_indirect(ha, addr_2, data); | ||
2298 | ha->isp_ops->wr_reg_indirect(ha, addr_1, value_2); | ||
2299 | |||
2300 | poll_wait = le32_to_cpu(poll_hdr->poll_wait); | ||
2301 | while (1) { | ||
2302 | ha->isp_ops->rd_reg_indirect(ha, addr_1, &r_value); | ||
2303 | |||
2304 | if ((r_value & poll_mask) != 0) { | ||
2305 | break; | ||
2306 | } else { | ||
2307 | msleep(1); | ||
2308 | if (--poll_wait == 0) { | ||
2309 | ql4_printk(KERN_ERR, ha, "%s: TIMEOUT_2\n", | ||
2310 | __func__); | ||
2311 | rval = QLA_ERROR; | ||
2312 | goto exit_process_pollrdmwr; | ||
2313 | } | ||
2314 | } | ||
2315 | } | ||
2316 | |||
2317 | *data_ptr++ = cpu_to_le32(addr_2); | ||
2318 | *data_ptr++ = cpu_to_le32(data); | ||
2319 | *d_ptr = data_ptr; | ||
2320 | |||
2321 | exit_process_pollrdmwr: | ||
2322 | return rval; | ||
2323 | } | ||
2324 | |||
2325 | static uint32_t qla4_83xx_minidump_process_rdrom(struct scsi_qla_host *ha, | ||
2326 | struct qla8xxx_minidump_entry_hdr *entry_hdr, | ||
2327 | uint32_t **d_ptr) | ||
2328 | { | ||
2329 | uint32_t fl_addr, u32_count, rval; | ||
2330 | struct qla8xxx_minidump_entry_rdrom *rom_hdr; | ||
2331 | uint32_t *data_ptr = *d_ptr; | ||
2332 | |||
2333 | rom_hdr = (struct qla8xxx_minidump_entry_rdrom *)entry_hdr; | ||
2334 | fl_addr = le32_to_cpu(rom_hdr->read_addr); | ||
2335 | u32_count = le32_to_cpu(rom_hdr->read_data_size)/sizeof(uint32_t); | ||
2336 | |||
2337 | DEBUG2(ql4_printk(KERN_INFO, ha, "[%s]: fl_addr: 0x%x, count: 0x%x\n", | ||
2338 | __func__, fl_addr, u32_count)); | ||
2339 | |||
2340 | rval = qla4_83xx_lockless_flash_read_u32(ha, fl_addr, | ||
2341 | (u8 *)(data_ptr), u32_count); | ||
2342 | |||
2343 | if (rval == QLA_ERROR) { | ||
2344 | ql4_printk(KERN_ERR, ha, "%s: Flash Read Error,Count=%d\n", | ||
2345 | __func__, u32_count); | ||
2346 | goto exit_process_rdrom; | ||
2347 | } | ||
2348 | |||
2349 | data_ptr += u32_count; | ||
2350 | *d_ptr = data_ptr; | ||
2351 | |||
2352 | exit_process_rdrom: | ||
2353 | return rval; | ||
2354 | } | ||
2355 | |||
2107 | /** | 2356 | /** |
2108 | * qla4_8xxx_collect_md_data - Retrieve firmware minidump data. | 2357 | * qla4_8xxx_collect_md_data - Retrieve firmware minidump data. |
2109 | * @ha: pointer to adapter structure | 2358 | * @ha: pointer to adapter structure |
@@ -2151,6 +2400,10 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha) | |||
2151 | (((uint8_t *)ha->fw_dump_tmplt_hdr) + | 2400 | (((uint8_t *)ha->fw_dump_tmplt_hdr) + |
2152 | tmplt_hdr->first_entry_offset); | 2401 | tmplt_hdr->first_entry_offset); |
2153 | 2402 | ||
2403 | if (is_qla8032(ha)) | ||
2404 | tmplt_hdr->saved_state_array[QLA83XX_SS_OCM_WNDREG_INDEX] = | ||
2405 | tmplt_hdr->ocm_window_reg[ha->func_num]; | ||
2406 | |||
2154 | /* Walk through the entry headers - validate/perform required action */ | 2407 | /* Walk through the entry headers - validate/perform required action */ |
2155 | for (i = 0; i < num_entry_hdr; i++) { | 2408 | for (i = 0; i < num_entry_hdr; i++) { |
2156 | if (data_collected >= ha->fw_dump_size) { | 2409 | if (data_collected >= ha->fw_dump_size) { |
@@ -2201,8 +2454,18 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha) | |||
2201 | break; | 2454 | break; |
2202 | case QLA8XXX_BOARD: | 2455 | case QLA8XXX_BOARD: |
2203 | case QLA8XXX_RDROM: | 2456 | case QLA8XXX_RDROM: |
2204 | qla4_82xx_minidump_process_rdrom(ha, entry_hdr, | 2457 | if (is_qla8022(ha)) { |
2205 | &data_ptr); | 2458 | qla4_82xx_minidump_process_rdrom(ha, entry_hdr, |
2459 | &data_ptr); | ||
2460 | } else if (is_qla8032(ha)) { | ||
2461 | rval = qla4_83xx_minidump_process_rdrom(ha, | ||
2462 | entry_hdr, | ||
2463 | &data_ptr); | ||
2464 | if (rval != QLA_SUCCESS) | ||
2465 | qla4_8xxx_mark_entry_skipped(ha, | ||
2466 | entry_hdr, | ||
2467 | i); | ||
2468 | } | ||
2206 | break; | 2469 | break; |
2207 | case QLA8XXX_L2DTG: | 2470 | case QLA8XXX_L2DTG: |
2208 | case QLA8XXX_L2ITG: | 2471 | case QLA8XXX_L2ITG: |
@@ -2215,6 +2478,8 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha) | |||
2215 | goto md_failed; | 2478 | goto md_failed; |
2216 | } | 2479 | } |
2217 | break; | 2480 | break; |
2481 | case QLA8XXX_L1DTG: | ||
2482 | case QLA8XXX_L1ITG: | ||
2218 | case QLA8XXX_L1DAT: | 2483 | case QLA8XXX_L1DAT: |
2219 | case QLA8XXX_L1INS: | 2484 | case QLA8XXX_L1INS: |
2220 | qla4_8xxx_minidump_process_l1cache(ha, entry_hdr, | 2485 | qla4_8xxx_minidump_process_l1cache(ha, entry_hdr, |
@@ -2232,6 +2497,34 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha) | |||
2232 | qla4_8xxx_minidump_process_queue(ha, entry_hdr, | 2497 | qla4_8xxx_minidump_process_queue(ha, entry_hdr, |
2233 | &data_ptr); | 2498 | &data_ptr); |
2234 | break; | 2499 | break; |
2500 | case QLA83XX_POLLRD: | ||
2501 | if (!is_qla8032(ha)) { | ||
2502 | qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i); | ||
2503 | break; | ||
2504 | } | ||
2505 | rval = qla83xx_minidump_process_pollrd(ha, entry_hdr, | ||
2506 | &data_ptr); | ||
2507 | if (rval != QLA_SUCCESS) | ||
2508 | qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i); | ||
2509 | break; | ||
2510 | case QLA83XX_RDMUX2: | ||
2511 | if (!is_qla8032(ha)) { | ||
2512 | qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i); | ||
2513 | break; | ||
2514 | } | ||
2515 | qla83xx_minidump_process_rdmux2(ha, entry_hdr, | ||
2516 | &data_ptr); | ||
2517 | break; | ||
2518 | case QLA83XX_POLLRDMWR: | ||
2519 | if (!is_qla8032(ha)) { | ||
2520 | qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i); | ||
2521 | break; | ||
2522 | } | ||
2523 | rval = qla83xx_minidump_process_pollrdmwr(ha, entry_hdr, | ||
2524 | &data_ptr); | ||
2525 | if (rval != QLA_SUCCESS) | ||
2526 | qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i); | ||
2527 | break; | ||
2235 | case QLA8XXX_RDNOP: | 2528 | case QLA8XXX_RDNOP: |
2236 | default: | 2529 | default: |
2237 | qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i); | 2530 | qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i); |
@@ -2283,7 +2576,7 @@ static void qla4_8xxx_uevent_emit(struct scsi_qla_host *ha, u32 code) | |||
2283 | kobject_uevent_env(&(&ha->pdev->dev)->kobj, KOBJ_CHANGE, envp); | 2576 | kobject_uevent_env(&(&ha->pdev->dev)->kobj, KOBJ_CHANGE, envp); |
2284 | } | 2577 | } |
2285 | 2578 | ||
2286 | static void qla4_8xxx_get_minidump(struct scsi_qla_host *ha) | 2579 | void qla4_8xxx_get_minidump(struct scsi_qla_host *ha) |
2287 | { | 2580 | { |
2288 | if (ql4xenablemd && test_bit(AF_FW_RECOVERY, &ha->flags) && | 2581 | if (ql4xenablemd && test_bit(AF_FW_RECOVERY, &ha->flags) && |
2289 | !test_bit(AF_82XX_FW_DUMPED, &ha->flags)) { | 2582 | !test_bit(AF_82XX_FW_DUMPED, &ha->flags)) { |
@@ -2303,12 +2596,11 @@ static void qla4_8xxx_get_minidump(struct scsi_qla_host *ha) | |||
2303 | * | 2596 | * |
2304 | * Note: IDC lock must be held upon entry | 2597 | * Note: IDC lock must be held upon entry |
2305 | **/ | 2598 | **/ |
2306 | static int | 2599 | int qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha) |
2307 | qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha) | ||
2308 | { | 2600 | { |
2309 | int rval = QLA_ERROR; | 2601 | int rval = QLA_ERROR; |
2310 | int i, timeout; | 2602 | int i, timeout; |
2311 | uint32_t old_count, count; | 2603 | uint32_t old_count, count, idc_ctrl; |
2312 | int need_reset = 0, peg_stuck = 1; | 2604 | int need_reset = 0, peg_stuck = 1; |
2313 | 2605 | ||
2314 | need_reset = ha->isp_ops->need_reset(ha); | 2606 | need_reset = ha->isp_ops->need_reset(ha); |
@@ -2351,8 +2643,24 @@ dev_initialize: | |||
2351 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, | 2643 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, |
2352 | QLA8XXX_DEV_INITIALIZING); | 2644 | QLA8XXX_DEV_INITIALIZING); |
2353 | 2645 | ||
2646 | /* | ||
2647 | * For ISP8324, if IDC_CTRL GRACEFUL_RESET_BIT1 is set, reset it after | ||
2648 | * device goes to INIT state. | ||
2649 | */ | ||
2650 | if (is_qla8032(ha)) { | ||
2651 | idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL); | ||
2652 | if (idc_ctrl & GRACEFUL_RESET_BIT1) { | ||
2653 | qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, | ||
2654 | (idc_ctrl & ~GRACEFUL_RESET_BIT1)); | ||
2655 | set_bit(AF_83XX_NO_FW_DUMP, &ha->flags); | ||
2656 | } | ||
2657 | } | ||
2658 | |||
2354 | ha->isp_ops->idc_unlock(ha); | 2659 | ha->isp_ops->idc_unlock(ha); |
2355 | qla4_8xxx_get_minidump(ha); | 2660 | |
2661 | if (is_qla8022(ha)) | ||
2662 | qla4_8xxx_get_minidump(ha); | ||
2663 | |||
2356 | rval = ha->isp_ops->restart_firmware(ha); | 2664 | rval = ha->isp_ops->restart_firmware(ha); |
2357 | ha->isp_ops->idc_lock(ha); | 2665 | ha->isp_ops->idc_lock(ha); |
2358 | 2666 | ||
@@ -2487,14 +2795,77 @@ static void qla4_82xx_set_idc_ver(struct scsi_qla_host *ha) | |||
2487 | } | 2795 | } |
2488 | } | 2796 | } |
2489 | 2797 | ||
2490 | static void qla4_8xxx_update_idc_reg(struct scsi_qla_host *ha) | 2798 | static int qla4_83xx_set_idc_ver(struct scsi_qla_host *ha) |
2491 | { | 2799 | { |
2492 | if (!test_bit(AF_INIT_DONE, &ha->flags)) { | 2800 | int idc_ver; |
2493 | ha->isp_ops->idc_lock(ha); | 2801 | uint32_t drv_active; |
2494 | qla4_8xxx_set_drv_active(ha); | 2802 | int rval = QLA_SUCCESS; |
2803 | |||
2804 | drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE); | ||
2805 | if (drv_active == (1 << ha->func_num)) { | ||
2806 | idc_ver = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_IDC_VERSION); | ||
2807 | idc_ver &= (~0xFF); | ||
2808 | idc_ver |= QLA83XX_IDC_VER_MAJ_VALUE; | ||
2809 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_IDC_VERSION, idc_ver); | ||
2810 | ql4_printk(KERN_INFO, ha, | ||
2811 | "%s: IDC version updated to %d\n", __func__, | ||
2812 | QLA83XX_IDC_VER_MAJ_VALUE); | ||
2813 | } else { | ||
2814 | idc_ver = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_IDC_VERSION); | ||
2815 | idc_ver &= 0xFF; | ||
2816 | if (QLA83XX_IDC_VER_MAJ_VALUE != idc_ver) { | ||
2817 | ql4_printk(KERN_INFO, ha, | ||
2818 | "%s: qla4xxx driver IDC version %d is not compatible with IDC version %d of other drivers!\n", | ||
2819 | __func__, QLA83XX_IDC_VER_MAJ_VALUE, | ||
2820 | idc_ver); | ||
2821 | rval = QLA_ERROR; | ||
2822 | goto exit_set_idc_ver; | ||
2823 | } | ||
2824 | } | ||
2825 | |||
2826 | /* Update IDC_MINOR_VERSION */ | ||
2827 | idc_ver = qla4_83xx_rd_reg(ha, QLA83XX_CRB_IDC_VER_MINOR); | ||
2828 | idc_ver &= ~(0x03 << (ha->func_num * 2)); | ||
2829 | idc_ver |= (QLA83XX_IDC_VER_MIN_VALUE << (ha->func_num * 2)); | ||
2830 | qla4_83xx_wr_reg(ha, QLA83XX_CRB_IDC_VER_MINOR, idc_ver); | ||
2831 | |||
2832 | exit_set_idc_ver: | ||
2833 | return rval; | ||
2834 | } | ||
2835 | |||
2836 | static int qla4_8xxx_update_idc_reg(struct scsi_qla_host *ha) | ||
2837 | { | ||
2838 | uint32_t drv_active; | ||
2839 | int rval = QLA_SUCCESS; | ||
2840 | |||
2841 | if (test_bit(AF_INIT_DONE, &ha->flags)) | ||
2842 | goto exit_update_idc_reg; | ||
2843 | |||
2844 | ha->isp_ops->idc_lock(ha); | ||
2845 | qla4_8xxx_set_drv_active(ha); | ||
2846 | |||
2847 | /* | ||
2848 | * If we are the first driver to load and | ||
2849 | * ql4xdontresethba is not set, clear IDC_CTRL BIT0. | ||
2850 | */ | ||
2851 | if (is_qla8032(ha)) { | ||
2852 | drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE); | ||
2853 | if ((drv_active == (1 << ha->func_num)) && !ql4xdontresethba) | ||
2854 | qla4_83xx_clear_idc_dontreset(ha); | ||
2855 | } | ||
2856 | |||
2857 | if (is_qla8022(ha)) { | ||
2495 | qla4_82xx_set_idc_ver(ha); | 2858 | qla4_82xx_set_idc_ver(ha); |
2496 | ha->isp_ops->idc_unlock(ha); | 2859 | } else if (is_qla8032(ha)) { |
2860 | rval = qla4_83xx_set_idc_ver(ha); | ||
2861 | if (rval == QLA_ERROR) | ||
2862 | qla4_8xxx_clear_drv_active(ha); | ||
2497 | } | 2863 | } |
2864 | |||
2865 | ha->isp_ops->idc_unlock(ha); | ||
2866 | |||
2867 | exit_update_idc_reg: | ||
2868 | return rval; | ||
2498 | } | 2869 | } |
2499 | 2870 | ||
2500 | /** | 2871 | /** |
@@ -2509,7 +2880,9 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) | |||
2509 | int rval = QLA_SUCCESS; | 2880 | int rval = QLA_SUCCESS; |
2510 | unsigned long dev_init_timeout; | 2881 | unsigned long dev_init_timeout; |
2511 | 2882 | ||
2512 | qla4_8xxx_update_idc_reg(ha); | 2883 | rval = qla4_8xxx_update_idc_reg(ha); |
2884 | if (rval == QLA_ERROR) | ||
2885 | goto exit_state_handler; | ||
2513 | 2886 | ||
2514 | dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE); | 2887 | dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE); |
2515 | DEBUG2(ql4_printk(KERN_INFO, ha, "Device state is 0x%x = %s\n", | 2888 | DEBUG2(ql4_printk(KERN_INFO, ha, "Device state is 0x%x = %s\n", |
@@ -2550,16 +2923,25 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) | |||
2550 | ha->isp_ops->idc_lock(ha); | 2923 | ha->isp_ops->idc_lock(ha); |
2551 | break; | 2924 | break; |
2552 | case QLA8XXX_DEV_NEED_RESET: | 2925 | case QLA8XXX_DEV_NEED_RESET: |
2553 | if (!ql4xdontresethba) { | 2926 | /* |
2554 | qla4_82xx_need_reset_handler(ha); | 2927 | * For ISP8324, if NEED_RESET is set by any driver, |
2555 | /* Update timeout value after need | 2928 | * it should be honored, irrespective of IDC_CTRL |
2556 | * reset handler */ | 2929 | * DONTRESET_BIT0 |
2557 | dev_init_timeout = jiffies + | 2930 | */ |
2558 | (ha->nx_dev_init_timeout * HZ); | 2931 | if (is_qla8032(ha)) { |
2559 | } else { | 2932 | qla4_83xx_need_reset_handler(ha); |
2560 | ha->isp_ops->idc_unlock(ha); | 2933 | } else if (is_qla8022(ha)) { |
2561 | msleep(1000); | 2934 | if (!ql4xdontresethba) { |
2562 | ha->isp_ops->idc_lock(ha); | 2935 | qla4_82xx_need_reset_handler(ha); |
2936 | /* Update timeout value after need | ||
2937 | * reset handler */ | ||
2938 | dev_init_timeout = jiffies + | ||
2939 | (ha->nx_dev_init_timeout * HZ); | ||
2940 | } else { | ||
2941 | ha->isp_ops->idc_unlock(ha); | ||
2942 | msleep(1000); | ||
2943 | ha->isp_ops->idc_lock(ha); | ||
2944 | } | ||
2563 | } | 2945 | } |
2564 | break; | 2946 | break; |
2565 | case QLA8XXX_DEV_NEED_QUIESCENT: | 2947 | case QLA8XXX_DEV_NEED_QUIESCENT: |
@@ -2587,6 +2969,7 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) | |||
2587 | } | 2969 | } |
2588 | exit: | 2970 | exit: |
2589 | ha->isp_ops->idc_unlock(ha); | 2971 | ha->isp_ops->idc_unlock(ha); |
2972 | exit_state_handler: | ||
2590 | return rval; | 2973 | return rval; |
2591 | } | 2974 | } |
2592 | 2975 | ||
@@ -2595,8 +2978,13 @@ int qla4_8xxx_load_risc(struct scsi_qla_host *ha) | |||
2595 | int retval; | 2978 | int retval; |
2596 | 2979 | ||
2597 | /* clear the interrupt */ | 2980 | /* clear the interrupt */ |
2598 | writel(0, &ha->qla4_82xx_reg->host_int); | 2981 | if (is_qla8032(ha)) { |
2599 | readl(&ha->qla4_82xx_reg->host_int); | 2982 | writel(0, &ha->qla4_83xx_reg->risc_intr); |
2983 | readl(&ha->qla4_83xx_reg->risc_intr); | ||
2984 | } else if (is_qla8022(ha)) { | ||
2985 | writel(0, &ha->qla4_82xx_reg->host_int); | ||
2986 | readl(&ha->qla4_82xx_reg->host_int); | ||
2987 | } | ||
2600 | 2988 | ||
2601 | retval = qla4_8xxx_device_state_handler(ha); | 2989 | retval = qla4_8xxx_device_state_handler(ha); |
2602 | 2990 | ||
@@ -2695,7 +3083,7 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr) | |||
2695 | const char *loc, *locations[] = { "DEF", "FLT" }; | 3083 | const char *loc, *locations[] = { "DEF", "FLT" }; |
2696 | uint16_t *wptr; | 3084 | uint16_t *wptr; |
2697 | uint16_t cnt, chksum; | 3085 | uint16_t cnt, chksum; |
2698 | uint32_t start; | 3086 | uint32_t start, status; |
2699 | struct qla_flt_header *flt; | 3087 | struct qla_flt_header *flt; |
2700 | struct qla_flt_region *region; | 3088 | struct qla_flt_region *region; |
2701 | struct ql82xx_hw_data *hw = &ha->hw; | 3089 | struct ql82xx_hw_data *hw = &ha->hw; |
@@ -2704,8 +3092,18 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr) | |||
2704 | wptr = (uint16_t *)ha->request_ring; | 3092 | wptr = (uint16_t *)ha->request_ring; |
2705 | flt = (struct qla_flt_header *)ha->request_ring; | 3093 | flt = (struct qla_flt_header *)ha->request_ring; |
2706 | region = (struct qla_flt_region *)&flt[1]; | 3094 | region = (struct qla_flt_region *)&flt[1]; |
2707 | qla4_82xx_read_optrom_data(ha, (uint8_t *)ha->request_ring, | 3095 | |
2708 | flt_addr << 2, OPTROM_BURST_SIZE); | 3096 | if (is_qla8022(ha)) { |
3097 | qla4_82xx_read_optrom_data(ha, (uint8_t *)ha->request_ring, | ||
3098 | flt_addr << 2, OPTROM_BURST_SIZE); | ||
3099 | } else if (is_qla8032(ha)) { | ||
3100 | status = qla4_83xx_flash_read_u32(ha, flt_addr << 2, | ||
3101 | (uint8_t *)ha->request_ring, | ||
3102 | 0x400); | ||
3103 | if (status != QLA_SUCCESS) | ||
3104 | goto no_flash_data; | ||
3105 | } | ||
3106 | |||
2709 | if (*wptr == __constant_cpu_to_le16(0xffff)) | 3107 | if (*wptr == __constant_cpu_to_le16(0xffff)) |
2710 | goto no_flash_data; | 3108 | goto no_flash_data; |
2711 | if (flt->version != __constant_cpu_to_le16(1)) { | 3109 | if (flt->version != __constant_cpu_to_le16(1)) { |
@@ -2918,8 +3316,12 @@ qla4_8xxx_get_flash_info(struct scsi_qla_host *ha) | |||
2918 | return ret; | 3316 | return ret; |
2919 | 3317 | ||
2920 | qla4_8xxx_get_flt_info(ha, flt_addr); | 3318 | qla4_8xxx_get_flt_info(ha, flt_addr); |
2921 | qla4_82xx_get_fdt_info(ha); | 3319 | if (is_qla8022(ha)) { |
2922 | qla4_82xx_get_idc_param(ha); | 3320 | qla4_82xx_get_fdt_info(ha); |
3321 | qla4_82xx_get_idc_param(ha); | ||
3322 | } else if (is_qla8032(ha)) { | ||
3323 | qla4_83xx_get_idc_param(ha); | ||
3324 | } | ||
2923 | 3325 | ||
2924 | return QLA_SUCCESS; | 3326 | return QLA_SUCCESS; |
2925 | } | 3327 | } |
@@ -3063,8 +3465,7 @@ exit_validate_mac82: | |||
3063 | 3465 | ||
3064 | /* Interrupt handling helpers. */ | 3466 | /* Interrupt handling helpers. */ |
3065 | 3467 | ||
3066 | static int | 3468 | int qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha) |
3067 | qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha) | ||
3068 | { | 3469 | { |
3069 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | 3470 | uint32_t mbox_cmd[MBOX_REG_COUNT]; |
3070 | uint32_t mbox_sts[MBOX_REG_COUNT]; | 3471 | uint32_t mbox_sts[MBOX_REG_COUNT]; |
@@ -3085,8 +3486,7 @@ qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha) | |||
3085 | return QLA_SUCCESS; | 3486 | return QLA_SUCCESS; |
3086 | } | 3487 | } |
3087 | 3488 | ||
3088 | static int | 3489 | int qla4_8xxx_mbx_intr_disable(struct scsi_qla_host *ha) |
3089 | qla4_8xxx_mbx_intr_disable(struct scsi_qla_host *ha) | ||
3090 | { | 3490 | { |
3091 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | 3491 | uint32_t mbox_cmd[MBOX_REG_COUNT]; |
3092 | uint32_t mbox_sts[MBOX_REG_COUNT]; | 3492 | uint32_t mbox_sts[MBOX_REG_COUNT]; |
diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h index 1894de093f0..ec5cbd003ba 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.h +++ b/drivers/scsi/qla4xxx/ql4_nx.h | |||
@@ -25,6 +25,8 @@ | |||
25 | #define CRB_RCVPEG_STATE QLA82XX_REG(0x13c) | 25 | #define CRB_RCVPEG_STATE QLA82XX_REG(0x13c) |
26 | #define CRB_DMA_SHIFT QLA82XX_REG(0xcc) | 26 | #define CRB_DMA_SHIFT QLA82XX_REG(0xcc) |
27 | #define CRB_TEMP_STATE QLA82XX_REG(0x1b4) | 27 | #define CRB_TEMP_STATE QLA82XX_REG(0x1b4) |
28 | #define CRB_CMDPEG_CHECK_RETRY_COUNT 60 | ||
29 | #define CRB_CMDPEG_CHECK_DELAY 500 | ||
28 | 30 | ||
29 | #define qla82xx_get_temp_val(x) ((x) >> 16) | 31 | #define qla82xx_get_temp_val(x) ((x) >> 16) |
30 | #define qla82xx_get_temp_state(x) ((x) & 0xffff) | 32 | #define qla82xx_get_temp_state(x) ((x) & 0xffff) |
@@ -508,6 +510,7 @@ enum { | |||
508 | 510 | ||
509 | #define QLA82XX_P2_ADDR_QDR_NET_MAX (0x00000003001fffffULL) | 511 | #define QLA82XX_P2_ADDR_QDR_NET_MAX (0x00000003001fffffULL) |
510 | #define QLA82XX_P3_ADDR_QDR_NET_MAX (0x0000000303ffffffULL) | 512 | #define QLA82XX_P3_ADDR_QDR_NET_MAX (0x0000000303ffffffULL) |
513 | #define QLA8XXX_ADDR_QDR_NET_MAX (0x0000000307ffffffULL) | ||
511 | 514 | ||
512 | #define QLA82XX_PCI_CRBSPACE (unsigned long)0x06000000 | 515 | #define QLA82XX_PCI_CRBSPACE (unsigned long)0x06000000 |
513 | #define QLA82XX_PCI_DIRECT_CRB (unsigned long)0x04400000 | 516 | #define QLA82XX_PCI_DIRECT_CRB (unsigned long)0x04400000 |
@@ -852,9 +855,13 @@ struct crb_addr_pair { | |||
852 | #define QLA8XXX_L2ITG 22 | 855 | #define QLA8XXX_L2ITG 22 |
853 | #define QLA8XXX_L2DAT 23 | 856 | #define QLA8XXX_L2DAT 23 |
854 | #define QLA8XXX_L2INS 24 | 857 | #define QLA8XXX_L2INS 24 |
858 | #define QLA83XX_POLLRD 35 | ||
859 | #define QLA83XX_RDMUX2 36 | ||
860 | #define QLA83XX_POLLRDMWR 37 | ||
855 | #define QLA8XXX_RDROM 71 | 861 | #define QLA8XXX_RDROM 71 |
856 | #define QLA8XXX_RDMEM 72 | 862 | #define QLA8XXX_RDMEM 72 |
857 | #define QLA8XXX_CNTRL 98 | 863 | #define QLA8XXX_CNTRL 98 |
864 | #define QLA83XX_TLHDR 99 | ||
858 | #define QLA8XXX_RDEND 255 | 865 | #define QLA8XXX_RDEND 255 |
859 | 866 | ||
860 | /* Opcodes for Control Entries. | 867 | /* Opcodes for Control Entries. |
@@ -1007,6 +1014,16 @@ struct qla8xxx_minidump_entry_queue { | |||
1007 | #define MD_MIU_TEST_AGT_ADDR_LO 0x41000094 | 1014 | #define MD_MIU_TEST_AGT_ADDR_LO 0x41000094 |
1008 | #define MD_MIU_TEST_AGT_ADDR_HI 0x41000098 | 1015 | #define MD_MIU_TEST_AGT_ADDR_HI 0x41000098 |
1009 | 1016 | ||
1017 | #define MD_MIU_TEST_AGT_WRDATA_LO 0x410000A0 | ||
1018 | #define MD_MIU_TEST_AGT_WRDATA_HI 0x410000A4 | ||
1019 | #define MD_MIU_TEST_AGT_WRDATA_ULO 0x410000B0 | ||
1020 | #define MD_MIU_TEST_AGT_WRDATA_UHI 0x410000B4 | ||
1021 | |||
1022 | #define MD_MIU_TEST_AGT_RDDATA_LO 0x410000A8 | ||
1023 | #define MD_MIU_TEST_AGT_RDDATA_HI 0x410000AC | ||
1024 | #define MD_MIU_TEST_AGT_RDDATA_ULO 0x410000B8 | ||
1025 | #define MD_MIU_TEST_AGT_RDDATA_UHI 0x410000BC | ||
1026 | |||
1010 | static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, | 1027 | static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, |
1011 | 0x410000AC, 0x410000B8, 0x410000BC }; | 1028 | 0x410000AC, 0x410000B8, 0x410000BC }; |
1012 | #endif | 1029 | #endif |
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 519f6667dc0..3e0e5de2c33 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "ql4_glbl.h" | 18 | #include "ql4_glbl.h" |
19 | #include "ql4_dbg.h" | 19 | #include "ql4_dbg.h" |
20 | #include "ql4_inline.h" | 20 | #include "ql4_inline.h" |
21 | #include "ql4_83xx.h" | ||
21 | 22 | ||
22 | /* | 23 | /* |
23 | * Driver version | 24 | * Driver version |
@@ -2315,8 +2316,17 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) | |||
2315 | if (ha->nx_pcibase) | 2316 | if (ha->nx_pcibase) |
2316 | iounmap( | 2317 | iounmap( |
2317 | (struct device_reg_82xx __iomem *)ha->nx_pcibase); | 2318 | (struct device_reg_82xx __iomem *)ha->nx_pcibase); |
2318 | } else if (ha->reg) | 2319 | } else if (is_qla8032(ha)) { |
2320 | if (ha->nx_pcibase) | ||
2321 | iounmap( | ||
2322 | (struct device_reg_83xx __iomem *)ha->nx_pcibase); | ||
2323 | } else if (ha->reg) { | ||
2319 | iounmap(ha->reg); | 2324 | iounmap(ha->reg); |
2325 | } | ||
2326 | |||
2327 | if (ha->reset_tmplt.buff) | ||
2328 | vfree(ha->reset_tmplt.buff); | ||
2329 | |||
2320 | pci_release_regions(ha->pdev); | 2330 | pci_release_regions(ha->pdev); |
2321 | } | 2331 | } |
2322 | 2332 | ||
@@ -2454,7 +2464,6 @@ static int qla4_8xxx_check_temp(struct scsi_qla_host *ha) | |||
2454 | static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) | 2464 | static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) |
2455 | { | 2465 | { |
2456 | uint32_t fw_heartbeat_counter; | 2466 | uint32_t fw_heartbeat_counter; |
2457 | uint32_t halt_status1, halt_status2; | ||
2458 | int status = QLA_SUCCESS; | 2467 | int status = QLA_SUCCESS; |
2459 | 2468 | ||
2460 | fw_heartbeat_counter = qla4_8xxx_rd_direct(ha, | 2469 | fw_heartbeat_counter = qla4_8xxx_rd_direct(ha, |
@@ -2472,28 +2481,7 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) | |||
2472 | /* FW not alive after 2 seconds */ | 2481 | /* FW not alive after 2 seconds */ |
2473 | if (ha->seconds_since_last_heartbeat == 2) { | 2482 | if (ha->seconds_since_last_heartbeat == 2) { |
2474 | ha->seconds_since_last_heartbeat = 0; | 2483 | ha->seconds_since_last_heartbeat = 0; |
2475 | halt_status1 = qla4_8xxx_rd_direct(ha, | 2484 | qla4_8xxx_dump_peg_reg(ha); |
2476 | QLA8XXX_PEG_HALT_STATUS1); | ||
2477 | halt_status2 = qla4_8xxx_rd_direct(ha, | ||
2478 | QLA8XXX_PEG_HALT_STATUS2); | ||
2479 | |||
2480 | ql4_printk(KERN_INFO, ha, | ||
2481 | "scsi(%ld): %s, Dumping hw/fw registers:\n " | ||
2482 | " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2:" | ||
2483 | " 0x%x,\n PEG_NET_0_PC: 0x%x, PEG_NET_1_PC:" | ||
2484 | " 0x%x,\n PEG_NET_2_PC: 0x%x, PEG_NET_3_PC:" | ||
2485 | " 0x%x,\n PEG_NET_4_PC: 0x%x\n", ha->host_no, | ||
2486 | __func__, halt_status1, halt_status2, | ||
2487 | qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 + | ||
2488 | 0x3c), | ||
2489 | qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 + | ||
2490 | 0x3c), | ||
2491 | qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 + | ||
2492 | 0x3c), | ||
2493 | qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 + | ||
2494 | 0x3c), | ||
2495 | qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + | ||
2496 | 0x3c)); | ||
2497 | status = QLA_ERROR; | 2485 | status = QLA_ERROR; |
2498 | } | 2486 | } |
2499 | } else | 2487 | } else |
@@ -2503,6 +2491,48 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) | |||
2503 | return status; | 2491 | return status; |
2504 | } | 2492 | } |
2505 | 2493 | ||
2494 | static void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha) | ||
2495 | { | ||
2496 | uint32_t halt_status; | ||
2497 | int halt_status_unrecoverable = 0; | ||
2498 | |||
2499 | halt_status = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS1); | ||
2500 | |||
2501 | if (is_qla8022(ha)) { | ||
2502 | ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n", | ||
2503 | __func__); | ||
2504 | qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, | ||
2505 | CRB_NIU_XG_PAUSE_CTL_P0 | | ||
2506 | CRB_NIU_XG_PAUSE_CTL_P1); | ||
2507 | |||
2508 | if (QLA82XX_FWERROR_CODE(halt_status) == 0x67) | ||
2509 | ql4_printk(KERN_ERR, ha, "%s: Firmware aborted with error code 0x00006700. Device is being reset\n", | ||
2510 | __func__); | ||
2511 | if (halt_status & HALT_STATUS_UNRECOVERABLE) | ||
2512 | halt_status_unrecoverable = 1; | ||
2513 | } else if (is_qla8032(ha)) { | ||
2514 | if (halt_status & QLA83XX_HALT_STATUS_FW_RESET) | ||
2515 | ql4_printk(KERN_ERR, ha, "%s: Firmware error detected device is being reset\n", | ||
2516 | __func__); | ||
2517 | else if (halt_status & QLA83XX_HALT_STATUS_UNRECOVERABLE) | ||
2518 | halt_status_unrecoverable = 1; | ||
2519 | } | ||
2520 | |||
2521 | /* | ||
2522 | * Since we cannot change dev_state in interrupt context, | ||
2523 | * set appropriate DPC flag then wakeup DPC | ||
2524 | */ | ||
2525 | if (halt_status_unrecoverable) { | ||
2526 | set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); | ||
2527 | } else { | ||
2528 | ql4_printk(KERN_INFO, ha, "%s: detect abort needed!\n", | ||
2529 | __func__); | ||
2530 | set_bit(DPC_RESET_HA, &ha->dpc_flags); | ||
2531 | } | ||
2532 | qla4xxx_mailbox_premature_completion(ha); | ||
2533 | qla4xxx_wake_dpc(ha); | ||
2534 | } | ||
2535 | |||
2506 | /** | 2536 | /** |
2507 | * qla4_8xxx_watchdog - Poll dev state | 2537 | * qla4_8xxx_watchdog - Poll dev state |
2508 | * @ha: Pointer to host adapter structure. | 2538 | * @ha: Pointer to host adapter structure. |
@@ -2511,7 +2541,7 @@ static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) | |||
2511 | **/ | 2541 | **/ |
2512 | void qla4_8xxx_watchdog(struct scsi_qla_host *ha) | 2542 | void qla4_8xxx_watchdog(struct scsi_qla_host *ha) |
2513 | { | 2543 | { |
2514 | uint32_t dev_state, halt_status; | 2544 | uint32_t dev_state; |
2515 | 2545 | ||
2516 | /* don't poll if reset is going on */ | 2546 | /* don't poll if reset is going on */ |
2517 | if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || | 2547 | if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || |
@@ -2520,16 +2550,18 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) | |||
2520 | dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE); | 2550 | dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE); |
2521 | 2551 | ||
2522 | if (qla4_8xxx_check_temp(ha)) { | 2552 | if (qla4_8xxx_check_temp(ha)) { |
2523 | ql4_printk(KERN_INFO, ha, "disabling pause" | 2553 | if (is_qla8022(ha)) { |
2524 | " transmit on port 0 & 1.\n"); | 2554 | ql4_printk(KERN_INFO, ha, "disabling pause transmit on port 0 & 1.\n"); |
2525 | qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, | 2555 | qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, |
2526 | CRB_NIU_XG_PAUSE_CTL_P0 | | 2556 | CRB_NIU_XG_PAUSE_CTL_P0 | |
2527 | CRB_NIU_XG_PAUSE_CTL_P1); | 2557 | CRB_NIU_XG_PAUSE_CTL_P1); |
2558 | } | ||
2528 | set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); | 2559 | set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); |
2529 | qla4xxx_wake_dpc(ha); | 2560 | qla4xxx_wake_dpc(ha); |
2530 | } else if (dev_state == QLA8XXX_DEV_NEED_RESET && | 2561 | } else if (dev_state == QLA8XXX_DEV_NEED_RESET && |
2531 | !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { | 2562 | !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { |
2532 | if (!ql4xdontresethba) { | 2563 | if (is_qla8032(ha) || |
2564 | (is_qla8022(ha) && !ql4xdontresethba)) { | ||
2533 | ql4_printk(KERN_INFO, ha, "%s: HW State: " | 2565 | ql4_printk(KERN_INFO, ha, "%s: HW State: " |
2534 | "NEED RESET!\n", __func__); | 2566 | "NEED RESET!\n", __func__); |
2535 | set_bit(DPC_RESET_HA, &ha->dpc_flags); | 2567 | set_bit(DPC_RESET_HA, &ha->dpc_flags); |
@@ -2543,36 +2575,8 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) | |||
2543 | qla4xxx_wake_dpc(ha); | 2575 | qla4xxx_wake_dpc(ha); |
2544 | } else { | 2576 | } else { |
2545 | /* Check firmware health */ | 2577 | /* Check firmware health */ |
2546 | if (qla4_8xxx_check_fw_alive(ha)) { | 2578 | if (qla4_8xxx_check_fw_alive(ha)) |
2547 | ql4_printk(KERN_INFO, ha, "disabling pause" | 2579 | qla4_8xxx_process_fw_error(ha); |
2548 | " transmit on port 0 & 1.\n"); | ||
2549 | qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, | ||
2550 | CRB_NIU_XG_PAUSE_CTL_P0 | | ||
2551 | CRB_NIU_XG_PAUSE_CTL_P1); | ||
2552 | halt_status = qla4_8xxx_rd_direct(ha, | ||
2553 | QLA8XXX_PEG_HALT_STATUS1); | ||
2554 | |||
2555 | if (QLA82XX_FWERROR_CODE(halt_status) == 0x67) | ||
2556 | ql4_printk(KERN_ERR, ha, "%s:" | ||
2557 | " Firmware aborted with" | ||
2558 | " error code 0x00006700." | ||
2559 | " Device is being reset\n", | ||
2560 | __func__); | ||
2561 | |||
2562 | /* Since we cannot change dev_state in interrupt | ||
2563 | * context, set appropriate DPC flag then wakeup | ||
2564 | * DPC */ | ||
2565 | if (halt_status & HALT_STATUS_UNRECOVERABLE) | ||
2566 | set_bit(DPC_HA_UNRECOVERABLE, | ||
2567 | &ha->dpc_flags); | ||
2568 | else { | ||
2569 | ql4_printk(KERN_INFO, ha, "%s: detect " | ||
2570 | "abort needed!\n", __func__); | ||
2571 | set_bit(DPC_RESET_HA, &ha->dpc_flags); | ||
2572 | } | ||
2573 | qla4xxx_mailbox_premature_completion(ha); | ||
2574 | qla4xxx_wake_dpc(ha); | ||
2575 | } | ||
2576 | } | 2580 | } |
2577 | } | 2581 | } |
2578 | } | 2582 | } |
@@ -2654,9 +2658,8 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) | |||
2654 | if (!pci_channel_offline(ha->pdev)) | 2658 | if (!pci_channel_offline(ha->pdev)) |
2655 | pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); | 2659 | pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); |
2656 | 2660 | ||
2657 | if (is_qla8022(ha)) { | 2661 | if (is_qla80XX(ha)) |
2658 | qla4_8xxx_watchdog(ha); | 2662 | qla4_8xxx_watchdog(ha); |
2659 | } | ||
2660 | 2663 | ||
2661 | if (is_qla40XX(ha)) { | 2664 | if (is_qla40XX(ha)) { |
2662 | /* Check for heartbeat interval. */ | 2665 | /* Check for heartbeat interval. */ |
@@ -2955,9 +2958,9 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) | |||
2955 | goto recover_ha_init_adapter; | 2958 | goto recover_ha_init_adapter; |
2956 | } | 2959 | } |
2957 | 2960 | ||
2958 | /* For the ISP-82xx adapter, issue a stop_firmware if invoked | 2961 | /* For the ISP-8xxx adapter, issue a stop_firmware if invoked |
2959 | * from eh_host_reset or ioctl module */ | 2962 | * from eh_host_reset or ioctl module */ |
2960 | if (is_qla8022(ha) && !reset_chip && | 2963 | if (is_qla80XX(ha) && !reset_chip && |
2961 | test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { | 2964 | test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { |
2962 | 2965 | ||
2963 | DEBUG2(ql4_printk(KERN_INFO, ha, | 2966 | DEBUG2(ql4_printk(KERN_INFO, ha, |
@@ -2980,13 +2983,13 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) | |||
2980 | } | 2983 | } |
2981 | 2984 | ||
2982 | /* Issue full chip reset if recovering from a catastrophic error, | 2985 | /* Issue full chip reset if recovering from a catastrophic error, |
2983 | * or if stop_firmware fails for ISP-82xx. | 2986 | * or if stop_firmware fails for ISP-8xxx. |
2984 | * This is the default case for ISP-4xxx */ | 2987 | * This is the default case for ISP-4xxx */ |
2985 | if (is_qla40XX(ha) || reset_chip) { | 2988 | if (is_qla40XX(ha) || reset_chip) { |
2986 | if (is_qla40XX(ha)) | 2989 | if (is_qla40XX(ha)) |
2987 | goto chip_reset; | 2990 | goto chip_reset; |
2988 | 2991 | ||
2989 | /* Check if 82XX firmware is alive or not | 2992 | /* Check if 8XXX firmware is alive or not |
2990 | * We may have arrived here from NEED_RESET | 2993 | * We may have arrived here from NEED_RESET |
2991 | * detection only */ | 2994 | * detection only */ |
2992 | if (test_bit(AF_FW_RECOVERY, &ha->flags)) | 2995 | if (test_bit(AF_FW_RECOVERY, &ha->flags)) |
@@ -3041,7 +3044,7 @@ recover_ha_init_adapter: | |||
3041 | * Since we don't want to block the DPC for too long | 3044 | * Since we don't want to block the DPC for too long |
3042 | * with multiple resets in the same thread, | 3045 | * with multiple resets in the same thread, |
3043 | * utilize DPC to retry */ | 3046 | * utilize DPC to retry */ |
3044 | if (is_qla8022(ha)) { | 3047 | if (is_qla80XX(ha)) { |
3045 | ha->isp_ops->idc_lock(ha); | 3048 | ha->isp_ops->idc_lock(ha); |
3046 | dev_state = qla4_8xxx_rd_direct(ha, | 3049 | dev_state = qla4_8xxx_rd_direct(ha, |
3047 | QLA8XXX_CRB_DEV_STATE); | 3050 | QLA8XXX_CRB_DEV_STATE); |
@@ -3386,7 +3389,7 @@ static void qla4xxx_do_dpc(struct work_struct *work) | |||
3386 | /* post events to application */ | 3389 | /* post events to application */ |
3387 | qla4xxx_do_work(ha); | 3390 | qla4xxx_do_work(ha); |
3388 | 3391 | ||
3389 | if (is_qla8022(ha)) { | 3392 | if (is_qla80XX(ha)) { |
3390 | if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { | 3393 | if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { |
3391 | ha->isp_ops->idc_lock(ha); | 3394 | ha->isp_ops->idc_lock(ha); |
3392 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, | 3395 | qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, |
@@ -3404,7 +3407,8 @@ static void qla4xxx_do_dpc(struct work_struct *work) | |||
3404 | (test_bit(DPC_RESET_HA, &ha->dpc_flags) || | 3407 | (test_bit(DPC_RESET_HA, &ha->dpc_flags) || |
3405 | test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || | 3408 | test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || |
3406 | test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) { | 3409 | test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) { |
3407 | if (ql4xdontresethba) { | 3410 | if ((is_qla8022(ha) && ql4xdontresethba) || |
3411 | (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) { | ||
3408 | DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", | 3412 | DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", |
3409 | ha->host_no, __func__)); | 3413 | ha->host_no, __func__)); |
3410 | clear_bit(DPC_RESET_HA, &ha->dpc_flags); | 3414 | clear_bit(DPC_RESET_HA, &ha->dpc_flags); |
@@ -3514,7 +3518,7 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha) | |||
3514 | /* Put firmware in known state */ | 3518 | /* Put firmware in known state */ |
3515 | ha->isp_ops->reset_firmware(ha); | 3519 | ha->isp_ops->reset_firmware(ha); |
3516 | 3520 | ||
3517 | if (is_qla8022(ha)) { | 3521 | if (is_qla80XX(ha)) { |
3518 | ha->isp_ops->idc_lock(ha); | 3522 | ha->isp_ops->idc_lock(ha); |
3519 | qla4_8xxx_clear_drv_active(ha); | 3523 | qla4_8xxx_clear_drv_active(ha); |
3520 | ha->isp_ops->idc_unlock(ha); | 3524 | ha->isp_ops->idc_unlock(ha); |
@@ -3564,16 +3568,20 @@ int qla4_8xxx_iospace_config(struct scsi_qla_host *ha) | |||
3564 | /* Mapping of IO base pointer, door bell read and write pointer */ | 3568 | /* Mapping of IO base pointer, door bell read and write pointer */ |
3565 | 3569 | ||
3566 | /* mapping of IO base pointer */ | 3570 | /* mapping of IO base pointer */ |
3567 | ha->qla4_82xx_reg = | 3571 | if (is_qla8022(ha)) { |
3568 | (struct device_reg_82xx __iomem *)((uint8_t *)ha->nx_pcibase + | 3572 | ha->qla4_82xx_reg = (struct device_reg_82xx __iomem *) |
3569 | 0xbc000 + (ha->pdev->devfn << 11)); | 3573 | ((uint8_t *)ha->nx_pcibase + 0xbc000 + |
3574 | (ha->pdev->devfn << 11)); | ||
3575 | ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 : | ||
3576 | QLA82XX_CAM_RAM_DB2); | ||
3577 | } else if (is_qla8032(ha)) { | ||
3578 | ha->qla4_83xx_reg = (struct device_reg_83xx __iomem *) | ||
3579 | ((uint8_t *)ha->nx_pcibase); | ||
3580 | } | ||
3570 | 3581 | ||
3571 | db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */ | 3582 | db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */ |
3572 | db_len = pci_resource_len(pdev, 4); | 3583 | db_len = pci_resource_len(pdev, 4); |
3573 | 3584 | ||
3574 | ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 : | ||
3575 | QLA82XX_CAM_RAM_DB2); | ||
3576 | |||
3577 | return 0; | 3585 | return 0; |
3578 | iospace_error_exit: | 3586 | iospace_error_exit: |
3579 | return -ENOMEM; | 3587 | return -ENOMEM; |
@@ -3693,6 +3701,34 @@ static struct isp_operations qla4_82xx_isp_ops = { | |||
3693 | .process_mailbox_interrupt = qla4_82xx_process_mbox_intr, | 3701 | .process_mailbox_interrupt = qla4_82xx_process_mbox_intr, |
3694 | }; | 3702 | }; |
3695 | 3703 | ||
3704 | static struct isp_operations qla4_83xx_isp_ops = { | ||
3705 | .iospace_config = qla4_8xxx_iospace_config, | ||
3706 | .pci_config = qla4_8xxx_pci_config, | ||
3707 | .disable_intrs = qla4_83xx_disable_intrs, | ||
3708 | .enable_intrs = qla4_83xx_enable_intrs, | ||
3709 | .start_firmware = qla4_8xxx_load_risc, | ||
3710 | .restart_firmware = qla4_83xx_start_firmware, | ||
3711 | .intr_handler = qla4_83xx_intr_handler, | ||
3712 | .interrupt_service_routine = qla4_83xx_interrupt_service_routine, | ||
3713 | .need_reset = qla4_8xxx_need_reset, | ||
3714 | .reset_chip = qla4_83xx_isp_reset, | ||
3715 | .reset_firmware = qla4_8xxx_stop_firmware, | ||
3716 | .queue_iocb = qla4_83xx_queue_iocb, | ||
3717 | .complete_iocb = qla4_83xx_complete_iocb, | ||
3718 | .rd_shdw_req_q_out = qla4_83xx_rd_shdw_req_q_out, | ||
3719 | .rd_shdw_rsp_q_in = qla4_83xx_rd_shdw_rsp_q_in, | ||
3720 | .get_sys_info = qla4_8xxx_get_sys_info, | ||
3721 | .rd_reg_direct = qla4_83xx_rd_reg, | ||
3722 | .wr_reg_direct = qla4_83xx_wr_reg, | ||
3723 | .rd_reg_indirect = qla4_83xx_rd_reg_indirect, | ||
3724 | .wr_reg_indirect = qla4_83xx_wr_reg_indirect, | ||
3725 | .idc_lock = qla4_83xx_drv_lock, | ||
3726 | .idc_unlock = qla4_83xx_drv_unlock, | ||
3727 | .rom_lock_recovery = qla4_83xx_rom_lock_recovery, | ||
3728 | .queue_mailbox_command = qla4_83xx_queue_mbox_cmd, | ||
3729 | .process_mailbox_interrupt = qla4_83xx_process_mbox_intr, | ||
3730 | }; | ||
3731 | |||
3696 | uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) | 3732 | uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) |
3697 | { | 3733 | { |
3698 | return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out); | 3734 | return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out); |
@@ -3703,6 +3739,11 @@ uint16_t qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host *ha) | |||
3703 | return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out)); | 3739 | return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out)); |
3704 | } | 3740 | } |
3705 | 3741 | ||
3742 | uint16_t qla4_83xx_rd_shdw_req_q_out(struct scsi_qla_host *ha) | ||
3743 | { | ||
3744 | return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->req_q_out)); | ||
3745 | } | ||
3746 | |||
3706 | uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) | 3747 | uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) |
3707 | { | 3748 | { |
3708 | return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in); | 3749 | return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in); |
@@ -3713,6 +3754,11 @@ uint16_t qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) | |||
3713 | return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in)); | 3754 | return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in)); |
3714 | } | 3755 | } |
3715 | 3756 | ||
3757 | uint16_t qla4_83xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) | ||
3758 | { | ||
3759 | return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->rsp_q_in)); | ||
3760 | } | ||
3761 | |||
3716 | static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) | 3762 | static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) |
3717 | { | 3763 | { |
3718 | struct scsi_qla_host *ha = data; | 3764 | struct scsi_qla_host *ha = data; |
@@ -5085,6 +5131,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
5085 | ha->pdev = pdev; | 5131 | ha->pdev = pdev; |
5086 | ha->host = host; | 5132 | ha->host = host; |
5087 | ha->host_no = host->host_no; | 5133 | ha->host_no = host->host_no; |
5134 | ha->func_num = PCI_FUNC(ha->pdev->devfn); | ||
5088 | 5135 | ||
5089 | pci_enable_pcie_error_reporting(pdev); | 5136 | pci_enable_pcie_error_reporting(pdev); |
5090 | 5137 | ||
@@ -5092,24 +5139,28 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
5092 | if (is_qla8022(ha)) { | 5139 | if (is_qla8022(ha)) { |
5093 | ha->isp_ops = &qla4_82xx_isp_ops; | 5140 | ha->isp_ops = &qla4_82xx_isp_ops; |
5094 | ha->reg_tbl = (uint32_t *) qla4_82xx_reg_tbl; | 5141 | ha->reg_tbl = (uint32_t *) qla4_82xx_reg_tbl; |
5095 | rwlock_init(&ha->hw_lock); | ||
5096 | ha->qdr_sn_window = -1; | 5142 | ha->qdr_sn_window = -1; |
5097 | ha->ddr_mn_window = -1; | 5143 | ha->ddr_mn_window = -1; |
5098 | ha->curr_window = 255; | 5144 | ha->curr_window = 255; |
5099 | ha->func_num = PCI_FUNC(ha->pdev->devfn); | ||
5100 | nx_legacy_intr = &legacy_intr[ha->func_num]; | 5145 | nx_legacy_intr = &legacy_intr[ha->func_num]; |
5101 | ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit; | 5146 | ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit; |
5102 | ha->nx_legacy_intr.tgt_status_reg = | 5147 | ha->nx_legacy_intr.tgt_status_reg = |
5103 | nx_legacy_intr->tgt_status_reg; | 5148 | nx_legacy_intr->tgt_status_reg; |
5104 | ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg; | 5149 | ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg; |
5105 | ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; | 5150 | ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; |
5151 | } else if (is_qla8032(ha)) { | ||
5152 | ha->isp_ops = &qla4_83xx_isp_ops; | ||
5153 | ha->reg_tbl = (uint32_t *)qla4_83xx_reg_tbl; | ||
5106 | } else { | 5154 | } else { |
5107 | ha->isp_ops = &qla4xxx_isp_ops; | 5155 | ha->isp_ops = &qla4xxx_isp_ops; |
5108 | } | 5156 | } |
5109 | 5157 | ||
5110 | /* Set EEH reset type to fundamental if required by hba */ | 5158 | if (is_qla80XX(ha)) { |
5111 | if (is_qla8022(ha)) | 5159 | rwlock_init(&ha->hw_lock); |
5160 | ha->pf_bit = ha->func_num << 16; | ||
5161 | /* Set EEH reset type to fundamental if required by hba */ | ||
5112 | pdev->needs_freset = 1; | 5162 | pdev->needs_freset = 1; |
5163 | } | ||
5113 | 5164 | ||
5114 | /* Configure PCI I/O space. */ | 5165 | /* Configure PCI I/O space. */ |
5115 | ret = ha->isp_ops->iospace_config(ha); | 5166 | ret = ha->isp_ops->iospace_config(ha); |
@@ -5165,8 +5216,20 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
5165 | if (ret) | 5216 | if (ret) |
5166 | goto probe_failed; | 5217 | goto probe_failed; |
5167 | 5218 | ||
5168 | if (is_qla8022(ha)) | 5219 | if (is_qla80XX(ha)) |
5169 | (void) qla4_8xxx_get_flash_info(ha); | 5220 | qla4_8xxx_get_flash_info(ha); |
5221 | |||
5222 | if (is_qla8032(ha)) { | ||
5223 | qla4_83xx_read_reset_template(ha); | ||
5224 | /* | ||
5225 | * NOTE: If ql4dontresethba==1, set IDC_CTRL DONTRESET_BIT0. | ||
5226 | * If DONRESET_BIT0 is set, drivers should not set dev_state | ||
5227 | * to NEED_RESET. But if NEED_RESET is set, drivers should | ||
5228 | * should honor the reset. | ||
5229 | */ | ||
5230 | if (ql4xdontresethba == 1) | ||
5231 | qla4_83xx_set_idc_dontreset(ha); | ||
5232 | } | ||
5170 | 5233 | ||
5171 | /* | 5234 | /* |
5172 | * Initialize the Host adapter request/response queues and | 5235 | * Initialize the Host adapter request/response queues and |
@@ -5177,7 +5240,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
5177 | while ((!test_bit(AF_ONLINE, &ha->flags)) && | 5240 | while ((!test_bit(AF_ONLINE, &ha->flags)) && |
5178 | init_retry_count++ < MAX_INIT_RETRIES) { | 5241 | init_retry_count++ < MAX_INIT_RETRIES) { |
5179 | 5242 | ||
5180 | if (is_qla8022(ha)) { | 5243 | if (is_qla80XX(ha)) { |
5181 | ha->isp_ops->idc_lock(ha); | 5244 | ha->isp_ops->idc_lock(ha); |
5182 | dev_state = qla4_8xxx_rd_direct(ha, | 5245 | dev_state = qla4_8xxx_rd_direct(ha, |
5183 | QLA82XX_CRB_DEV_STATE); | 5246 | QLA82XX_CRB_DEV_STATE); |
@@ -5201,7 +5264,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
5201 | if (!test_bit(AF_ONLINE, &ha->flags)) { | 5264 | if (!test_bit(AF_ONLINE, &ha->flags)) { |
5202 | ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); | 5265 | ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); |
5203 | 5266 | ||
5204 | if (is_qla8022(ha) && ql4xdontresethba) { | 5267 | if ((is_qla8022(ha) && ql4xdontresethba) || |
5268 | (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) { | ||
5205 | /* Put the device in failed state. */ | 5269 | /* Put the device in failed state. */ |
5206 | DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n")); | 5270 | DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n")); |
5207 | ha->isp_ops->idc_lock(ha); | 5271 | ha->isp_ops->idc_lock(ha); |
@@ -5233,7 +5297,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
5233 | goto remove_host; | 5297 | goto remove_host; |
5234 | } | 5298 | } |
5235 | 5299 | ||
5236 | /* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc | 5300 | /* |
5301 | * For ISP-8XXX, request_irqs is called in qla4_8xxx_load_risc | ||
5237 | * (which is called indirectly by qla4xxx_initialize_adapter), | 5302 | * (which is called indirectly by qla4xxx_initialize_adapter), |
5238 | * so that irqs will be registered after crbinit but before | 5303 | * so that irqs will be registered after crbinit but before |
5239 | * mbx_intr_enable. | 5304 | * mbx_intr_enable. |
@@ -5793,7 +5858,16 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) | |||
5793 | 5858 | ||
5794 | ha = to_qla_host(cmd->device->host); | 5859 | ha = to_qla_host(cmd->device->host); |
5795 | 5860 | ||
5796 | if (ql4xdontresethba) { | 5861 | if (is_qla8032(ha) && ql4xdontresethba) |
5862 | qla4_83xx_set_idc_dontreset(ha); | ||
5863 | |||
5864 | /* | ||
5865 | * For ISP8324, if IDC_CTRL DONTRESET_BIT0 is set by other | ||
5866 | * protocol drivers, we should not set device_state to | ||
5867 | * NEED_RESET | ||
5868 | */ | ||
5869 | if (ql4xdontresethba || | ||
5870 | (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) { | ||
5797 | DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", | 5871 | DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", |
5798 | ha->host_no, __func__)); | 5872 | ha->host_no, __func__)); |
5799 | 5873 | ||
@@ -5817,7 +5891,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) | |||
5817 | } | 5891 | } |
5818 | 5892 | ||
5819 | if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { | 5893 | if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { |
5820 | if (is_qla8022(ha)) | 5894 | if (is_qla80XX(ha)) |
5821 | set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); | 5895 | set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); |
5822 | else | 5896 | else |
5823 | set_bit(DPC_RESET_HA, &ha->dpc_flags); | 5897 | set_bit(DPC_RESET_HA, &ha->dpc_flags); |
@@ -5912,7 +5986,7 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type) | |||
5912 | break; | 5986 | break; |
5913 | case SCSI_FIRMWARE_RESET: | 5987 | case SCSI_FIRMWARE_RESET: |
5914 | if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { | 5988 | if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { |
5915 | if (is_qla8022(ha)) | 5989 | if (is_qla80XX(ha)) |
5916 | /* set firmware context reset */ | 5990 | /* set firmware context reset */ |
5917 | set_bit(DPC_RESET_HA_FW_CONTEXT, | 5991 | set_bit(DPC_RESET_HA_FW_CONTEXT, |
5918 | &ha->dpc_flags); | 5992 | &ha->dpc_flags); |
@@ -6150,7 +6224,7 @@ qla4xxx_pci_slot_reset(struct pci_dev *pdev) | |||
6150 | 6224 | ||
6151 | ha->isp_ops->disable_intrs(ha); | 6225 | ha->isp_ops->disable_intrs(ha); |
6152 | 6226 | ||
6153 | if (is_qla8022(ha)) { | 6227 | if (is_qla80XX(ha)) { |
6154 | if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) { | 6228 | if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) { |
6155 | ret = PCI_ERS_RESULT_RECOVERED; | 6229 | ret = PCI_ERS_RESULT_RECOVERED; |
6156 | goto exit_slot_reset; | 6230 | goto exit_slot_reset; |
@@ -6216,6 +6290,12 @@ static struct pci_device_id qla4xxx_pci_tbl[] = { | |||
6216 | .subvendor = PCI_ANY_ID, | 6290 | .subvendor = PCI_ANY_ID, |
6217 | .subdevice = PCI_ANY_ID, | 6291 | .subdevice = PCI_ANY_ID, |
6218 | }, | 6292 | }, |
6293 | { | ||
6294 | .vendor = PCI_VENDOR_ID_QLOGIC, | ||
6295 | .device = PCI_DEVICE_ID_QLOGIC_ISP8324, | ||
6296 | .subvendor = PCI_ANY_ID, | ||
6297 | .subdevice = PCI_ANY_ID, | ||
6298 | }, | ||
6219 | {0, 0}, | 6299 | {0, 0}, |
6220 | }; | 6300 | }; |
6221 | MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); | 6301 | MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); |