]>
Commit | Line | Data |
---|---|---|
afaf5a2d DS |
1 | /* |
2 | * QLogic iSCSI HBA Driver | |
3 | * Copyright (c) 2003-2006 QLogic Corporation | |
4 | * | |
5 | * See LICENSE.qla4xxx for copyright and licensing details. | |
6 | */ | |
7 | ||
8 | #include "ql4_def.h" | |
c0e344c9 DS |
9 | #include "ql4_glbl.h" |
10 | #include "ql4_dbg.h" | |
11 | #include "ql4_inline.h" | |
afaf5a2d DS |
12 | |
13 | ||
14 | /** | |
15 | * qla4xxx_mailbox_command - issues mailbox commands | |
16 | * @ha: Pointer to host adapter structure. | |
17 | * @inCount: number of mailbox registers to load. | |
18 | * @outCount: number of mailbox registers to return. | |
19 | * @mbx_cmd: data pointer for mailbox in registers. | |
20 | * @mbx_sts: data pointer for mailbox out registers. | |
21 | * | |
f4f5df23 | 22 | * This routine isssue mailbox commands and waits for completion. |
afaf5a2d DS |
23 | * If outCount is 0, this routine completes successfully WITHOUT waiting |
24 | * for the mailbox command to complete. | |
25 | **/ | |
f4f5df23 VC |
26 | int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, |
27 | uint8_t outCount, uint32_t *mbx_cmd, | |
28 | uint32_t *mbx_sts) | |
afaf5a2d DS |
29 | { |
30 | int status = QLA_ERROR; | |
31 | uint8_t i; | |
32 | u_long wait_count; | |
33 | uint32_t intr_status; | |
34 | unsigned long flags = 0; | |
afaf5a2d DS |
35 | |
36 | /* Make sure that pointers are valid */ | |
37 | if (!mbx_cmd || !mbx_sts) { | |
38 | DEBUG2(printk("scsi%ld: %s: Invalid mbx_cmd or mbx_sts " | |
39 | "pointer\n", ha->host_no, __func__)); | |
477ffb9d DS |
40 | return status; |
41 | } | |
21033639 NJ |
42 | |
43 | if (is_qla8022(ha) && | |
44 | test_bit(AF_FW_RECOVERY, &ha->flags)) { | |
45 | DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: prematurely " | |
46 | "completing mbx cmd as firmware recovery detected\n", | |
47 | ha->host_no, __func__)); | |
48 | return status; | |
49 | } | |
50 | ||
2232be0d LC |
51 | if ((is_aer_supported(ha)) && |
52 | (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))) { | |
53 | DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Perm failure on EEH, " | |
54 | "timeout MBX Exiting.\n", ha->host_no, __func__)); | |
55 | return status; | |
56 | } | |
57 | ||
477ffb9d DS |
58 | /* Mailbox code active */ |
59 | wait_count = MBOX_TOV * 100; | |
60 | ||
61 | while (wait_count--) { | |
62 | mutex_lock(&ha->mbox_sem); | |
63 | if (!test_bit(AF_MBOX_COMMAND, &ha->flags)) { | |
64 | set_bit(AF_MBOX_COMMAND, &ha->flags); | |
65 | mutex_unlock(&ha->mbox_sem); | |
66 | break; | |
67 | } | |
68 | mutex_unlock(&ha->mbox_sem); | |
69 | if (!wait_count) { | |
70 | DEBUG2(printk("scsi%ld: %s: mbox_sem failed\n", | |
71 | ha->host_no, __func__)); | |
72 | return status; | |
73 | } | |
74 | msleep(10); | |
afaf5a2d DS |
75 | } |
76 | ||
77 | /* To prevent overwriting mailbox registers for a command that has | |
f4f5df23 VC |
78 | * not yet been serviced, check to see if an active command |
79 | * (AEN, IOCB, etc.) is interrupting, then service it. | |
afaf5a2d DS |
80 | * ----------------------------------------------------------------- |
81 | */ | |
82 | spin_lock_irqsave(&ha->hardware_lock, flags); | |
f4f5df23 VC |
83 | |
84 | if (is_qla8022(ha)) { | |
85 | intr_status = readl(&ha->qla4_8xxx_reg->host_int); | |
86 | if (intr_status & ISRX_82XX_RISC_INT) { | |
87 | /* Service existing interrupt */ | |
88 | DEBUG2(printk("scsi%ld: %s: " | |
89 | "servicing existing interrupt\n", | |
90 | ha->host_no, __func__)); | |
91 | intr_status = readl(&ha->qla4_8xxx_reg->host_status); | |
92 | ha->isp_ops->interrupt_service_routine(ha, intr_status); | |
93 | clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); | |
94 | if (test_bit(AF_INTERRUPTS_ON, &ha->flags) && | |
95 | test_bit(AF_INTx_ENABLED, &ha->flags)) | |
96 | qla4_8xxx_wr_32(ha, | |
97 | ha->nx_legacy_intr.tgt_mask_reg, | |
98 | 0xfbff); | |
99 | } | |
100 | } else { | |
101 | intr_status = readl(&ha->reg->ctrl_status); | |
102 | if (intr_status & CSR_SCSI_PROCESSOR_INTR) { | |
103 | /* Service existing interrupt */ | |
104 | ha->isp_ops->interrupt_service_routine(ha, intr_status); | |
105 | clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); | |
106 | } | |
afaf5a2d DS |
107 | } |
108 | ||
afaf5a2d DS |
109 | ha->mbox_status_count = outCount; |
110 | for (i = 0; i < outCount; i++) | |
111 | ha->mbox_status[i] = 0; | |
112 | ||
f4f5df23 VC |
113 | if (is_qla8022(ha)) { |
114 | /* Load all mailbox registers, except mailbox 0. */ | |
115 | DEBUG5( | |
116 | printk("scsi%ld: %s: Cmd ", ha->host_no, __func__); | |
117 | for (i = 0; i < inCount; i++) | |
118 | printk("mb%d=%04x ", i, mbx_cmd[i]); | |
119 | printk("\n")); | |
120 | ||
121 | for (i = 1; i < inCount; i++) | |
122 | writel(mbx_cmd[i], &ha->qla4_8xxx_reg->mailbox_in[i]); | |
123 | writel(mbx_cmd[0], &ha->qla4_8xxx_reg->mailbox_in[0]); | |
124 | readl(&ha->qla4_8xxx_reg->mailbox_in[0]); | |
125 | writel(HINT_MBX_INT_PENDING, &ha->qla4_8xxx_reg->hint); | |
126 | } else { | |
127 | /* Load all mailbox registers, except mailbox 0. */ | |
128 | for (i = 1; i < inCount; i++) | |
129 | writel(mbx_cmd[i], &ha->reg->mailbox[i]); | |
130 | ||
131 | /* Wakeup firmware */ | |
132 | writel(mbx_cmd[0], &ha->reg->mailbox[0]); | |
133 | readl(&ha->reg->mailbox[0]); | |
134 | writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status); | |
135 | readl(&ha->reg->ctrl_status); | |
136 | } | |
afaf5a2d | 137 | |
afaf5a2d DS |
138 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
139 | ||
140 | /* Wait for completion */ | |
afaf5a2d DS |
141 | |
142 | /* | |
143 | * If we don't want status, don't wait for the mailbox command to | |
144 | * complete. For example, MBOX_CMD_RESET_FW doesn't return status, | |
145 | * you must poll the inbound Interrupt Mask for completion. | |
146 | */ | |
147 | if (outCount == 0) { | |
148 | status = QLA_SUCCESS; | |
afaf5a2d DS |
149 | goto mbox_exit; |
150 | } | |
afaf5a2d | 151 | |
f4f5df23 VC |
152 | /* |
153 | * Wait for completion: Poll or completion queue | |
154 | */ | |
155 | if (test_bit(AF_IRQ_ATTACHED, &ha->flags) && | |
156 | test_bit(AF_INTERRUPTS_ON, &ha->flags) && | |
157 | test_bit(AF_ONLINE, &ha->flags) && | |
158 | !test_bit(AF_HBA_GOING_AWAY, &ha->flags)) { | |
159 | /* Do not poll for completion. Use completion queue */ | |
160 | set_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags); | |
161 | wait_for_completion_timeout(&ha->mbx_intr_comp, MBOX_TOV * HZ); | |
162 | clear_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags); | |
163 | } else { | |
164 | /* Poll for command to complete */ | |
165 | wait_count = jiffies + MBOX_TOV * HZ; | |
166 | while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) { | |
167 | if (time_after_eq(jiffies, wait_count)) | |
168 | break; | |
2232be0d | 169 | |
afaf5a2d DS |
170 | /* |
171 | * Service the interrupt. | |
172 | * The ISR will save the mailbox status registers | |
173 | * to a temporary storage location in the adapter | |
174 | * structure. | |
175 | */ | |
f4f5df23 VC |
176 | |
177 | spin_lock_irqsave(&ha->hardware_lock, flags); | |
178 | if (is_qla8022(ha)) { | |
179 | intr_status = | |
180 | readl(&ha->qla4_8xxx_reg->host_int); | |
181 | if (intr_status & ISRX_82XX_RISC_INT) { | |
182 | ha->mbox_status_count = outCount; | |
183 | intr_status = | |
184 | readl(&ha->qla4_8xxx_reg->host_status); | |
185 | ha->isp_ops->interrupt_service_routine( | |
186 | ha, intr_status); | |
187 | if (test_bit(AF_INTERRUPTS_ON, | |
188 | &ha->flags) && | |
189 | test_bit(AF_INTx_ENABLED, | |
190 | &ha->flags)) | |
191 | qla4_8xxx_wr_32(ha, | |
192 | ha->nx_legacy_intr.tgt_mask_reg, | |
193 | 0xfbff); | |
194 | } | |
195 | } else { | |
196 | intr_status = readl(&ha->reg->ctrl_status); | |
197 | if (intr_status & INTR_PENDING) { | |
198 | /* | |
199 | * Service the interrupt. | |
200 | * The ISR will save the mailbox status | |
201 | * registers to a temporary storage | |
202 | * location in the adapter structure. | |
203 | */ | |
204 | ha->mbox_status_count = outCount; | |
205 | ha->isp_ops->interrupt_service_routine( | |
206 | ha, intr_status); | |
207 | } | |
208 | } | |
209 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | |
210 | msleep(10); | |
afaf5a2d | 211 | } |
afaf5a2d | 212 | } |
afaf5a2d DS |
213 | |
214 | /* Check for mailbox timeout. */ | |
215 | if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) { | |
21033639 NJ |
216 | if (is_qla8022(ha) && |
217 | test_bit(AF_FW_RECOVERY, &ha->flags)) { | |
218 | DEBUG2(ql4_printk(KERN_INFO, ha, | |
219 | "scsi%ld: %s: prematurely completing mbx cmd as " | |
220 | "firmware recovery detected\n", | |
221 | ha->host_no, __func__)); | |
222 | goto mbox_exit; | |
223 | } | |
afaf5a2d DS |
224 | DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...," |
225 | " Scheduling Adapter Reset\n", ha->host_no, | |
226 | mbx_cmd[0])); | |
227 | ha->mailbox_timeout_count++; | |
228 | mbx_sts[0] = (-1); | |
229 | set_bit(DPC_RESET_HA, &ha->dpc_flags); | |
230 | goto mbox_exit; | |
231 | } | |
232 | ||
233 | /* | |
234 | * Copy the mailbox out registers to the caller's mailbox in/out | |
235 | * structure. | |
236 | */ | |
237 | spin_lock_irqsave(&ha->hardware_lock, flags); | |
238 | for (i = 0; i < outCount; i++) | |
239 | mbx_sts[i] = ha->mbox_status[i]; | |
240 | ||
241 | /* Set return status and error flags (if applicable). */ | |
242 | switch (ha->mbox_status[0]) { | |
243 | case MBOX_STS_COMMAND_COMPLETE: | |
244 | status = QLA_SUCCESS; | |
245 | break; | |
246 | ||
247 | case MBOX_STS_INTERMEDIATE_COMPLETION: | |
248 | status = QLA_SUCCESS; | |
249 | break; | |
250 | ||
251 | case MBOX_STS_BUSY: | |
252 | DEBUG2( printk("scsi%ld: %s: Cmd = %08X, ISP BUSY\n", | |
253 | ha->host_no, __func__, mbx_cmd[0])); | |
254 | ha->mailbox_timeout_count++; | |
255 | break; | |
256 | ||
257 | default: | |
258 | DEBUG2(printk("scsi%ld: %s: **** FAILED, cmd = %08X, " | |
259 | "sts = %08X ****\n", ha->host_no, __func__, | |
260 | mbx_cmd[0], mbx_sts[0])); | |
261 | break; | |
262 | } | |
263 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | |
264 | ||
265 | mbox_exit: | |
477ffb9d | 266 | mutex_lock(&ha->mbox_sem); |
afaf5a2d | 267 | clear_bit(AF_MBOX_COMMAND, &ha->flags); |
afaf5a2d | 268 | mutex_unlock(&ha->mbox_sem); |
477ffb9d | 269 | clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); |
afaf5a2d DS |
270 | |
271 | return status; | |
272 | } | |
21033639 NJ |
273 | |
274 | void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha) | |
275 | { | |
276 | set_bit(AF_FW_RECOVERY, &ha->flags); | |
277 | ql4_printk(KERN_INFO, ha, "scsi%ld: %s: set FW RECOVERY!\n", | |
278 | ha->host_no, __func__); | |
279 | ||
280 | if (test_bit(AF_MBOX_COMMAND, &ha->flags)) { | |
281 | if (test_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags)) { | |
282 | complete(&ha->mbx_intr_comp); | |
283 | ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Due to fw " | |
284 | "recovery, doing premature completion of " | |
285 | "mbx cmd\n", ha->host_no, __func__); | |
286 | ||
287 | } else { | |
288 | set_bit(AF_MBOX_COMMAND_DONE, &ha->flags); | |
289 | ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Due to fw " | |
290 | "recovery, doing premature completion of " | |
291 | "polling mbx cmd\n", ha->host_no, __func__); | |
292 | } | |
293 | } | |
294 | } | |
afaf5a2d | 295 | |
f4f5df23 | 296 | static uint8_t |
2a49a78e VC |
297 | qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, |
298 | uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) | |
299 | { | |
300 | memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT); | |
301 | memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); | |
302 | mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE; | |
303 | mbox_cmd[1] = 0; | |
304 | mbox_cmd[2] = LSDW(init_fw_cb_dma); | |
305 | mbox_cmd[3] = MSDW(init_fw_cb_dma); | |
306 | mbox_cmd[4] = sizeof(struct addr_ctrl_blk); | |
307 | mbox_cmd[5] = (IFCB_VER_MAX << 8) | IFCB_VER_MIN; | |
308 | ||
309 | if (qla4xxx_mailbox_command(ha, 6, 6, mbox_cmd, mbox_sts) != | |
310 | QLA_SUCCESS) { | |
311 | DEBUG2(printk(KERN_WARNING "scsi%ld: %s: " | |
312 | "MBOX_CMD_INITIALIZE_FIRMWARE" | |
313 | " failed w/ status %04X\n", | |
314 | ha->host_no, __func__, mbox_sts[0])); | |
315 | return QLA_ERROR; | |
316 | } | |
317 | return QLA_SUCCESS; | |
318 | } | |
319 | ||
f4f5df23 | 320 | static uint8_t |
2a49a78e VC |
321 | qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, |
322 | uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) | |
323 | { | |
324 | memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT); | |
325 | memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); | |
326 | mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; | |
327 | mbox_cmd[2] = LSDW(init_fw_cb_dma); | |
328 | mbox_cmd[3] = MSDW(init_fw_cb_dma); | |
329 | mbox_cmd[4] = sizeof(struct addr_ctrl_blk); | |
330 | ||
331 | if (qla4xxx_mailbox_command(ha, 5, 5, mbox_cmd, mbox_sts) != | |
332 | QLA_SUCCESS) { | |
333 | DEBUG2(printk(KERN_WARNING "scsi%ld: %s: " | |
334 | "MBOX_CMD_GET_INIT_FW_CTRL_BLOCK" | |
335 | " failed w/ status %04X\n", | |
336 | ha->host_no, __func__, mbox_sts[0])); | |
337 | return QLA_ERROR; | |
338 | } | |
339 | return QLA_SUCCESS; | |
340 | } | |
341 | ||
f4f5df23 | 342 | static void |
2a49a78e VC |
343 | qla4xxx_update_local_ip(struct scsi_qla_host *ha, |
344 | struct addr_ctrl_blk *init_fw_cb) | |
345 | { | |
346 | /* Save IPv4 Address Info */ | |
347 | memcpy(ha->ip_address, init_fw_cb->ipv4_addr, | |
348 | min(sizeof(ha->ip_address), sizeof(init_fw_cb->ipv4_addr))); | |
349 | memcpy(ha->subnet_mask, init_fw_cb->ipv4_subnet, | |
350 | min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->ipv4_subnet))); | |
351 | memcpy(ha->gateway, init_fw_cb->ipv4_gw_addr, | |
352 | min(sizeof(ha->gateway), sizeof(init_fw_cb->ipv4_gw_addr))); | |
353 | ||
354 | if (is_ipv6_enabled(ha)) { | |
355 | /* Save IPv6 Address */ | |
356 | ha->ipv6_link_local_state = init_fw_cb->ipv6_lnk_lcl_addr_state; | |
357 | ha->ipv6_addr0_state = init_fw_cb->ipv6_addr0_state; | |
358 | ha->ipv6_addr1_state = init_fw_cb->ipv6_addr1_state; | |
359 | ha->ipv6_default_router_state = init_fw_cb->ipv6_dflt_rtr_state; | |
360 | ha->ipv6_link_local_addr.in6_u.u6_addr8[0] = 0xFE; | |
361 | ha->ipv6_link_local_addr.in6_u.u6_addr8[1] = 0x80; | |
362 | ||
363 | memcpy(&ha->ipv6_link_local_addr.in6_u.u6_addr8[8], | |
364 | init_fw_cb->ipv6_if_id, | |
365 | min(sizeof(ha->ipv6_link_local_addr)/2, | |
366 | sizeof(init_fw_cb->ipv6_if_id))); | |
367 | memcpy(&ha->ipv6_addr0, init_fw_cb->ipv6_addr0, | |
368 | min(sizeof(ha->ipv6_addr0), | |
369 | sizeof(init_fw_cb->ipv6_addr0))); | |
370 | memcpy(&ha->ipv6_addr1, init_fw_cb->ipv6_addr1, | |
371 | min(sizeof(ha->ipv6_addr1), | |
372 | sizeof(init_fw_cb->ipv6_addr1))); | |
373 | memcpy(&ha->ipv6_default_router_addr, | |
374 | init_fw_cb->ipv6_dflt_rtr_addr, | |
375 | min(sizeof(ha->ipv6_default_router_addr), | |
376 | sizeof(init_fw_cb->ipv6_dflt_rtr_addr))); | |
377 | } | |
378 | } | |
379 | ||
f4f5df23 | 380 | static uint8_t |
2a49a78e VC |
381 | qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, |
382 | uint32_t *mbox_cmd, | |
383 | uint32_t *mbox_sts, | |
384 | struct addr_ctrl_blk *init_fw_cb, | |
385 | dma_addr_t init_fw_cb_dma) | |
386 | { | |
387 | if (qla4xxx_get_ifcb(ha, mbox_cmd, mbox_sts, init_fw_cb_dma) | |
388 | != QLA_SUCCESS) { | |
389 | DEBUG2(printk(KERN_WARNING | |
390 | "scsi%ld: %s: Failed to get init_fw_ctrl_blk\n", | |
391 | ha->host_no, __func__)); | |
392 | return QLA_ERROR; | |
393 | } | |
394 | ||
395 | DEBUG2(qla4xxx_dump_buffer(init_fw_cb, sizeof(struct addr_ctrl_blk))); | |
396 | ||
397 | /* Save some info in adapter structure. */ | |
398 | ha->acb_version = init_fw_cb->acb_version; | |
399 | ha->firmware_options = le16_to_cpu(init_fw_cb->fw_options); | |
400 | ha->tcp_options = le16_to_cpu(init_fw_cb->ipv4_tcp_opts); | |
401 | ha->ipv4_options = le16_to_cpu(init_fw_cb->ipv4_ip_opts); | |
402 | ha->ipv4_addr_state = le16_to_cpu(init_fw_cb->ipv4_addr_state); | |
403 | ha->heartbeat_interval = init_fw_cb->hb_interval; | |
404 | memcpy(ha->name_string, init_fw_cb->iscsi_name, | |
405 | min(sizeof(ha->name_string), | |
406 | sizeof(init_fw_cb->iscsi_name))); | |
407 | /*memcpy(ha->alias, init_fw_cb->Alias, | |
408 | min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ | |
409 | ||
410 | /* Save Command Line Paramater info */ | |
2a49a78e VC |
411 | ha->discovery_wait = ql4xdiscoverywait; |
412 | ||
413 | if (ha->acb_version == ACB_SUPPORTED) { | |
414 | ha->ipv6_options = init_fw_cb->ipv6_opts; | |
415 | ha->ipv6_addl_options = init_fw_cb->ipv6_addtl_opts; | |
416 | } | |
417 | qla4xxx_update_local_ip(ha, init_fw_cb); | |
418 | ||
419 | return QLA_SUCCESS; | |
420 | } | |
421 | ||
afaf5a2d DS |
422 | /** |
423 | * qla4xxx_initialize_fw_cb - initializes firmware control block. | |
424 | * @ha: Pointer to host adapter structure. | |
425 | **/ | |
426 | int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) | |
427 | { | |
2a49a78e | 428 | struct addr_ctrl_blk *init_fw_cb; |
afaf5a2d DS |
429 | dma_addr_t init_fw_cb_dma; |
430 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
431 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
432 | int status = QLA_ERROR; | |
433 | ||
434 | init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, | |
2a49a78e | 435 | sizeof(struct addr_ctrl_blk), |
afaf5a2d DS |
436 | &init_fw_cb_dma, GFP_KERNEL); |
437 | if (init_fw_cb == NULL) { | |
438 | DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n", | |
439 | ha->host_no, __func__)); | |
beabe7c1 | 440 | goto exit_init_fw_cb_no_free; |
afaf5a2d | 441 | } |
2a49a78e | 442 | memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); |
afaf5a2d DS |
443 | |
444 | /* Get Initialize Firmware Control Block. */ | |
445 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
446 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | |
c0e344c9 | 447 | |
2a49a78e | 448 | if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) != |
afaf5a2d DS |
449 | QLA_SUCCESS) { |
450 | dma_free_coherent(&ha->pdev->dev, | |
2a49a78e | 451 | sizeof(struct addr_ctrl_blk), |
afaf5a2d | 452 | init_fw_cb, init_fw_cb_dma); |
2a49a78e | 453 | goto exit_init_fw_cb; |
afaf5a2d DS |
454 | } |
455 | ||
456 | /* Initialize request and response queues. */ | |
457 | qla4xxx_init_rings(ha); | |
458 | ||
459 | /* Fill in the request and response queue information. */ | |
2a49a78e VC |
460 | init_fw_cb->rqq_consumer_idx = cpu_to_le16(ha->request_out); |
461 | init_fw_cb->compq_producer_idx = cpu_to_le16(ha->response_in); | |
462 | init_fw_cb->rqq_len = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH); | |
463 | init_fw_cb->compq_len = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH); | |
464 | init_fw_cb->rqq_addr_lo = cpu_to_le32(LSDW(ha->request_dma)); | |
465 | init_fw_cb->rqq_addr_hi = cpu_to_le32(MSDW(ha->request_dma)); | |
466 | init_fw_cb->compq_addr_lo = cpu_to_le32(LSDW(ha->response_dma)); | |
467 | init_fw_cb->compq_addr_hi = cpu_to_le32(MSDW(ha->response_dma)); | |
468 | init_fw_cb->shdwreg_addr_lo = cpu_to_le32(LSDW(ha->shadow_regs_dma)); | |
469 | init_fw_cb->shdwreg_addr_hi = cpu_to_le32(MSDW(ha->shadow_regs_dma)); | |
afaf5a2d DS |
470 | |
471 | /* Set up required options. */ | |
2a49a78e | 472 | init_fw_cb->fw_options |= |
afaf5a2d DS |
473 | __constant_cpu_to_le16(FWOPT_SESSION_MODE | |
474 | FWOPT_INITIATOR_MODE); | |
2a49a78e | 475 | init_fw_cb->fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); |
afaf5a2d | 476 | |
2a49a78e VC |
477 | if (qla4xxx_set_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) |
478 | != QLA_SUCCESS) { | |
479 | DEBUG2(printk(KERN_WARNING | |
480 | "scsi%ld: %s: Failed to set init_fw_ctrl_blk\n", | |
481 | ha->host_no, __func__)); | |
482 | goto exit_init_fw_cb; | |
483 | } | |
c0e344c9 | 484 | |
2a49a78e VC |
485 | if (qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], |
486 | init_fw_cb, init_fw_cb_dma) != QLA_SUCCESS) { | |
487 | DEBUG2(printk("scsi%ld: %s: Failed to update local ifcb\n", | |
488 | ha->host_no, __func__)); | |
489 | goto exit_init_fw_cb; | |
afaf5a2d | 490 | } |
2a49a78e VC |
491 | status = QLA_SUCCESS; |
492 | ||
493 | exit_init_fw_cb: | |
494 | dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), | |
495 | init_fw_cb, init_fw_cb_dma); | |
beabe7c1 | 496 | exit_init_fw_cb_no_free: |
afaf5a2d DS |
497 | return status; |
498 | } | |
499 | ||
500 | /** | |
501 | * qla4xxx_get_dhcp_ip_address - gets HBA ip address via DHCP | |
502 | * @ha: Pointer to host adapter structure. | |
503 | **/ | |
504 | int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha) | |
505 | { | |
2a49a78e | 506 | struct addr_ctrl_blk *init_fw_cb; |
afaf5a2d DS |
507 | dma_addr_t init_fw_cb_dma; |
508 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
509 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
510 | ||
511 | init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, | |
2a49a78e | 512 | sizeof(struct addr_ctrl_blk), |
afaf5a2d DS |
513 | &init_fw_cb_dma, GFP_KERNEL); |
514 | if (init_fw_cb == NULL) { | |
515 | printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no, | |
516 | __func__); | |
beabe7c1 | 517 | return QLA_ERROR; |
afaf5a2d DS |
518 | } |
519 | ||
520 | /* Get Initialize Firmware Control Block. */ | |
2a49a78e VC |
521 | memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); |
522 | if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) != | |
afaf5a2d DS |
523 | QLA_SUCCESS) { |
524 | DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n", | |
525 | ha->host_no, __func__)); | |
526 | dma_free_coherent(&ha->pdev->dev, | |
2a49a78e | 527 | sizeof(struct addr_ctrl_blk), |
afaf5a2d DS |
528 | init_fw_cb, init_fw_cb_dma); |
529 | return QLA_ERROR; | |
530 | } | |
531 | ||
532 | /* Save IP Address. */ | |
2a49a78e VC |
533 | qla4xxx_update_local_ip(ha, init_fw_cb); |
534 | dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), | |
535 | init_fw_cb, init_fw_cb_dma); | |
afaf5a2d DS |
536 | |
537 | return QLA_SUCCESS; | |
538 | } | |
539 | ||
540 | /** | |
541 | * qla4xxx_get_firmware_state - gets firmware state of HBA | |
542 | * @ha: Pointer to host adapter structure. | |
543 | **/ | |
544 | int qla4xxx_get_firmware_state(struct scsi_qla_host * ha) | |
545 | { | |
546 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
547 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
548 | ||
549 | /* Get firmware version */ | |
550 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
551 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | |
c0e344c9 | 552 | |
afaf5a2d | 553 | mbox_cmd[0] = MBOX_CMD_GET_FW_STATE; |
c0e344c9 DS |
554 | |
555 | if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 4, &mbox_cmd[0], &mbox_sts[0]) != | |
afaf5a2d DS |
556 | QLA_SUCCESS) { |
557 | DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ " | |
558 | "status %04X\n", ha->host_no, __func__, | |
559 | mbox_sts[0])); | |
560 | return QLA_ERROR; | |
561 | } | |
562 | ha->firmware_state = mbox_sts[1]; | |
563 | ha->board_id = mbox_sts[2]; | |
564 | ha->addl_fw_state = mbox_sts[3]; | |
565 | DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n", | |
566 | ha->host_no, __func__, ha->firmware_state);) | |
567 | ||
f4f5df23 | 568 | return QLA_SUCCESS; |
afaf5a2d DS |
569 | } |
570 | ||
571 | /** | |
572 | * qla4xxx_get_firmware_status - retrieves firmware status | |
573 | * @ha: Pointer to host adapter structure. | |
574 | **/ | |
575 | int qla4xxx_get_firmware_status(struct scsi_qla_host * ha) | |
576 | { | |
577 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
578 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
579 | ||
580 | /* Get firmware version */ | |
581 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
582 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | |
c0e344c9 | 583 | |
afaf5a2d | 584 | mbox_cmd[0] = MBOX_CMD_GET_FW_STATUS; |
c0e344c9 DS |
585 | |
586 | if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0], &mbox_sts[0]) != | |
afaf5a2d DS |
587 | QLA_SUCCESS) { |
588 | DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ " | |
589 | "status %04X\n", ha->host_no, __func__, | |
590 | mbox_sts[0])); | |
591 | return QLA_ERROR; | |
592 | } | |
f4f5df23 VC |
593 | |
594 | ql4_printk(KERN_INFO, ha, "%ld firmare IOCBs available (%d).\n", | |
595 | ha->host_no, mbox_cmd[2]); | |
596 | ||
afaf5a2d DS |
597 | return QLA_SUCCESS; |
598 | } | |
599 | ||
600 | /** | |
601 | * qla4xxx_get_fwddb_entry - retrieves firmware ddb entry | |
602 | * @ha: Pointer to host adapter structure. | |
603 | * @fw_ddb_index: Firmware's device database index | |
604 | * @fw_ddb_entry: Pointer to firmware's device database entry structure | |
605 | * @num_valid_ddb_entries: Pointer to number of valid ddb entries | |
606 | * @next_ddb_index: Pointer to next valid device database index | |
607 | * @fw_ddb_device_state: Pointer to device state | |
608 | **/ | |
609 | int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, | |
610 | uint16_t fw_ddb_index, | |
611 | struct dev_db_entry *fw_ddb_entry, | |
612 | dma_addr_t fw_ddb_entry_dma, | |
613 | uint32_t *num_valid_ddb_entries, | |
614 | uint32_t *next_ddb_index, | |
615 | uint32_t *fw_ddb_device_state, | |
616 | uint32_t *conn_err_detail, | |
617 | uint16_t *tcp_source_port_num, | |
618 | uint16_t *connection_id) | |
619 | { | |
620 | int status = QLA_ERROR; | |
2a49a78e | 621 | uint16_t options; |
afaf5a2d DS |
622 | uint32_t mbox_cmd[MBOX_REG_COUNT]; |
623 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
624 | ||
625 | /* Make sure the device index is valid */ | |
626 | if (fw_ddb_index >= MAX_DDB_ENTRIES) { | |
f4f5df23 | 627 | DEBUG2(printk("scsi%ld: %s: ddb [%d] out of range.\n", |
afaf5a2d DS |
628 | ha->host_no, __func__, fw_ddb_index)); |
629 | goto exit_get_fwddb; | |
630 | } | |
631 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
632 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | |
c0e344c9 | 633 | |
afaf5a2d DS |
634 | mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY; |
635 | mbox_cmd[1] = (uint32_t) fw_ddb_index; | |
636 | mbox_cmd[2] = LSDW(fw_ddb_entry_dma); | |
637 | mbox_cmd[3] = MSDW(fw_ddb_entry_dma); | |
c0e344c9 DS |
638 | mbox_cmd[4] = sizeof(struct dev_db_entry); |
639 | ||
640 | if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 7, &mbox_cmd[0], &mbox_sts[0]) == | |
afaf5a2d DS |
641 | QLA_ERROR) { |
642 | DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed" | |
643 | " with status 0x%04X\n", ha->host_no, __func__, | |
644 | mbox_sts[0])); | |
645 | goto exit_get_fwddb; | |
646 | } | |
647 | if (fw_ddb_index != mbox_sts[1]) { | |
f4f5df23 | 648 | DEBUG2(printk("scsi%ld: %s: ddb mismatch [%d] != [%d].\n", |
afaf5a2d DS |
649 | ha->host_no, __func__, fw_ddb_index, |
650 | mbox_sts[1])); | |
651 | goto exit_get_fwddb; | |
652 | } | |
653 | if (fw_ddb_entry) { | |
2a49a78e VC |
654 | options = le16_to_cpu(fw_ddb_entry->options); |
655 | if (options & DDB_OPT_IPV6_DEVICE) { | |
c2660df3 | 656 | ql4_printk(KERN_INFO, ha, "%s: DDB[%d] MB0 %04x Tot %d " |
2a49a78e VC |
657 | "Next %d State %04x ConnErr %08x %pI6 " |
658 | ":%04d \"%s\"\n", __func__, fw_ddb_index, | |
659 | mbox_sts[0], mbox_sts[2], mbox_sts[3], | |
660 | mbox_sts[4], mbox_sts[5], | |
661 | fw_ddb_entry->ip_addr, | |
662 | le16_to_cpu(fw_ddb_entry->port), | |
663 | fw_ddb_entry->iscsi_name); | |
664 | } else { | |
c2660df3 | 665 | ql4_printk(KERN_INFO, ha, "%s: DDB[%d] MB0 %04x Tot %d " |
2a49a78e VC |
666 | "Next %d State %04x ConnErr %08x %pI4 " |
667 | ":%04d \"%s\"\n", __func__, fw_ddb_index, | |
668 | mbox_sts[0], mbox_sts[2], mbox_sts[3], | |
669 | mbox_sts[4], mbox_sts[5], | |
670 | fw_ddb_entry->ip_addr, | |
671 | le16_to_cpu(fw_ddb_entry->port), | |
672 | fw_ddb_entry->iscsi_name); | |
673 | } | |
afaf5a2d DS |
674 | } |
675 | if (num_valid_ddb_entries) | |
676 | *num_valid_ddb_entries = mbox_sts[2]; | |
677 | if (next_ddb_index) | |
678 | *next_ddb_index = mbox_sts[3]; | |
679 | if (fw_ddb_device_state) | |
680 | *fw_ddb_device_state = mbox_sts[4]; | |
681 | ||
682 | /* | |
683 | * RA: This mailbox has been changed to pass connection error and | |
684 | * details. Its true for ISP4010 as per Version E - Not sure when it | |
685 | * was changed. Get the time2wait from the fw_dd_entry field : | |
686 | * default_time2wait which we call it as minTime2Wait DEV_DB_ENTRY | |
687 | * struct. | |
688 | */ | |
689 | if (conn_err_detail) | |
690 | *conn_err_detail = mbox_sts[5]; | |
691 | if (tcp_source_port_num) | |
1482338f | 692 | *tcp_source_port_num = (uint16_t) (mbox_sts[6] >> 16); |
afaf5a2d DS |
693 | if (connection_id) |
694 | *connection_id = (uint16_t) mbox_sts[6] & 0x00FF; | |
695 | status = QLA_SUCCESS; | |
696 | ||
697 | exit_get_fwddb: | |
698 | return status; | |
699 | } | |
700 | ||
701 | /** | |
702 | * qla4xxx_set_fwddb_entry - sets a ddb entry. | |
703 | * @ha: Pointer to host adapter structure. | |
704 | * @fw_ddb_index: Firmware's device database index | |
705 | * @fw_ddb_entry: Pointer to firmware's ddb entry structure, or NULL. | |
706 | * | |
707 | * This routine initializes or updates the adapter's device database | |
708 | * entry for the specified device. It also triggers a login for the | |
709 | * specified device. Therefore, it may also be used as a secondary | |
710 | * login routine when a NULL pointer is specified for the fw_ddb_entry. | |
711 | **/ | |
712 | int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, | |
713 | dma_addr_t fw_ddb_entry_dma) | |
714 | { | |
715 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
716 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
f4f5df23 | 717 | int status; |
afaf5a2d DS |
718 | |
719 | /* Do not wait for completion. The firmware will send us an | |
720 | * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status. | |
721 | */ | |
722 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
723 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | |
724 | ||
725 | mbox_cmd[0] = MBOX_CMD_SET_DATABASE_ENTRY; | |
726 | mbox_cmd[1] = (uint32_t) fw_ddb_index; | |
727 | mbox_cmd[2] = LSDW(fw_ddb_entry_dma); | |
728 | mbox_cmd[3] = MSDW(fw_ddb_entry_dma); | |
c0e344c9 | 729 | mbox_cmd[4] = sizeof(struct dev_db_entry); |
afaf5a2d | 730 | |
f4f5df23 VC |
731 | status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], |
732 | &mbox_sts[0]); | |
733 | DEBUG2(printk("scsi%ld: %s: status=%d mbx0=0x%x mbx4=0x%x\n", | |
734 | ha->host_no, __func__, status, mbox_sts[0], mbox_sts[4]);) | |
735 | ||
736 | return status; | |
afaf5a2d DS |
737 | } |
738 | ||
739 | /** | |
740 | * qla4xxx_get_crash_record - retrieves crash record. | |
741 | * @ha: Pointer to host adapter structure. | |
742 | * | |
743 | * This routine retrieves a crash record from the QLA4010 after an 8002h aen. | |
744 | **/ | |
745 | void qla4xxx_get_crash_record(struct scsi_qla_host * ha) | |
746 | { | |
747 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
748 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
749 | struct crash_record *crash_record = NULL; | |
750 | dma_addr_t crash_record_dma = 0; | |
751 | uint32_t crash_record_size = 0; | |
c0e344c9 | 752 | |
afaf5a2d DS |
753 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); |
754 | memset(&mbox_sts, 0, sizeof(mbox_cmd)); | |
755 | ||
756 | /* Get size of crash record. */ | |
757 | mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD; | |
c0e344c9 DS |
758 | |
759 | if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != | |
afaf5a2d DS |
760 | QLA_SUCCESS) { |
761 | DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve size!\n", | |
762 | ha->host_no, __func__)); | |
763 | goto exit_get_crash_record; | |
764 | } | |
765 | crash_record_size = mbox_sts[4]; | |
766 | if (crash_record_size == 0) { | |
767 | DEBUG2(printk("scsi%ld: %s: ERROR: Crash record size is 0!\n", | |
768 | ha->host_no, __func__)); | |
769 | goto exit_get_crash_record; | |
770 | } | |
771 | ||
772 | /* Alloc Memory for Crash Record. */ | |
773 | crash_record = dma_alloc_coherent(&ha->pdev->dev, crash_record_size, | |
774 | &crash_record_dma, GFP_KERNEL); | |
775 | if (crash_record == NULL) | |
776 | goto exit_get_crash_record; | |
777 | ||
778 | /* Get Crash Record. */ | |
c0e344c9 DS |
779 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); |
780 | memset(&mbox_sts, 0, sizeof(mbox_cmd)); | |
781 | ||
afaf5a2d DS |
782 | mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD; |
783 | mbox_cmd[2] = LSDW(crash_record_dma); | |
784 | mbox_cmd[3] = MSDW(crash_record_dma); | |
785 | mbox_cmd[4] = crash_record_size; | |
c0e344c9 DS |
786 | |
787 | if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != | |
afaf5a2d DS |
788 | QLA_SUCCESS) |
789 | goto exit_get_crash_record; | |
790 | ||
791 | /* Dump Crash Record. */ | |
792 | ||
793 | exit_get_crash_record: | |
794 | if (crash_record) | |
795 | dma_free_coherent(&ha->pdev->dev, crash_record_size, | |
796 | crash_record, crash_record_dma); | |
797 | } | |
798 | ||
799 | /** | |
800 | * qla4xxx_get_conn_event_log - retrieves connection event log | |
801 | * @ha: Pointer to host adapter structure. | |
802 | **/ | |
803 | void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha) | |
804 | { | |
805 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
806 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
807 | struct conn_event_log_entry *event_log = NULL; | |
808 | dma_addr_t event_log_dma = 0; | |
809 | uint32_t event_log_size = 0; | |
810 | uint32_t num_valid_entries; | |
811 | uint32_t oldest_entry = 0; | |
812 | uint32_t max_event_log_entries; | |
813 | uint8_t i; | |
814 | ||
815 | ||
816 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
817 | memset(&mbox_sts, 0, sizeof(mbox_cmd)); | |
818 | ||
819 | /* Get size of crash record. */ | |
820 | mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG; | |
c0e344c9 DS |
821 | |
822 | if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != | |
afaf5a2d DS |
823 | QLA_SUCCESS) |
824 | goto exit_get_event_log; | |
825 | ||
826 | event_log_size = mbox_sts[4]; | |
827 | if (event_log_size == 0) | |
828 | goto exit_get_event_log; | |
829 | ||
830 | /* Alloc Memory for Crash Record. */ | |
831 | event_log = dma_alloc_coherent(&ha->pdev->dev, event_log_size, | |
832 | &event_log_dma, GFP_KERNEL); | |
833 | if (event_log == NULL) | |
834 | goto exit_get_event_log; | |
835 | ||
836 | /* Get Crash Record. */ | |
c0e344c9 DS |
837 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); |
838 | memset(&mbox_sts, 0, sizeof(mbox_cmd)); | |
839 | ||
afaf5a2d DS |
840 | mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG; |
841 | mbox_cmd[2] = LSDW(event_log_dma); | |
842 | mbox_cmd[3] = MSDW(event_log_dma); | |
c0e344c9 DS |
843 | |
844 | if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != | |
afaf5a2d DS |
845 | QLA_SUCCESS) { |
846 | DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve event " | |
847 | "log!\n", ha->host_no, __func__)); | |
848 | goto exit_get_event_log; | |
849 | } | |
850 | ||
851 | /* Dump Event Log. */ | |
852 | num_valid_entries = mbox_sts[1]; | |
853 | ||
854 | max_event_log_entries = event_log_size / | |
855 | sizeof(struct conn_event_log_entry); | |
856 | ||
857 | if (num_valid_entries > max_event_log_entries) | |
858 | oldest_entry = num_valid_entries % max_event_log_entries; | |
859 | ||
860 | DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n", | |
861 | ha->host_no, num_valid_entries)); | |
862 | ||
11010fec | 863 | if (ql4xextended_error_logging == 3) { |
afaf5a2d DS |
864 | if (oldest_entry == 0) { |
865 | /* Circular Buffer has not wrapped around */ | |
866 | for (i=0; i < num_valid_entries; i++) { | |
867 | qla4xxx_dump_buffer((uint8_t *)event_log+ | |
868 | (i*sizeof(*event_log)), | |
869 | sizeof(*event_log)); | |
870 | } | |
871 | } | |
872 | else { | |
873 | /* Circular Buffer has wrapped around - | |
874 | * display accordingly*/ | |
875 | for (i=oldest_entry; i < max_event_log_entries; i++) { | |
876 | qla4xxx_dump_buffer((uint8_t *)event_log+ | |
877 | (i*sizeof(*event_log)), | |
878 | sizeof(*event_log)); | |
879 | } | |
880 | for (i=0; i < oldest_entry; i++) { | |
881 | qla4xxx_dump_buffer((uint8_t *)event_log+ | |
882 | (i*sizeof(*event_log)), | |
883 | sizeof(*event_log)); | |
884 | } | |
885 | } | |
886 | } | |
887 | ||
888 | exit_get_event_log: | |
889 | if (event_log) | |
890 | dma_free_coherent(&ha->pdev->dev, event_log_size, event_log, | |
891 | event_log_dma); | |
892 | } | |
893 | ||
09a0f719 VC |
894 | /** |
895 | * qla4xxx_abort_task - issues Abort Task | |
896 | * @ha: Pointer to host adapter structure. | |
897 | * @srb: Pointer to srb entry | |
898 | * | |
899 | * This routine performs a LUN RESET on the specified target/lun. | |
900 | * The caller must ensure that the ddb_entry and lun_entry pointers | |
901 | * are valid before calling this routine. | |
902 | **/ | |
903 | int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb) | |
904 | { | |
905 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
906 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
907 | struct scsi_cmnd *cmd = srb->cmd; | |
908 | int status = QLA_SUCCESS; | |
909 | unsigned long flags = 0; | |
910 | uint32_t index; | |
911 | ||
912 | /* | |
913 | * Send abort task command to ISP, so that the ISP will return | |
914 | * request with ABORT status | |
915 | */ | |
916 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
917 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | |
918 | ||
919 | spin_lock_irqsave(&ha->hardware_lock, flags); | |
920 | index = (unsigned long)(unsigned char *)cmd->host_scribble; | |
921 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | |
922 | ||
923 | /* Firmware already posted completion on response queue */ | |
924 | if (index == MAX_SRBS) | |
925 | return status; | |
926 | ||
927 | mbox_cmd[0] = MBOX_CMD_ABORT_TASK; | |
928 | mbox_cmd[1] = srb->fw_ddb_index; | |
929 | mbox_cmd[2] = index; | |
930 | /* Immediate Command Enable */ | |
931 | mbox_cmd[5] = 0x01; | |
932 | ||
933 | qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], | |
934 | &mbox_sts[0]); | |
935 | if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE) { | |
936 | status = QLA_ERROR; | |
937 | ||
938 | DEBUG2(printk(KERN_WARNING "scsi%ld:%d:%d: abort task FAILED: " | |
939 | "mbx0=%04X, mb1=%04X, mb2=%04X, mb3=%04X, mb4=%04X\n", | |
940 | ha->host_no, cmd->device->id, cmd->device->lun, mbox_sts[0], | |
941 | mbox_sts[1], mbox_sts[2], mbox_sts[3], mbox_sts[4])); | |
942 | } | |
943 | ||
944 | return status; | |
945 | } | |
946 | ||
afaf5a2d DS |
947 | /** |
948 | * qla4xxx_reset_lun - issues LUN Reset | |
949 | * @ha: Pointer to host adapter structure. | |
f4f5df23 VC |
950 | * @ddb_entry: Pointer to device database entry |
951 | * @lun: lun number | |
afaf5a2d DS |
952 | * |
953 | * This routine performs a LUN RESET on the specified target/lun. | |
954 | * The caller must ensure that the ddb_entry and lun_entry pointers | |
955 | * are valid before calling this routine. | |
956 | **/ | |
957 | int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, | |
958 | int lun) | |
959 | { | |
960 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
961 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
962 | int status = QLA_SUCCESS; | |
963 | ||
964 | DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no, | |
f4f5df23 | 965 | ddb_entry->fw_ddb_index, lun)); |
afaf5a2d DS |
966 | |
967 | /* | |
968 | * Send lun reset command to ISP, so that the ISP will return all | |
969 | * outstanding requests with RESET status | |
970 | */ | |
971 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
972 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | |
c0e344c9 | 973 | |
afaf5a2d DS |
974 | mbox_cmd[0] = MBOX_CMD_LUN_RESET; |
975 | mbox_cmd[1] = ddb_entry->fw_ddb_index; | |
976 | mbox_cmd[2] = lun << 8; | |
977 | mbox_cmd[5] = 0x01; /* Immediate Command Enable */ | |
c0e344c9 DS |
978 | |
979 | qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]); | |
afaf5a2d DS |
980 | if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE && |
981 | mbox_sts[0] != MBOX_STS_COMMAND_ERROR) | |
982 | status = QLA_ERROR; | |
983 | ||
984 | return status; | |
985 | } | |
986 | ||
ce545039 MC |
987 | /** |
988 | * qla4xxx_reset_target - issues target Reset | |
989 | * @ha: Pointer to host adapter structure. | |
990 | * @db_entry: Pointer to device database entry | |
991 | * @un_entry: Pointer to lun entry structure | |
992 | * | |
993 | * This routine performs a TARGET RESET on the specified target. | |
994 | * The caller must ensure that the ddb_entry pointers | |
995 | * are valid before calling this routine. | |
996 | **/ | |
997 | int qla4xxx_reset_target(struct scsi_qla_host *ha, | |
998 | struct ddb_entry *ddb_entry) | |
999 | { | |
1000 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
1001 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
1002 | int status = QLA_SUCCESS; | |
1003 | ||
1004 | DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no, | |
f4f5df23 | 1005 | ddb_entry->fw_ddb_index)); |
ce545039 MC |
1006 | |
1007 | /* | |
1008 | * Send target reset command to ISP, so that the ISP will return all | |
1009 | * outstanding requests with RESET status | |
1010 | */ | |
1011 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
1012 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | |
1013 | ||
1014 | mbox_cmd[0] = MBOX_CMD_TARGET_WARM_RESET; | |
1015 | mbox_cmd[1] = ddb_entry->fw_ddb_index; | |
1016 | mbox_cmd[5] = 0x01; /* Immediate Command Enable */ | |
1017 | ||
1018 | qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], | |
1019 | &mbox_sts[0]); | |
1020 | if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE && | |
1021 | mbox_sts[0] != MBOX_STS_COMMAND_ERROR) | |
1022 | status = QLA_ERROR; | |
1023 | ||
1024 | return status; | |
1025 | } | |
afaf5a2d DS |
1026 | |
1027 | int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, | |
1028 | uint32_t offset, uint32_t len) | |
1029 | { | |
1030 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
1031 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
1032 | ||
1033 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
1034 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | |
c0e344c9 | 1035 | |
afaf5a2d DS |
1036 | mbox_cmd[0] = MBOX_CMD_READ_FLASH; |
1037 | mbox_cmd[1] = LSDW(dma_addr); | |
1038 | mbox_cmd[2] = MSDW(dma_addr); | |
1039 | mbox_cmd[3] = offset; | |
1040 | mbox_cmd[4] = len; | |
c0e344c9 DS |
1041 | |
1042 | if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], &mbox_sts[0]) != | |
afaf5a2d DS |
1043 | QLA_SUCCESS) { |
1044 | DEBUG2(printk("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ " | |
1045 | "status %04X %04X, offset %08x, len %08x\n", ha->host_no, | |
1046 | __func__, mbox_sts[0], mbox_sts[1], offset, len)); | |
1047 | return QLA_ERROR; | |
1048 | } | |
1049 | return QLA_SUCCESS; | |
1050 | } | |
1051 | ||
1052 | /** | |
1053 | * qla4xxx_get_fw_version - gets firmware version | |
1054 | * @ha: Pointer to host adapter structure. | |
1055 | * | |
1056 | * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may | |
1057 | * hold an address for data. Make sure that we write 0 to those mailboxes, | |
1058 | * if unused. | |
1059 | **/ | |
1060 | int qla4xxx_get_fw_version(struct scsi_qla_host * ha) | |
1061 | { | |
1062 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
1063 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
1064 | ||
1065 | /* Get firmware version. */ | |
1066 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
1067 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | |
c0e344c9 | 1068 | |
afaf5a2d | 1069 | mbox_cmd[0] = MBOX_CMD_ABOUT_FW; |
c0e344c9 DS |
1070 | |
1071 | if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != | |
afaf5a2d DS |
1072 | QLA_SUCCESS) { |
1073 | DEBUG2(printk("scsi%ld: %s: MBOX_CMD_ABOUT_FW failed w/ " | |
1074 | "status %04X\n", ha->host_no, __func__, mbox_sts[0])); | |
1075 | return QLA_ERROR; | |
1076 | } | |
1077 | ||
1078 | /* Save firmware version information. */ | |
1079 | ha->firmware_version[0] = mbox_sts[1]; | |
1080 | ha->firmware_version[1] = mbox_sts[2]; | |
1081 | ha->patch_number = mbox_sts[3]; | |
1082 | ha->build_number = mbox_sts[4]; | |
1083 | ||
1084 | return QLA_SUCCESS; | |
1085 | } | |
1086 | ||
47975477 AB |
1087 | static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, |
1088 | dma_addr_t dma_addr) | |
afaf5a2d DS |
1089 | { |
1090 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
1091 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
1092 | ||
1093 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
1094 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | |
1095 | ||
1096 | mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS; | |
1097 | mbox_cmd[2] = LSDW(dma_addr); | |
1098 | mbox_cmd[3] = MSDW(dma_addr); | |
1099 | ||
c0e344c9 | 1100 | if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) != |
afaf5a2d DS |
1101 | QLA_SUCCESS) { |
1102 | DEBUG2(printk("scsi%ld: %s: failed status %04X\n", | |
1103 | ha->host_no, __func__, mbox_sts[0])); | |
1104 | return QLA_ERROR; | |
1105 | } | |
1106 | return QLA_SUCCESS; | |
1107 | } | |
1108 | ||
47975477 | 1109 | static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index) |
afaf5a2d DS |
1110 | { |
1111 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | |
1112 | uint32_t mbox_sts[MBOX_REG_COUNT]; | |
1113 | ||
1114 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | |
1115 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | |
1116 | ||
1117 | mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY; | |
1118 | mbox_cmd[1] = MAX_PRST_DEV_DB_ENTRIES; | |
1119 | ||
c0e344c9 | 1120 | if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0], &mbox_sts[0]) != |
afaf5a2d DS |
1121 | QLA_SUCCESS) { |
1122 | if (mbox_sts[0] == MBOX_STS_COMMAND_ERROR) { | |
1123 | *ddb_index = mbox_sts[2]; | |
1124 | } else { | |
1125 | DEBUG2(printk("scsi%ld: %s: failed status %04X\n", | |
1126 | ha->host_no, __func__, mbox_sts[0])); | |
1127 | return QLA_ERROR; | |
1128 | } | |
1129 | } else { | |
1130 | *ddb_index = MAX_PRST_DEV_DB_ENTRIES; | |
1131 | } | |
1132 | ||
1133 | return QLA_SUCCESS; | |
1134 | } | |
1135 | ||
1136 | ||
1137 | int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port) | |
1138 | { | |
1139 | struct dev_db_entry *fw_ddb_entry; | |
1140 | dma_addr_t fw_ddb_entry_dma; | |
1141 | uint32_t ddb_index; | |
1142 | int ret_val = QLA_SUCCESS; | |
1143 | ||
1144 | ||
1145 | fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, | |
1146 | sizeof(*fw_ddb_entry), | |
1147 | &fw_ddb_entry_dma, GFP_KERNEL); | |
1148 | if (!fw_ddb_entry) { | |
1149 | DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", | |
1150 | ha->host_no, __func__)); | |
1151 | ret_val = QLA_ERROR; | |
beabe7c1 | 1152 | goto exit_send_tgts_no_free; |
afaf5a2d DS |
1153 | } |
1154 | ||
1155 | ret_val = qla4xxx_get_default_ddb(ha, fw_ddb_entry_dma); | |
1156 | if (ret_val != QLA_SUCCESS) | |
beabe7c1 | 1157 | goto exit_send_tgts; |
afaf5a2d DS |
1158 | |
1159 | ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index); | |
1160 | if (ret_val != QLA_SUCCESS) | |
beabe7c1 | 1161 | goto exit_send_tgts; |
afaf5a2d | 1162 | |
c0e344c9 DS |
1163 | memset(fw_ddb_entry->iscsi_alias, 0, |
1164 | sizeof(fw_ddb_entry->iscsi_alias)); | |
afaf5a2d | 1165 | |
c0e344c9 DS |
1166 | memset(fw_ddb_entry->iscsi_name, 0, |
1167 | sizeof(fw_ddb_entry->iscsi_name)); | |
afaf5a2d | 1168 | |
c0e344c9 DS |
1169 | memset(fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr)); |
1170 | memset(fw_ddb_entry->tgt_addr, 0, | |
1171 | sizeof(fw_ddb_entry->tgt_addr)); | |
afaf5a2d DS |
1172 | |
1173 | fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET); | |
c0e344c9 | 1174 | fw_ddb_entry->port = cpu_to_le16(ntohs(port)); |
afaf5a2d | 1175 | |
c0e344c9 DS |
1176 | fw_ddb_entry->ip_addr[0] = *ip; |
1177 | fw_ddb_entry->ip_addr[1] = *(ip + 1); | |
1178 | fw_ddb_entry->ip_addr[2] = *(ip + 2); | |
1179 | fw_ddb_entry->ip_addr[3] = *(ip + 3); | |
afaf5a2d DS |
1180 | |
1181 | ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma); | |
1182 | ||
beabe7c1 | 1183 | exit_send_tgts: |
afaf5a2d DS |
1184 | dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), |
1185 | fw_ddb_entry, fw_ddb_entry_dma); | |
beabe7c1 | 1186 | exit_send_tgts_no_free: |
afaf5a2d DS |
1187 | return ret_val; |
1188 | } | |
1189 |