1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * QLogic iSCSI HBA Driver |
4 | * Copyright (c) 2003-2013 QLogic Corporation |
5 | */ |
6 | |
7 | #include <scsi/iscsi_if.h> |
8 | #include "ql4_def.h" |
9 | #include "ql4_glbl.h" |
10 | #include "ql4_dbg.h" |
11 | #include "ql4_inline.h" |
12 | |
13 | static void ql4xxx_set_mac_number(struct scsi_qla_host *ha) |
14 | { |
15 | uint32_t value; |
16 | unsigned long flags; |
17 | |
18 | /* Get the function number */ |
19 | spin_lock_irqsave(&ha->hardware_lock, flags); |
20 | value = readw(addr: &ha->reg->ctrl_status); |
21 | spin_unlock_irqrestore(lock: &ha->hardware_lock, flags); |
22 | |
23 | switch (value & ISP_CONTROL_FN_MASK) { |
24 | case ISP_CONTROL_FN0_SCSI: |
25 | ha->mac_index = 1; |
26 | break; |
27 | case ISP_CONTROL_FN1_SCSI: |
28 | ha->mac_index = 3; |
29 | break; |
30 | default: |
31 | DEBUG2(printk("scsi%ld: %s: Invalid function number, " |
32 | "ispControlStatus = 0x%x\n" , ha->host_no, |
33 | __func__, value)); |
34 | break; |
35 | } |
36 | DEBUG2(printk("scsi%ld: %s: mac_index %d.\n" , ha->host_no, __func__, |
37 | ha->mac_index)); |
38 | } |
39 | |
40 | /** |
41 | * qla4xxx_free_ddb - deallocate ddb |
42 | * @ha: pointer to host adapter structure. |
43 | * @ddb_entry: pointer to device database entry |
44 | * |
45 | * This routine marks a DDB entry INVALID |
46 | **/ |
47 | void qla4xxx_free_ddb(struct scsi_qla_host *ha, |
48 | struct ddb_entry *ddb_entry) |
49 | { |
50 | /* Remove device pointer from index mapping arrays */ |
51 | ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = |
52 | (struct ddb_entry *) INVALID_ENTRY; |
53 | ha->tot_ddbs--; |
54 | } |
55 | |
56 | /** |
57 | * qla4xxx_init_response_q_entries() - Initializes response queue entries. |
58 | * @ha: HA context |
59 | * |
60 | * Beginning of request ring has initialization control block already built |
61 | * by nvram config routine. |
62 | **/ |
63 | static void qla4xxx_init_response_q_entries(struct scsi_qla_host *ha) |
64 | { |
65 | uint16_t cnt; |
66 | struct response *pkt; |
67 | |
68 | pkt = (struct response *)ha->response_ptr; |
69 | for (cnt = 0; cnt < RESPONSE_QUEUE_DEPTH; cnt++) { |
70 | pkt->signature = RESPONSE_PROCESSED; |
71 | pkt++; |
72 | } |
73 | } |
74 | |
75 | /** |
76 | * qla4xxx_init_rings - initialize hw queues |
77 | * @ha: pointer to host adapter structure. |
78 | * |
79 | * This routine initializes the internal queues for the specified adapter. |
80 | * The QLA4010 requires us to restart the queues at index 0. |
81 | * The QLA4000 doesn't care, so just default to QLA4010's requirement. |
82 | **/ |
83 | int qla4xxx_init_rings(struct scsi_qla_host *ha) |
84 | { |
85 | unsigned long flags = 0; |
86 | int i; |
87 | |
88 | /* Initialize request queue. */ |
89 | spin_lock_irqsave(&ha->hardware_lock, flags); |
90 | ha->request_out = 0; |
91 | ha->request_in = 0; |
92 | ha->request_ptr = &ha->request_ring[ha->request_in]; |
93 | ha->req_q_count = REQUEST_QUEUE_DEPTH; |
94 | |
95 | /* Initialize response queue. */ |
96 | ha->response_in = 0; |
97 | ha->response_out = 0; |
98 | ha->response_ptr = &ha->response_ring[ha->response_out]; |
99 | |
100 | if (is_qla8022(ha)) { |
101 | writel(val: 0, |
102 | addr: (unsigned long __iomem *)&ha->qla4_82xx_reg->req_q_out); |
103 | writel(val: 0, |
104 | addr: (unsigned long __iomem *)&ha->qla4_82xx_reg->rsp_q_in); |
105 | writel(val: 0, |
106 | addr: (unsigned long __iomem *)&ha->qla4_82xx_reg->rsp_q_out); |
107 | } else if (is_qla8032(ha) || is_qla8042(ha)) { |
108 | writel(val: 0, |
109 | addr: (unsigned long __iomem *)&ha->qla4_83xx_reg->req_q_in); |
110 | writel(val: 0, |
111 | addr: (unsigned long __iomem *)&ha->qla4_83xx_reg->rsp_q_in); |
112 | writel(val: 0, |
113 | addr: (unsigned long __iomem *)&ha->qla4_83xx_reg->rsp_q_out); |
114 | } else { |
115 | /* |
116 | * Initialize DMA Shadow registers. The firmware is really |
117 | * supposed to take care of this, but on some uniprocessor |
118 | * systems, the shadow registers aren't cleared-- causing |
119 | * the interrupt_handler to think there are responses to be |
120 | * processed when there aren't. |
121 | */ |
122 | ha->shadow_regs->req_q_out = cpu_to_le32(0); |
123 | ha->shadow_regs->rsp_q_in = cpu_to_le32(0); |
124 | wmb(); |
125 | |
126 | writel(val: 0, addr: &ha->reg->req_q_in); |
127 | writel(val: 0, addr: &ha->reg->rsp_q_out); |
128 | readl(addr: &ha->reg->rsp_q_out); |
129 | } |
130 | |
131 | qla4xxx_init_response_q_entries(ha); |
132 | |
133 | /* Initialize mailbox active array */ |
134 | for (i = 0; i < MAX_MRB; i++) |
135 | ha->active_mrb_array[i] = NULL; |
136 | |
137 | spin_unlock_irqrestore(lock: &ha->hardware_lock, flags); |
138 | |
139 | return QLA_SUCCESS; |
140 | } |
141 | |
142 | /** |
143 | * qla4xxx_get_sys_info - validate adapter MAC address(es) |
144 | * @ha: pointer to host adapter structure. |
145 | * |
146 | **/ |
147 | int qla4xxx_get_sys_info(struct scsi_qla_host *ha) |
148 | { |
149 | struct flash_sys_info *sys_info; |
150 | dma_addr_t sys_info_dma; |
151 | int status = QLA_ERROR; |
152 | |
153 | sys_info = dma_alloc_coherent(dev: &ha->pdev->dev, size: sizeof(*sys_info), |
154 | dma_handle: &sys_info_dma, GFP_KERNEL); |
155 | if (sys_info == NULL) { |
156 | DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n" , |
157 | ha->host_no, __func__)); |
158 | |
159 | goto exit_get_sys_info_no_free; |
160 | } |
161 | |
162 | /* Get flash sys info */ |
163 | if (qla4xxx_get_flash(ha, dma_addr: sys_info_dma, FLASH_OFFSET_SYS_INFO, |
164 | len: sizeof(*sys_info)) != QLA_SUCCESS) { |
165 | DEBUG2(printk("scsi%ld: %s: get_flash FLASH_OFFSET_SYS_INFO " |
166 | "failed\n" , ha->host_no, __func__)); |
167 | |
168 | goto exit_get_sys_info; |
169 | } |
170 | |
171 | /* Save M.A.C. address & serial_number */ |
172 | memcpy(ha->my_mac, &sys_info->physAddr[0].address[0], |
173 | min(sizeof(ha->my_mac), |
174 | sizeof(sys_info->physAddr[0].address))); |
175 | memcpy(ha->serial_number, &sys_info->acSerialNumber, |
176 | min(sizeof(ha->serial_number), |
177 | sizeof(sys_info->acSerialNumber))); |
178 | |
179 | status = QLA_SUCCESS; |
180 | |
181 | exit_get_sys_info: |
182 | dma_free_coherent(dev: &ha->pdev->dev, size: sizeof(*sys_info), cpu_addr: sys_info, |
183 | dma_handle: sys_info_dma); |
184 | |
185 | exit_get_sys_info_no_free: |
186 | return status; |
187 | } |
188 | |
189 | /** |
190 | * qla4xxx_init_local_data - initialize adapter specific local data |
191 | * @ha: pointer to host adapter structure. |
192 | * |
193 | **/ |
194 | static void qla4xxx_init_local_data(struct scsi_qla_host *ha) |
195 | { |
196 | /* Initialize aen queue */ |
197 | ha->aen_q_count = MAX_AEN_ENTRIES; |
198 | } |
199 | |
200 | static uint8_t |
201 | qla4xxx_wait_for_ip_config(struct scsi_qla_host *ha) |
202 | { |
203 | uint8_t ipv4_wait = 0; |
204 | uint8_t ipv6_wait = 0; |
205 | int8_t ip_address[IPv6_ADDR_LEN] = {0} ; |
206 | |
207 | /* If both IPv4 & IPv6 are enabled, possibly only one |
208 | * IP address may be acquired, so check to see if we |
209 | * need to wait for another */ |
210 | if (is_ipv4_enabled(ha) && is_ipv6_enabled(ha)) { |
211 | if (((ha->addl_fw_state & FW_ADDSTATE_DHCPv4_ENABLED) != 0) && |
212 | ((ha->addl_fw_state & |
213 | FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED) == 0)) { |
214 | ipv4_wait = 1; |
215 | } |
216 | if (((ha->ip_config.ipv6_addl_options & |
217 | IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) != 0) && |
218 | ((ha->ip_config.ipv6_link_local_state == |
219 | IP_ADDRSTATE_ACQUIRING) || |
220 | (ha->ip_config.ipv6_addr0_state == |
221 | IP_ADDRSTATE_ACQUIRING) || |
222 | (ha->ip_config.ipv6_addr1_state == |
223 | IP_ADDRSTATE_ACQUIRING))) { |
224 | |
225 | ipv6_wait = 1; |
226 | |
227 | if ((ha->ip_config.ipv6_link_local_state == |
228 | IP_ADDRSTATE_PREFERRED) || |
229 | (ha->ip_config.ipv6_addr0_state == |
230 | IP_ADDRSTATE_PREFERRED) || |
231 | (ha->ip_config.ipv6_addr1_state == |
232 | IP_ADDRSTATE_PREFERRED)) { |
233 | DEBUG2(printk(KERN_INFO "scsi%ld: %s: " |
234 | "Preferred IP configured." |
235 | " Don't wait!\n" , ha->host_no, |
236 | __func__)); |
237 | ipv6_wait = 0; |
238 | } |
239 | if (memcmp(p: &ha->ip_config.ipv6_default_router_addr, |
240 | q: ip_address, IPv6_ADDR_LEN) == 0) { |
241 | DEBUG2(printk(KERN_INFO "scsi%ld: %s: " |
242 | "No Router configured. " |
243 | "Don't wait!\n" , ha->host_no, |
244 | __func__)); |
245 | ipv6_wait = 0; |
246 | } |
247 | if ((ha->ip_config.ipv6_default_router_state == |
248 | IPV6_RTRSTATE_MANUAL) && |
249 | (ha->ip_config.ipv6_link_local_state == |
250 | IP_ADDRSTATE_TENTATIVE) && |
251 | (memcmp(p: &ha->ip_config.ipv6_link_local_addr, |
252 | q: &ha->ip_config.ipv6_default_router_addr, size: 4) == |
253 | 0)) { |
254 | DEBUG2(printk("scsi%ld: %s: LinkLocal Router & " |
255 | "IP configured. Don't wait!\n" , |
256 | ha->host_no, __func__)); |
257 | ipv6_wait = 0; |
258 | } |
259 | } |
260 | if (ipv4_wait || ipv6_wait) { |
261 | DEBUG2(printk("scsi%ld: %s: Wait for additional " |
262 | "IP(s) \"" , ha->host_no, __func__)); |
263 | if (ipv4_wait) |
264 | DEBUG2(printk("IPv4 " )); |
265 | if (ha->ip_config.ipv6_link_local_state == |
266 | IP_ADDRSTATE_ACQUIRING) |
267 | DEBUG2(printk("IPv6LinkLocal " )); |
268 | if (ha->ip_config.ipv6_addr0_state == |
269 | IP_ADDRSTATE_ACQUIRING) |
270 | DEBUG2(printk("IPv6Addr0 " )); |
271 | if (ha->ip_config.ipv6_addr1_state == |
272 | IP_ADDRSTATE_ACQUIRING) |
273 | DEBUG2(printk("IPv6Addr1 " )); |
274 | DEBUG2(printk("\"\n" )); |
275 | } |
276 | } |
277 | |
278 | return ipv4_wait|ipv6_wait; |
279 | } |
280 | |
281 | static int qla4_80xx_is_minidump_dma_capable(struct scsi_qla_host *ha, |
282 | struct qla4_8xxx_minidump_template_hdr *md_hdr) |
283 | { |
284 | int offset = (is_qla8022(ha)) ? QLA8022_TEMPLATE_CAP_OFFSET : |
285 | QLA83XX_TEMPLATE_CAP_OFFSET; |
286 | int rval = 1; |
287 | uint32_t *cap_offset; |
288 | |
289 | cap_offset = (uint32_t *)((char *)md_hdr + offset); |
290 | |
291 | if (!(le32_to_cpu(*cap_offset) & BIT_0)) { |
292 | ql4_printk(KERN_INFO, ha, "PEX DMA Not supported %d\n" , |
293 | *cap_offset); |
294 | rval = 0; |
295 | } |
296 | |
297 | return rval; |
298 | } |
299 | |
300 | /** |
301 | * qla4xxx_alloc_fw_dump - Allocate memory for minidump data. |
302 | * @ha: pointer to host adapter structure. |
303 | **/ |
304 | void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha) |
305 | { |
306 | int status; |
307 | uint32_t capture_debug_level; |
308 | int hdr_entry_bit, k; |
309 | void *md_tmp; |
310 | dma_addr_t md_tmp_dma; |
311 | struct qla4_8xxx_minidump_template_hdr *md_hdr; |
312 | int dma_capable; |
313 | |
314 | if (ha->fw_dump) { |
315 | ql4_printk(KERN_WARNING, ha, |
316 | "Firmware dump previously allocated.\n" ); |
317 | return; |
318 | } |
319 | |
320 | status = qla4xxx_req_template_size(ha); |
321 | if (status != QLA_SUCCESS) { |
322 | ql4_printk(KERN_INFO, ha, |
323 | "scsi%ld: Failed to get template size\n" , |
324 | ha->host_no); |
325 | return; |
326 | } |
327 | |
328 | clear_bit(AF_82XX_FW_DUMPED, addr: &ha->flags); |
329 | |
330 | /* Allocate memory for saving the template */ |
331 | md_tmp = dma_alloc_coherent(dev: &ha->pdev->dev, size: ha->fw_dump_tmplt_size, |
332 | dma_handle: &md_tmp_dma, GFP_KERNEL); |
333 | if (!md_tmp) { |
334 | ql4_printk(KERN_INFO, ha, |
335 | "scsi%ld: Failed to allocate DMA memory\n" , |
336 | ha->host_no); |
337 | return; |
338 | } |
339 | |
340 | /* Request template */ |
341 | status = qla4xxx_get_minidump_template(ha, phys_addr: md_tmp_dma); |
342 | if (status != QLA_SUCCESS) { |
343 | ql4_printk(KERN_INFO, ha, |
344 | "scsi%ld: Failed to get minidump template\n" , |
345 | ha->host_no); |
346 | goto alloc_cleanup; |
347 | } |
348 | |
349 | md_hdr = (struct qla4_8xxx_minidump_template_hdr *)md_tmp; |
350 | |
351 | dma_capable = qla4_80xx_is_minidump_dma_capable(ha, md_hdr); |
352 | |
353 | capture_debug_level = md_hdr->capture_debug_level; |
354 | |
355 | /* Get capture mask based on module loadtime setting. */ |
356 | if ((ql4xmdcapmask >= 0x3 && ql4xmdcapmask <= 0x7F) || |
357 | (ql4xmdcapmask == 0xFF && dma_capable)) { |
358 | ha->fw_dump_capture_mask = ql4xmdcapmask; |
359 | } else { |
360 | if (ql4xmdcapmask == 0xFF) |
361 | ql4_printk(KERN_INFO, ha, "Falling back to default capture mask, as PEX DMA is not supported\n" ); |
362 | ha->fw_dump_capture_mask = capture_debug_level; |
363 | } |
364 | |
365 | md_hdr->driver_capture_mask = ha->fw_dump_capture_mask; |
366 | |
367 | DEBUG2(ql4_printk(KERN_INFO, ha, "Minimum num of entries = %d\n" , |
368 | md_hdr->num_of_entries)); |
369 | DEBUG2(ql4_printk(KERN_INFO, ha, "Dump template size = %d\n" , |
370 | ha->fw_dump_tmplt_size)); |
371 | DEBUG2(ql4_printk(KERN_INFO, ha, "Selected Capture mask =0x%x\n" , |
372 | ha->fw_dump_capture_mask)); |
373 | |
374 | /* Calculate fw_dump_size */ |
375 | for (hdr_entry_bit = 0x2, k = 1; (hdr_entry_bit & 0xFF); |
376 | hdr_entry_bit <<= 1, k++) { |
377 | if (hdr_entry_bit & ha->fw_dump_capture_mask) |
378 | ha->fw_dump_size += md_hdr->capture_size_array[k]; |
379 | } |
380 | |
381 | /* Total firmware dump size including command header */ |
382 | ha->fw_dump_size += ha->fw_dump_tmplt_size; |
383 | ha->fw_dump = vmalloc(size: ha->fw_dump_size); |
384 | if (!ha->fw_dump) |
385 | goto alloc_cleanup; |
386 | |
387 | DEBUG2(ql4_printk(KERN_INFO, ha, |
388 | "Minidump Template Size = 0x%x KB\n" , |
389 | ha->fw_dump_tmplt_size)); |
390 | DEBUG2(ql4_printk(KERN_INFO, ha, |
391 | "Total Minidump size = 0x%x KB\n" , ha->fw_dump_size)); |
392 | |
393 | memcpy(ha->fw_dump, md_tmp, ha->fw_dump_tmplt_size); |
394 | ha->fw_dump_tmplt_hdr = ha->fw_dump; |
395 | |
396 | alloc_cleanup: |
397 | dma_free_coherent(dev: &ha->pdev->dev, size: ha->fw_dump_tmplt_size, |
398 | cpu_addr: md_tmp, dma_handle: md_tmp_dma); |
399 | } |
400 | |
401 | static int qla4xxx_fw_ready(struct scsi_qla_host *ha) |
402 | { |
403 | uint32_t timeout_count; |
404 | int ready = 0; |
405 | |
406 | DEBUG2(ql4_printk(KERN_INFO, ha, "Waiting for Firmware Ready..\n" )); |
407 | for (timeout_count = ADAPTER_INIT_TOV; timeout_count > 0; |
408 | timeout_count--) { |
409 | if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, addr: &ha->dpc_flags)) |
410 | qla4xxx_get_dhcp_ip_address(ha); |
411 | |
412 | /* Get firmware state. */ |
413 | if (qla4xxx_get_firmware_state(ha) != QLA_SUCCESS) { |
414 | DEBUG2(printk("scsi%ld: %s: unable to get firmware " |
415 | "state\n" , ha->host_no, __func__)); |
416 | break; |
417 | } |
418 | |
419 | if (ha->firmware_state & FW_STATE_ERROR) { |
420 | DEBUG2(printk("scsi%ld: %s: an unrecoverable error has" |
421 | " occurred\n" , ha->host_no, __func__)); |
422 | break; |
423 | |
424 | } |
425 | if (ha->firmware_state & FW_STATE_CONFIG_WAIT) { |
426 | /* |
427 | * The firmware has not yet been issued an Initialize |
428 | * Firmware command, so issue it now. |
429 | */ |
430 | if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) |
431 | break; |
432 | |
433 | /* Go back and test for ready state - no wait. */ |
434 | continue; |
435 | } |
436 | |
437 | if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) { |
438 | DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:" |
439 | "AUTOCONNECT in progress\n" , |
440 | ha->host_no, __func__)); |
441 | } |
442 | |
443 | if (ha->firmware_state & FW_STATE_CONFIGURING_IP) { |
444 | DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:" |
445 | " CONFIGURING IP\n" , |
446 | ha->host_no, __func__)); |
447 | /* |
448 | * Check for link state after 15 secs and if link is |
449 | * still DOWN then, cable is unplugged. Ignore "DHCP |
450 | * in Progress/CONFIGURING IP" bit to check if firmware |
451 | * is in ready state or not after 15 secs. |
452 | * This is applicable for both 2.x & 3.x firmware |
453 | */ |
454 | if (timeout_count <= (ADAPTER_INIT_TOV - 15)) { |
455 | if (ha->addl_fw_state & FW_ADDSTATE_LINK_UP) { |
456 | DEBUG2(printk(KERN_INFO "scsi%ld: %s:" |
457 | " LINK UP (Cable plugged)\n" , |
458 | ha->host_no, __func__)); |
459 | } else if (ha->firmware_state & |
460 | (FW_STATE_CONFIGURING_IP | |
461 | FW_STATE_READY)) { |
462 | DEBUG2(printk(KERN_INFO "scsi%ld: %s: " |
463 | "LINK DOWN (Cable unplugged)\n" , |
464 | ha->host_no, __func__)); |
465 | ha->firmware_state = FW_STATE_READY; |
466 | } |
467 | } |
468 | } |
469 | |
470 | if (ha->firmware_state == FW_STATE_READY) { |
471 | /* If DHCP IP Addr is available, retrieve it now. */ |
472 | if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, |
473 | addr: &ha->dpc_flags)) |
474 | qla4xxx_get_dhcp_ip_address(ha); |
475 | |
476 | if (!qla4xxx_wait_for_ip_config(ha) || |
477 | timeout_count == 1) { |
478 | DEBUG2(ql4_printk(KERN_INFO, ha, |
479 | "Firmware Ready..\n" )); |
480 | /* The firmware is ready to process SCSI |
481 | commands. */ |
482 | DEBUG2(ql4_printk(KERN_INFO, ha, |
483 | "scsi%ld: %s: MEDIA TYPE" |
484 | " - %s\n" , ha->host_no, |
485 | __func__, (ha->addl_fw_state & |
486 | FW_ADDSTATE_OPTICAL_MEDIA) |
487 | != 0 ? "OPTICAL" : "COPPER" )); |
488 | DEBUG2(ql4_printk(KERN_INFO, ha, |
489 | "scsi%ld: %s: DHCPv4 STATE" |
490 | " Enabled %s\n" , ha->host_no, |
491 | __func__, (ha->addl_fw_state & |
492 | FW_ADDSTATE_DHCPv4_ENABLED) != 0 ? |
493 | "YES" : "NO" )); |
494 | DEBUG2(ql4_printk(KERN_INFO, ha, |
495 | "scsi%ld: %s: LINK %s\n" , |
496 | ha->host_no, __func__, |
497 | (ha->addl_fw_state & |
498 | FW_ADDSTATE_LINK_UP) != 0 ? |
499 | "UP" : "DOWN" )); |
500 | DEBUG2(ql4_printk(KERN_INFO, ha, |
501 | "scsi%ld: %s: iSNS Service " |
502 | "Started %s\n" , |
503 | ha->host_no, __func__, |
504 | (ha->addl_fw_state & |
505 | FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ? |
506 | "YES" : "NO" )); |
507 | |
508 | ready = 1; |
509 | break; |
510 | } |
511 | } |
512 | DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - " |
513 | "seconds expired= %d\n" , ha->host_no, __func__, |
514 | ha->firmware_state, ha->addl_fw_state, |
515 | timeout_count)); |
516 | if (is_qla4032(ha) && |
517 | !(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) && |
518 | (timeout_count < ADAPTER_INIT_TOV - 5)) { |
519 | break; |
520 | } |
521 | |
522 | msleep(msecs: 1000); |
523 | } /* end of for */ |
524 | |
525 | if (timeout_count <= 0) |
526 | DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n" , |
527 | ha->host_no, __func__)); |
528 | |
529 | if (ha->firmware_state & FW_STATE_CONFIGURING_IP) { |
530 | DEBUG2(printk("scsi%ld: %s: FW initialized, but is reporting " |
531 | "it's waiting to configure an IP address\n" , |
532 | ha->host_no, __func__)); |
533 | ready = 1; |
534 | } else if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) { |
535 | DEBUG2(printk("scsi%ld: %s: FW initialized, but " |
536 | "auto-discovery still in process\n" , |
537 | ha->host_no, __func__)); |
538 | ready = 1; |
539 | } |
540 | |
541 | return ready; |
542 | } |
543 | |
544 | /** |
545 | * qla4xxx_init_firmware - initializes the firmware. |
546 | * @ha: pointer to host adapter structure. |
547 | * |
548 | **/ |
549 | static int qla4xxx_init_firmware(struct scsi_qla_host *ha) |
550 | { |
551 | int status = QLA_ERROR; |
552 | |
553 | if (is_aer_supported(ha) && |
554 | test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags)) |
555 | return status; |
556 | |
557 | /* For 82xx, stop firmware before initializing because if BIOS |
558 | * has previously initialized firmware, then driver's initialize |
559 | * firmware will fail. */ |
560 | if (is_qla80XX(ha)) |
561 | qla4_8xxx_stop_firmware(ha); |
562 | |
563 | ql4_printk(KERN_INFO, ha, "Initializing firmware..\n" ); |
564 | if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) { |
565 | DEBUG2(printk("scsi%ld: %s: Failed to initialize firmware " |
566 | "control block\n" , ha->host_no, __func__)); |
567 | return status; |
568 | } |
569 | |
570 | if (!qla4xxx_fw_ready(ha)) |
571 | return status; |
572 | |
573 | if (is_qla80XX(ha) && !test_bit(AF_INIT_DONE, &ha->flags)) |
574 | qla4xxx_alloc_fw_dump(ha); |
575 | |
576 | return qla4xxx_get_firmware_status(ha); |
577 | } |
578 | |
579 | static void qla4xxx_set_model_info(struct scsi_qla_host *ha) |
580 | { |
581 | uint16_t board_id_string[8]; |
582 | int i; |
583 | int size = sizeof(ha->nvram->isp4022.boardIdStr); |
584 | int offset = offsetof(struct eeprom_data, isp4022.boardIdStr) / 2; |
585 | |
586 | for (i = 0; i < (size / 2) ; i++) { |
587 | board_id_string[i] = rd_nvram_word(ha, offset); |
588 | offset += 1; |
589 | } |
590 | |
591 | memcpy(ha->model_name, board_id_string, size); |
592 | } |
593 | |
594 | static int qla4xxx_config_nvram(struct scsi_qla_host *ha) |
595 | { |
596 | unsigned long flags; |
597 | union external_hw_config_reg extHwConfig; |
598 | |
599 | DEBUG2(printk("scsi%ld: %s: Get EEProm parameters \n" , ha->host_no, |
600 | __func__)); |
601 | if (ql4xxx_lock_flash(a: ha) != QLA_SUCCESS) |
602 | return QLA_ERROR; |
603 | if (ql4xxx_lock_nvram(a: ha) != QLA_SUCCESS) { |
604 | ql4xxx_unlock_flash(a: ha); |
605 | return QLA_ERROR; |
606 | } |
607 | |
608 | /* Get EEPRom Parameters from NVRAM and validate */ |
609 | ql4_printk(KERN_INFO, ha, "Configuring NVRAM ...\n" ); |
610 | if (qla4xxx_is_nvram_configuration_valid(ha) == QLA_SUCCESS) { |
611 | spin_lock_irqsave(&ha->hardware_lock, flags); |
612 | extHwConfig.Asuint32_t = |
613 | rd_nvram_word(ha, offset: eeprom_ext_hw_conf_offset(ha)); |
614 | spin_unlock_irqrestore(lock: &ha->hardware_lock, flags); |
615 | } else { |
616 | ql4_printk(KERN_WARNING, ha, |
617 | "scsi%ld: %s: EEProm checksum invalid. " |
618 | "Please update your EEPROM\n" , ha->host_no, |
619 | __func__); |
620 | |
621 | /* Attempt to set defaults */ |
622 | if (is_qla4010(ha)) |
623 | extHwConfig.Asuint32_t = 0x1912; |
624 | else if (is_qla4022(ha) | is_qla4032(ha)) |
625 | extHwConfig.Asuint32_t = 0x0023; |
626 | else |
627 | return QLA_ERROR; |
628 | } |
629 | |
630 | if (is_qla4022(ha) || is_qla4032(ha)) |
631 | qla4xxx_set_model_info(ha); |
632 | else |
633 | strcpy(p: ha->model_name, q: "QLA4010" ); |
634 | |
635 | DEBUG(printk("scsi%ld: %s: Setting extHwConfig to 0xFFFF%04x\n" , |
636 | ha->host_no, __func__, extHwConfig.Asuint32_t)); |
637 | |
638 | spin_lock_irqsave(&ha->hardware_lock, flags); |
639 | writel(val: (0xFFFF << 16) | extHwConfig.Asuint32_t, addr: isp_ext_hw_conf(ha)); |
640 | readl(addr: isp_ext_hw_conf(ha)); |
641 | spin_unlock_irqrestore(lock: &ha->hardware_lock, flags); |
642 | |
643 | ql4xxx_unlock_nvram(a: ha); |
644 | ql4xxx_unlock_flash(a: ha); |
645 | |
646 | return QLA_SUCCESS; |
647 | } |
648 | |
649 | /** |
650 | * qla4_8xxx_pci_config() - Setup ISP82xx PCI configuration registers. |
651 | * @ha: HA context |
652 | */ |
653 | void qla4_8xxx_pci_config(struct scsi_qla_host *ha) |
654 | { |
655 | pci_set_master(dev: ha->pdev); |
656 | } |
657 | |
658 | void qla4xxx_pci_config(struct scsi_qla_host *ha) |
659 | { |
660 | uint16_t w; |
661 | int status; |
662 | |
663 | ql4_printk(KERN_INFO, ha, "Configuring PCI space...\n" ); |
664 | |
665 | pci_set_master(dev: ha->pdev); |
666 | status = pci_set_mwi(dev: ha->pdev); |
667 | if (status) |
668 | ql4_printk(KERN_WARNING, ha, "Failed to set MWI\n" ); |
669 | |
670 | /* |
671 | * We want to respect framework's setting of PCI configuration space |
672 | * command register and also want to make sure that all bits of |
673 | * interest to us are properly set in command register. |
674 | */ |
675 | pci_read_config_word(dev: ha->pdev, PCI_COMMAND, val: &w); |
676 | w |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR; |
677 | w &= ~PCI_COMMAND_INTX_DISABLE; |
678 | pci_write_config_word(dev: ha->pdev, PCI_COMMAND, val: w); |
679 | } |
680 | |
681 | static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha) |
682 | { |
683 | int status = QLA_ERROR; |
684 | unsigned long max_wait_time; |
685 | unsigned long flags; |
686 | uint32_t mbox_status; |
687 | |
688 | ql4_printk(KERN_INFO, ha, "Starting firmware ...\n" ); |
689 | |
690 | /* |
691 | * Start firmware from flash ROM |
692 | * |
693 | * WORKAROUND: Stuff a non-constant value that the firmware can |
694 | * use as a seed for a random number generator in MB7 prior to |
695 | * setting BOOT_ENABLE. Fixes problem where the TCP |
696 | * connections use the same TCP ports after each reboot, |
697 | * causing some connections to not get re-established. |
698 | */ |
699 | DEBUG(printk("scsi%d: %s: Start firmware from flash ROM\n" , |
700 | ha->host_no, __func__)); |
701 | |
702 | spin_lock_irqsave(&ha->hardware_lock, flags); |
703 | writel(val: jiffies, addr: &ha->reg->mailbox[7]); |
704 | if (is_qla4022(ha) | is_qla4032(ha)) |
705 | writel(val: set_rmask(NVR_WRITE_ENABLE), |
706 | addr: &ha->reg->u1.isp4022.nvram); |
707 | |
708 | writel(val: 2, addr: &ha->reg->mailbox[6]); |
709 | readl(addr: &ha->reg->mailbox[6]); |
710 | |
711 | writel(val: set_rmask(CSR_BOOT_ENABLE), addr: &ha->reg->ctrl_status); |
712 | readl(addr: &ha->reg->ctrl_status); |
713 | spin_unlock_irqrestore(lock: &ha->hardware_lock, flags); |
714 | |
715 | /* Wait for firmware to come UP. */ |
716 | DEBUG2(printk(KERN_INFO "scsi%ld: %s: Wait up to %d seconds for " |
717 | "boot firmware to complete...\n" , |
718 | ha->host_no, __func__, FIRMWARE_UP_TOV)); |
719 | max_wait_time = jiffies + (FIRMWARE_UP_TOV * HZ); |
720 | do { |
721 | uint32_t ctrl_status; |
722 | |
723 | spin_lock_irqsave(&ha->hardware_lock, flags); |
724 | ctrl_status = readw(addr: &ha->reg->ctrl_status); |
725 | mbox_status = readw(addr: &ha->reg->mailbox[0]); |
726 | spin_unlock_irqrestore(lock: &ha->hardware_lock, flags); |
727 | |
728 | if (ctrl_status & set_rmask(CSR_SCSI_PROCESSOR_INTR)) |
729 | break; |
730 | if (mbox_status == MBOX_STS_COMMAND_COMPLETE) |
731 | break; |
732 | |
733 | DEBUG2(printk(KERN_INFO "scsi%ld: %s: Waiting for boot " |
734 | "firmware to complete... ctrl_sts=0x%x, remaining=%ld\n" , |
735 | ha->host_no, __func__, ctrl_status, max_wait_time)); |
736 | |
737 | msleep_interruptible(msecs: 250); |
738 | } while (!time_after_eq(jiffies, max_wait_time)); |
739 | |
740 | if (mbox_status == MBOX_STS_COMMAND_COMPLETE) { |
741 | DEBUG(printk(KERN_INFO "scsi%ld: %s: Firmware has started\n" , |
742 | ha->host_no, __func__)); |
743 | |
744 | spin_lock_irqsave(&ha->hardware_lock, flags); |
745 | writel(val: set_rmask(CSR_SCSI_PROCESSOR_INTR), |
746 | addr: &ha->reg->ctrl_status); |
747 | readl(addr: &ha->reg->ctrl_status); |
748 | spin_unlock_irqrestore(lock: &ha->hardware_lock, flags); |
749 | |
750 | status = QLA_SUCCESS; |
751 | } else { |
752 | printk(KERN_INFO "scsi%ld: %s: Boot firmware failed " |
753 | "- mbox status 0x%x\n" , ha->host_no, __func__, |
754 | mbox_status); |
755 | status = QLA_ERROR; |
756 | } |
757 | return status; |
758 | } |
759 | |
760 | int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) |
761 | { |
762 | #define QL4_LOCK_DRVR_WAIT 60 |
763 | #define QL4_LOCK_DRVR_SLEEP 1 |
764 | |
765 | int drvr_wait = QL4_LOCK_DRVR_WAIT; |
766 | while (drvr_wait) { |
767 | if (ql4xxx_lock_drvr(a) == 0) { |
768 | ssleep(QL4_LOCK_DRVR_SLEEP); |
769 | DEBUG2(printk("scsi%ld: %s: Waiting for " |
770 | "Global Init Semaphore(%d)...\n" , |
771 | a->host_no, |
772 | __func__, drvr_wait)); |
773 | drvr_wait -= QL4_LOCK_DRVR_SLEEP; |
774 | } else { |
775 | DEBUG2(printk("scsi%ld: %s: Global Init Semaphore " |
776 | "acquired\n" , a->host_no, __func__)); |
777 | return QLA_SUCCESS; |
778 | } |
779 | } |
780 | return QLA_ERROR; |
781 | } |
782 | |
783 | /** |
784 | * qla4xxx_start_firmware - starts qla4xxx firmware |
785 | * @ha: Pointer to host adapter structure. |
786 | * |
787 | * This routine performs the necessary steps to start the firmware for |
788 | * the QLA4010 adapter. |
789 | **/ |
790 | int qla4xxx_start_firmware(struct scsi_qla_host *ha) |
791 | { |
792 | unsigned long flags = 0; |
793 | uint32_t mbox_status; |
794 | int status = QLA_ERROR; |
795 | int soft_reset = 1; |
796 | int config_chip = 0; |
797 | |
798 | if (is_qla4022(ha) | is_qla4032(ha)) |
799 | ql4xxx_set_mac_number(ha); |
800 | |
801 | if (ql4xxx_lock_drvr_wait(a: ha) != QLA_SUCCESS) |
802 | return QLA_ERROR; |
803 | |
804 | spin_lock_irqsave(&ha->hardware_lock, flags); |
805 | |
806 | DEBUG2(printk("scsi%ld: %s: port_ctrl = 0x%08X\n" , ha->host_no, |
807 | __func__, readw(isp_port_ctrl(ha)))); |
808 | DEBUG(printk("scsi%ld: %s: port_status = 0x%08X\n" , ha->host_no, |
809 | __func__, readw(isp_port_status(ha)))); |
810 | |
811 | /* Is Hardware already initialized? */ |
812 | if ((readw(addr: isp_port_ctrl(ha)) & 0x8000) != 0) { |
813 | DEBUG(printk("scsi%ld: %s: Hardware has already been " |
814 | "initialized\n" , ha->host_no, __func__)); |
815 | |
816 | /* Receive firmware boot acknowledgement */ |
817 | mbox_status = readw(addr: &ha->reg->mailbox[0]); |
818 | |
819 | DEBUG2(printk("scsi%ld: %s: H/W Config complete - mbox[0]= " |
820 | "0x%x\n" , ha->host_no, __func__, mbox_status)); |
821 | |
822 | /* Is firmware already booted? */ |
823 | if (mbox_status == 0) { |
824 | /* F/W not running, must be config by net driver */ |
825 | config_chip = 1; |
826 | soft_reset = 0; |
827 | } else { |
828 | writel(val: set_rmask(CSR_SCSI_PROCESSOR_INTR), |
829 | addr: &ha->reg->ctrl_status); |
830 | readl(addr: &ha->reg->ctrl_status); |
831 | writel(val: set_rmask(CSR_SCSI_COMPLETION_INTR), |
832 | addr: &ha->reg->ctrl_status); |
833 | readl(addr: &ha->reg->ctrl_status); |
834 | spin_unlock_irqrestore(lock: &ha->hardware_lock, flags); |
835 | if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) { |
836 | DEBUG2(printk("scsi%ld: %s: Get firmware " |
837 | "state -- state = 0x%x\n" , |
838 | ha->host_no, |
839 | __func__, ha->firmware_state)); |
840 | /* F/W is running */ |
841 | if (ha->firmware_state & |
842 | FW_STATE_CONFIG_WAIT) { |
843 | DEBUG2(printk("scsi%ld: %s: Firmware " |
844 | "in known state -- " |
845 | "config and " |
846 | "boot, state = 0x%x\n" , |
847 | ha->host_no, __func__, |
848 | ha->firmware_state)); |
849 | config_chip = 1; |
850 | soft_reset = 0; |
851 | } |
852 | } else { |
853 | DEBUG2(printk("scsi%ld: %s: Firmware in " |
854 | "unknown state -- resetting," |
855 | " state = " |
856 | "0x%x\n" , ha->host_no, __func__, |
857 | ha->firmware_state)); |
858 | } |
859 | spin_lock_irqsave(&ha->hardware_lock, flags); |
860 | } |
861 | } else { |
862 | DEBUG(printk("scsi%ld: %s: H/W initialization hasn't been " |
863 | "started - resetting\n" , ha->host_no, __func__)); |
864 | } |
865 | spin_unlock_irqrestore(lock: &ha->hardware_lock, flags); |
866 | |
867 | DEBUG(printk("scsi%ld: %s: Flags soft_rest=%d, config= %d\n " , |
868 | ha->host_no, __func__, soft_reset, config_chip)); |
869 | if (soft_reset) { |
870 | DEBUG(printk("scsi%ld: %s: Issue Soft Reset\n" , ha->host_no, |
871 | __func__)); |
872 | status = qla4xxx_soft_reset(ha); /* NOTE: acquires drvr |
873 | * lock again, but ok */ |
874 | if (status == QLA_ERROR) { |
875 | DEBUG(printk("scsi%d: %s: Soft Reset failed!\n" , |
876 | ha->host_no, __func__)); |
877 | ql4xxx_unlock_drvr(a: ha); |
878 | return QLA_ERROR; |
879 | } |
880 | config_chip = 1; |
881 | |
882 | /* Reset clears the semaphore, so acquire again */ |
883 | if (ql4xxx_lock_drvr_wait(a: ha) != QLA_SUCCESS) |
884 | return QLA_ERROR; |
885 | } |
886 | |
887 | if (config_chip) { |
888 | if ((status = qla4xxx_config_nvram(ha)) == QLA_SUCCESS) |
889 | status = qla4xxx_start_firmware_from_flash(ha); |
890 | } |
891 | |
892 | ql4xxx_unlock_drvr(a: ha); |
893 | if (status == QLA_SUCCESS) { |
894 | if (test_and_clear_bit(AF_GET_CRASH_RECORD, addr: &ha->flags)) |
895 | qla4xxx_get_crash_record(ha); |
896 | |
897 | qla4xxx_init_rings(ha); |
898 | } else { |
899 | DEBUG(printk("scsi%ld: %s: Firmware has NOT started\n" , |
900 | ha->host_no, __func__)); |
901 | } |
902 | return status; |
903 | } |
904 | /** |
905 | * qla4xxx_free_ddb_index - Free DDBs reserved by firmware |
906 | * @ha: pointer to adapter structure |
907 | * |
908 | * Since firmware is not running in autoconnect mode the DDB indices should |
909 | * be freed so that when login happens from user space there are free DDB |
910 | * indices available. |
911 | **/ |
912 | void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) |
913 | { |
914 | int max_ddbs; |
915 | int ret; |
916 | uint32_t idx = 0, next_idx = 0; |
917 | uint32_t state = 0, conn_err = 0; |
918 | |
919 | max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : |
920 | MAX_DEV_DB_ENTRIES; |
921 | |
922 | for (idx = 0; idx < max_ddbs; idx = next_idx) { |
923 | ret = qla4xxx_get_fwddb_entry(ha, fw_ddb_index: idx, NULL, fw_ddb_entry_dma: 0, NULL, |
924 | next_ddb_index: &next_idx, fw_ddb_device_state: &state, conn_err_detail: &conn_err, |
925 | NULL, NULL); |
926 | if (ret == QLA_ERROR) { |
927 | next_idx++; |
928 | continue; |
929 | } |
930 | if (state == DDB_DS_NO_CONNECTION_ACTIVE || |
931 | state == DDB_DS_SESSION_FAILED) { |
932 | DEBUG2(ql4_printk(KERN_INFO, ha, |
933 | "Freeing DDB index = 0x%x\n" , idx)); |
934 | ret = qla4xxx_clear_ddb_entry(ha, fw_ddb_index: idx); |
935 | if (ret == QLA_ERROR) |
936 | ql4_printk(KERN_ERR, ha, |
937 | "Unable to clear DDB index = " |
938 | "0x%x\n" , idx); |
939 | } |
940 | if (next_idx == 0) |
941 | break; |
942 | } |
943 | } |
944 | |
945 | /** |
946 | * qla4xxx_initialize_adapter - initiailizes hba |
947 | * @ha: Pointer to host adapter structure. |
948 | * @is_reset: Is this init path or reset path |
949 | * |
950 | * This routine parforms all of the steps necessary to initialize the adapter. |
951 | * |
952 | **/ |
953 | int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset) |
954 | { |
955 | int status = QLA_ERROR; |
956 | |
957 | ha->eeprom_cmd_data = 0; |
958 | |
959 | ql4_printk(KERN_INFO, ha, "Configuring PCI space...\n" ); |
960 | ha->isp_ops->pci_config(ha); |
961 | |
962 | ha->isp_ops->disable_intrs(ha); |
963 | |
964 | /* Initialize the Host adapter request/response queues and firmware */ |
965 | if (ha->isp_ops->start_firmware(ha) == QLA_ERROR) |
966 | goto exit_init_hba; |
967 | |
968 | /* |
969 | * For ISP83XX, mailbox and IOCB interrupts are enabled separately. |
970 | * Mailbox interrupts must be enabled prior to issuing any mailbox |
971 | * command in order to prevent the possibility of losing interrupts |
972 | * while switching from polling to interrupt mode. IOCB interrupts are |
973 | * enabled via isp_ops->enable_intrs. |
974 | */ |
975 | if (is_qla8032(ha) || is_qla8042(ha)) |
976 | qla4_83xx_enable_mbox_intrs(ha); |
977 | |
978 | if (qla4xxx_about_firmware(ha) == QLA_ERROR) |
979 | goto exit_init_hba; |
980 | |
981 | if (ha->isp_ops->get_sys_info(ha) == QLA_ERROR) |
982 | goto exit_init_hba; |
983 | |
984 | qla4xxx_init_local_data(ha); |
985 | |
986 | status = qla4xxx_init_firmware(ha); |
987 | if (status == QLA_ERROR) |
988 | goto exit_init_hba; |
989 | |
990 | if (is_reset == RESET_ADAPTER) |
991 | qla4xxx_build_ddb_list(ha, is_reset); |
992 | |
993 | set_bit(AF_ONLINE, addr: &ha->flags); |
994 | |
995 | exit_init_hba: |
996 | DEBUG2(printk("scsi%ld: initialize adapter: %s\n" , ha->host_no, |
997 | status == QLA_ERROR ? "FAILED" : "SUCCEEDED" )); |
998 | return status; |
999 | } |
1000 | |
1001 | int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, |
1002 | struct ddb_entry *ddb_entry, uint32_t state) |
1003 | { |
1004 | uint32_t old_fw_ddb_device_state; |
1005 | int status = QLA_ERROR; |
1006 | |
1007 | old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; |
1008 | DEBUG2(ql4_printk(KERN_INFO, ha, |
1009 | "%s: DDB - old state = 0x%x, new state = 0x%x for " |
1010 | "index [%d]\n" , __func__, |
1011 | ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); |
1012 | |
1013 | ddb_entry->fw_ddb_device_state = state; |
1014 | |
1015 | switch (old_fw_ddb_device_state) { |
1016 | case DDB_DS_LOGIN_IN_PROCESS: |
1017 | switch (state) { |
1018 | case DDB_DS_SESSION_ACTIVE: |
1019 | case DDB_DS_DISCOVERY: |
1020 | qla4xxx_update_session_conn_param(ha, ddb_entry); |
1021 | ddb_entry->unblock_sess(ddb_entry->sess); |
1022 | status = QLA_SUCCESS; |
1023 | break; |
1024 | case DDB_DS_SESSION_FAILED: |
1025 | case DDB_DS_NO_CONNECTION_ACTIVE: |
1026 | iscsi_conn_login_event(conn: ddb_entry->conn, |
1027 | state: ISCSI_CONN_STATE_FREE); |
1028 | status = QLA_SUCCESS; |
1029 | break; |
1030 | } |
1031 | break; |
1032 | case DDB_DS_SESSION_ACTIVE: |
1033 | case DDB_DS_DISCOVERY: |
1034 | switch (state) { |
1035 | case DDB_DS_SESSION_FAILED: |
1036 | /* |
1037 | * iscsi_session failure will cause userspace to |
1038 | * stop the connection which in turn would block the |
1039 | * iscsi_session and start relogin |
1040 | */ |
1041 | iscsi_session_failure(session: ddb_entry->sess->dd_data, |
1042 | err: ISCSI_ERR_CONN_FAILED); |
1043 | status = QLA_SUCCESS; |
1044 | break; |
1045 | case DDB_DS_NO_CONNECTION_ACTIVE: |
1046 | clear_bit(nr: fw_ddb_index, addr: ha->ddb_idx_map); |
1047 | status = QLA_SUCCESS; |
1048 | break; |
1049 | } |
1050 | break; |
1051 | case DDB_DS_SESSION_FAILED: |
1052 | switch (state) { |
1053 | case DDB_DS_SESSION_ACTIVE: |
1054 | case DDB_DS_DISCOVERY: |
1055 | ddb_entry->unblock_sess(ddb_entry->sess); |
1056 | qla4xxx_update_session_conn_param(ha, ddb_entry); |
1057 | status = QLA_SUCCESS; |
1058 | break; |
1059 | case DDB_DS_SESSION_FAILED: |
1060 | iscsi_session_failure(session: ddb_entry->sess->dd_data, |
1061 | err: ISCSI_ERR_CONN_FAILED); |
1062 | status = QLA_SUCCESS; |
1063 | break; |
1064 | } |
1065 | break; |
1066 | default: |
1067 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unknown Event\n" , |
1068 | __func__)); |
1069 | break; |
1070 | } |
1071 | return status; |
1072 | } |
1073 | |
1074 | void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry) |
1075 | { |
1076 | /* |
1077 | * This triggers a relogin. After the relogin_timer |
1078 | * expires, the relogin gets scheduled. We must wait a |
1079 | * minimum amount of time since receiving an 0x8014 AEN |
1080 | * with failed device_state or a logout response before |
1081 | * we can issue another relogin. |
1082 | * |
1083 | * Firmware pads this timeout: (time2wait +1). |
1084 | * Driver retry to login should be longer than F/W. |
1085 | * Otherwise F/W will fail |
1086 | * set_ddb() mbx cmd with 0x4005 since it still |
1087 | * counting down its time2wait. |
1088 | */ |
1089 | atomic_set(v: &ddb_entry->relogin_timer, i: 0); |
1090 | atomic_set(v: &ddb_entry->retry_relogin_timer, |
1091 | i: ddb_entry->default_time2wait + 4); |
1092 | |
1093 | } |
1094 | |
1095 | int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, |
1096 | struct ddb_entry *ddb_entry, uint32_t state) |
1097 | { |
1098 | uint32_t old_fw_ddb_device_state; |
1099 | int status = QLA_ERROR; |
1100 | |
1101 | old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; |
1102 | DEBUG2(ql4_printk(KERN_INFO, ha, |
1103 | "%s: DDB - old state = 0x%x, new state = 0x%x for " |
1104 | "index [%d]\n" , __func__, |
1105 | ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); |
1106 | |
1107 | ddb_entry->fw_ddb_device_state = state; |
1108 | |
1109 | switch (old_fw_ddb_device_state) { |
1110 | case DDB_DS_LOGIN_IN_PROCESS: |
1111 | case DDB_DS_NO_CONNECTION_ACTIVE: |
1112 | switch (state) { |
1113 | case DDB_DS_SESSION_ACTIVE: |
1114 | ddb_entry->unblock_sess(ddb_entry->sess); |
1115 | qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); |
1116 | status = QLA_SUCCESS; |
1117 | break; |
1118 | case DDB_DS_SESSION_FAILED: |
1119 | iscsi_block_session(session: ddb_entry->sess); |
1120 | if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) |
1121 | qla4xxx_arm_relogin_timer(ddb_entry); |
1122 | status = QLA_SUCCESS; |
1123 | break; |
1124 | } |
1125 | break; |
1126 | case DDB_DS_SESSION_ACTIVE: |
1127 | switch (state) { |
1128 | case DDB_DS_SESSION_FAILED: |
1129 | iscsi_block_session(session: ddb_entry->sess); |
1130 | if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) |
1131 | qla4xxx_arm_relogin_timer(ddb_entry); |
1132 | status = QLA_SUCCESS; |
1133 | break; |
1134 | } |
1135 | break; |
1136 | case DDB_DS_SESSION_FAILED: |
1137 | switch (state) { |
1138 | case DDB_DS_SESSION_ACTIVE: |
1139 | ddb_entry->unblock_sess(ddb_entry->sess); |
1140 | qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); |
1141 | status = QLA_SUCCESS; |
1142 | break; |
1143 | case DDB_DS_SESSION_FAILED: |
1144 | if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) |
1145 | qla4xxx_arm_relogin_timer(ddb_entry); |
1146 | status = QLA_SUCCESS; |
1147 | break; |
1148 | } |
1149 | break; |
1150 | default: |
1151 | DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unknown Event\n" , |
1152 | __func__)); |
1153 | break; |
1154 | } |
1155 | return status; |
1156 | } |
1157 | |
1158 | /** |
1159 | * qla4xxx_process_ddb_changed - process ddb state change |
1160 | * @ha: Pointer to host adapter structure. |
1161 | * @fw_ddb_index: Firmware's device database index |
1162 | * @state: Device state |
1163 | * @conn_err: Unused |
1164 | * |
1165 | * This routine processes a Decive Database Changed AEN Event. |
1166 | **/ |
1167 | int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, |
1168 | uint32_t fw_ddb_index, |
1169 | uint32_t state, uint32_t conn_err) |
1170 | { |
1171 | struct ddb_entry *ddb_entry; |
1172 | |
1173 | /* check for out of range index */ |
1174 | if (fw_ddb_index >= MAX_DDB_ENTRIES) |
1175 | goto exit_ddb_event; |
1176 | |
1177 | /* Get the corresponging ddb entry */ |
1178 | ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); |
1179 | /* Device does not currently exist in our database. */ |
1180 | if (ddb_entry == NULL) { |
1181 | ql4_printk(KERN_ERR, ha, "%s: No ddb_entry at FW index [%d]\n" , |
1182 | __func__, fw_ddb_index); |
1183 | |
1184 | if (state == DDB_DS_NO_CONNECTION_ACTIVE) |
1185 | clear_bit(nr: fw_ddb_index, addr: ha->ddb_idx_map); |
1186 | |
1187 | goto exit_ddb_event; |
1188 | } |
1189 | |
1190 | ddb_entry->ddb_change(ha, fw_ddb_index, ddb_entry, state); |
1191 | |
1192 | exit_ddb_event: |
1193 | return QLA_ERROR; |
1194 | } |
1195 | |
1196 | /** |
1197 | * qla4xxx_login_flash_ddb - Login to target (DDB) |
1198 | * @cls_session: Pointer to the session to login |
1199 | * |
1200 | * This routine logins to the target. |
1201 | * Issues setddb and conn open mbx |
1202 | **/ |
1203 | void qla4xxx_login_flash_ddb(struct iscsi_cls_session *cls_session) |
1204 | { |
1205 | struct iscsi_session *sess; |
1206 | struct ddb_entry *ddb_entry; |
1207 | struct scsi_qla_host *ha; |
1208 | struct dev_db_entry *fw_ddb_entry = NULL; |
1209 | dma_addr_t fw_ddb_dma; |
1210 | uint32_t mbx_sts = 0; |
1211 | int ret; |
1212 | |
1213 | sess = cls_session->dd_data; |
1214 | ddb_entry = sess->dd_data; |
1215 | ha = ddb_entry->ha; |
1216 | |
1217 | if (!test_bit(AF_LINK_UP, &ha->flags)) |
1218 | return; |
1219 | |
1220 | if (ddb_entry->ddb_type != FLASH_DDB) { |
1221 | DEBUG2(ql4_printk(KERN_INFO, ha, |
1222 | "Skipping login to non FLASH DB" )); |
1223 | goto exit_login; |
1224 | } |
1225 | |
1226 | fw_ddb_entry = dma_pool_alloc(pool: ha->fw_ddb_dma_pool, GFP_KERNEL, |
1227 | handle: &fw_ddb_dma); |
1228 | if (fw_ddb_entry == NULL) { |
1229 | DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n" )); |
1230 | goto exit_login; |
1231 | } |
1232 | |
1233 | if (ddb_entry->fw_ddb_index == INVALID_ENTRY) { |
1234 | ret = qla4xxx_get_ddb_index(ha, ddb_index: &ddb_entry->fw_ddb_index); |
1235 | if (ret == QLA_ERROR) |
1236 | goto exit_login; |
1237 | |
1238 | ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; |
1239 | ha->tot_ddbs++; |
1240 | } |
1241 | |
1242 | memcpy(fw_ddb_entry, &ddb_entry->fw_ddb_entry, |
1243 | sizeof(struct dev_db_entry)); |
1244 | ddb_entry->sess->target_id = ddb_entry->fw_ddb_index; |
1245 | |
1246 | ret = qla4xxx_set_ddb_entry(ha, fw_ddb_index: ddb_entry->fw_ddb_index, |
1247 | fw_ddb_entry_dma: fw_ddb_dma, mbx_sts: &mbx_sts); |
1248 | if (ret == QLA_ERROR) { |
1249 | DEBUG2(ql4_printk(KERN_ERR, ha, "Set DDB failed\n" )); |
1250 | goto exit_login; |
1251 | } |
1252 | |
1253 | ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; |
1254 | ret = qla4xxx_conn_open(ha, fw_ddb_index: ddb_entry->fw_ddb_index); |
1255 | if (ret == QLA_ERROR) { |
1256 | ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n" , __func__, |
1257 | sess->targetname); |
1258 | goto exit_login; |
1259 | } |
1260 | |
1261 | exit_login: |
1262 | if (fw_ddb_entry) |
1263 | dma_pool_free(pool: ha->fw_ddb_dma_pool, vaddr: fw_ddb_entry, addr: fw_ddb_dma); |
1264 | } |
1265 | |
1266 | |