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