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