diff options
author | Vikas Chaudhary <vikas.chaudhary@qlogic.com> | 2010-04-28 02:07:07 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-05-02 15:38:19 -0400 |
commit | 2a49a78ed3c8d7c8319595270110c69f99c61a74 (patch) | |
tree | 14a771d774b25525aa1604e48004b6bc0415c104 /drivers/scsi/qla4xxx/ql4_init.c | |
parent | 3487d9e7c4727b3e587f61d2120e35e34f200faa (diff) |
[SCSI] qla4xxx: added IPv6 support.
Signed-off-by: Karen Higgins <karen.higgins@qlogic.com>
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Signed-off-by: Ravi Anand <ravi.anand@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/qla4xxx/ql4_init.c')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_init.c | 218 |
1 files changed, 178 insertions, 40 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 92329a461c6..36ec02c49a1 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c | |||
@@ -189,6 +189,78 @@ static int qla4xxx_init_local_data(struct scsi_qla_host *ha) | |||
189 | return qla4xxx_get_firmware_status(ha); | 189 | return qla4xxx_get_firmware_status(ha); |
190 | } | 190 | } |
191 | 191 | ||
192 | static uint8_t | ||
193 | qla4xxx_wait_for_ip_config(struct scsi_qla_host *ha) | ||
194 | { | ||
195 | uint8_t ipv4_wait = 0; | ||
196 | uint8_t ipv6_wait = 0; | ||
197 | int8_t ip_address[IPv6_ADDR_LEN] = {0} ; | ||
198 | |||
199 | /* If both IPv4 & IPv6 are enabled, possibly only one | ||
200 | * IP address may be acquired, so check to see if we | ||
201 | * need to wait for another */ | ||
202 | if (is_ipv4_enabled(ha) && is_ipv6_enabled(ha)) { | ||
203 | if (((ha->addl_fw_state & FW_ADDSTATE_DHCPv4_ENABLED) != 0) && | ||
204 | ((ha->addl_fw_state & | ||
205 | FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED) == 0)) { | ||
206 | ipv4_wait = 1; | ||
207 | } | ||
208 | if (((ha->ipv6_addl_options & | ||
209 | IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) != 0) && | ||
210 | ((ha->ipv6_link_local_state == IP_ADDRSTATE_ACQUIRING) || | ||
211 | (ha->ipv6_addr0_state == IP_ADDRSTATE_ACQUIRING) || | ||
212 | (ha->ipv6_addr1_state == IP_ADDRSTATE_ACQUIRING))) { | ||
213 | |||
214 | ipv6_wait = 1; | ||
215 | |||
216 | if ((ha->ipv6_link_local_state == | ||
217 | IP_ADDRSTATE_PREFERRED) || | ||
218 | (ha->ipv6_addr0_state == IP_ADDRSTATE_PREFERRED) || | ||
219 | (ha->ipv6_addr1_state == IP_ADDRSTATE_PREFERRED)) { | ||
220 | DEBUG2(printk(KERN_INFO "scsi%ld: %s: " | ||
221 | "Preferred IP configured." | ||
222 | " Don't wait!\n", ha->host_no, | ||
223 | __func__)); | ||
224 | ipv6_wait = 0; | ||
225 | } | ||
226 | if (memcmp(&ha->ipv6_default_router_addr, ip_address, | ||
227 | IPv6_ADDR_LEN) == 0) { | ||
228 | DEBUG2(printk(KERN_INFO "scsi%ld: %s: " | ||
229 | "No Router configured. " | ||
230 | "Don't wait!\n", ha->host_no, | ||
231 | __func__)); | ||
232 | ipv6_wait = 0; | ||
233 | } | ||
234 | if ((ha->ipv6_default_router_state == | ||
235 | IPV6_RTRSTATE_MANUAL) && | ||
236 | (ha->ipv6_link_local_state == | ||
237 | IP_ADDRSTATE_TENTATIVE) && | ||
238 | (memcmp(&ha->ipv6_link_local_addr, | ||
239 | &ha->ipv6_default_router_addr, 4) == 0)) { | ||
240 | DEBUG2(printk("scsi%ld: %s: LinkLocal Router & " | ||
241 | "IP configured. Don't wait!\n", | ||
242 | ha->host_no, __func__)); | ||
243 | ipv6_wait = 0; | ||
244 | } | ||
245 | } | ||
246 | if (ipv4_wait || ipv6_wait) { | ||
247 | DEBUG2(printk("scsi%ld: %s: Wait for additional " | ||
248 | "IP(s) \"", ha->host_no, __func__)); | ||
249 | if (ipv4_wait) | ||
250 | DEBUG2(printk("IPv4 ")); | ||
251 | if (ha->ipv6_link_local_state == IP_ADDRSTATE_ACQUIRING) | ||
252 | DEBUG2(printk("IPv6LinkLocal ")); | ||
253 | if (ha->ipv6_addr0_state == IP_ADDRSTATE_ACQUIRING) | ||
254 | DEBUG2(printk("IPv6Addr0 ")); | ||
255 | if (ha->ipv6_addr1_state == IP_ADDRSTATE_ACQUIRING) | ||
256 | DEBUG2(printk("IPv6Addr1 ")); | ||
257 | DEBUG2(printk("\"\n")); | ||
258 | } | ||
259 | } | ||
260 | |||
261 | return ipv4_wait|ipv6_wait; | ||
262 | } | ||
263 | |||
192 | static int qla4xxx_fw_ready(struct scsi_qla_host *ha) | 264 | static int qla4xxx_fw_ready(struct scsi_qla_host *ha) |
193 | { | 265 | { |
194 | uint32_t timeout_count; | 266 | uint32_t timeout_count; |
@@ -226,38 +298,80 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) | |||
226 | continue; | 298 | continue; |
227 | } | 299 | } |
228 | 300 | ||
301 | if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) { | ||
302 | DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:" | ||
303 | "AUTOCONNECT in progress\n", | ||
304 | ha->host_no, __func__)); | ||
305 | } | ||
306 | |||
307 | if (ha->firmware_state & FW_STATE_CONFIGURING_IP) { | ||
308 | DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:" | ||
309 | " CONFIGURING IP\n", | ||
310 | ha->host_no, __func__)); | ||
311 | /* | ||
312 | * Check for link state after 15 secs and if link is | ||
313 | * still DOWN then, cable is unplugged. Ignore "DHCP | ||
314 | * in Progress/CONFIGURING IP" bit to check if firmware | ||
315 | * is in ready state or not after 15 secs. | ||
316 | * This is applicable for both 2.x & 3.x firmware | ||
317 | */ | ||
318 | if (timeout_count <= (ADAPTER_INIT_TOV - 15)) { | ||
319 | if (ha->addl_fw_state & FW_ADDSTATE_LINK_UP) { | ||
320 | DEBUG2(printk(KERN_INFO "scsi%ld: %s:" | ||
321 | " LINK UP (Cable plugged)\n", | ||
322 | ha->host_no, __func__)); | ||
323 | } else if (ha->firmware_state & | ||
324 | (FW_STATE_CONFIGURING_IP | | ||
325 | FW_STATE_READY)) { | ||
326 | DEBUG2(printk(KERN_INFO "scsi%ld: %s: " | ||
327 | "LINK DOWN (Cable unplugged)\n", | ||
328 | ha->host_no, __func__)); | ||
329 | ha->firmware_state = FW_STATE_READY; | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | |||
229 | if (ha->firmware_state == FW_STATE_READY) { | 334 | if (ha->firmware_state == FW_STATE_READY) { |
230 | DEBUG2(dev_info(&ha->pdev->dev, "Firmware Ready..\n")); | 335 | /* If DHCP IP Addr is available, retrieve it now. */ |
231 | /* The firmware is ready to process SCSI commands. */ | 336 | if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, |
232 | DEBUG2(dev_info(&ha->pdev->dev, | 337 | &ha->dpc_flags)) |
233 | "scsi%ld: %s: MEDIA TYPE - %s\n", | 338 | qla4xxx_get_dhcp_ip_address(ha); |
234 | ha->host_no, | 339 | |
235 | __func__, (ha->addl_fw_state & | 340 | if (!qla4xxx_wait_for_ip_config(ha) || |
236 | FW_ADDSTATE_OPTICAL_MEDIA) | 341 | timeout_count == 1) { |
237 | != 0 ? "OPTICAL" : "COPPER")); | 342 | DEBUG2(dev_info(&ha->pdev->dev, |
238 | DEBUG2(dev_info(&ha->pdev->dev, | 343 | "Firmware Ready..\n")); |
239 | "scsi%ld: %s: DHCP STATE Enabled " | 344 | /* The firmware is ready to process SCSI |
240 | "%s\n", | 345 | commands. */ |
241 | ha->host_no, __func__, | 346 | DEBUG2(dev_info(&ha->pdev->dev, |
242 | (ha->addl_fw_state & | 347 | "scsi%ld: %s: MEDIA TYPE" |
243 | FW_ADDSTATE_DHCP_ENABLED) != 0 ? | 348 | " - %s\n", ha->host_no, |
244 | "YES" : "NO")); | 349 | __func__, (ha->addl_fw_state & |
245 | DEBUG2(dev_info(&ha->pdev->dev, | 350 | FW_ADDSTATE_OPTICAL_MEDIA) |
246 | "scsi%ld: %s: LINK %s\n", | 351 | != 0 ? "OPTICAL" : "COPPER")); |
247 | ha->host_no, __func__, | 352 | DEBUG2(dev_info(&ha->pdev->dev, |
248 | (ha->addl_fw_state & | 353 | "scsi%ld: %s: DHCPv4 STATE" |
249 | FW_ADDSTATE_LINK_UP) != 0 ? | 354 | " Enabled %s\n", ha->host_no, |
250 | "UP" : "DOWN")); | 355 | __func__, (ha->addl_fw_state & |
251 | DEBUG2(dev_info(&ha->pdev->dev, | 356 | FW_ADDSTATE_DHCPv4_ENABLED) != 0 ? |
252 | "scsi%ld: %s: iSNS Service " | 357 | "YES" : "NO")); |
253 | "Started %s\n", | 358 | DEBUG2(dev_info(&ha->pdev->dev, |
254 | ha->host_no, __func__, | 359 | "scsi%ld: %s: LINK %s\n", |
255 | (ha->addl_fw_state & | 360 | ha->host_no, __func__, |
256 | FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ? | 361 | (ha->addl_fw_state & |
257 | "YES" : "NO")); | 362 | FW_ADDSTATE_LINK_UP) != 0 ? |
258 | 363 | "UP" : "DOWN")); | |
259 | ready = 1; | 364 | DEBUG2(dev_info(&ha->pdev->dev, |
260 | break; | 365 | "scsi%ld: %s: iSNS Service " |
366 | "Started %s\n", | ||
367 | ha->host_no, __func__, | ||
368 | (ha->addl_fw_state & | ||
369 | FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ? | ||
370 | "YES" : "NO")); | ||
371 | |||
372 | ready = 1; | ||
373 | break; | ||
374 | } | ||
261 | } | 375 | } |
262 | DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - " | 376 | DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - " |
263 | "seconds expired= %d\n", ha->host_no, __func__, | 377 | "seconds expired= %d\n", ha->host_no, __func__, |
@@ -272,15 +386,19 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) | |||
272 | msleep(1000); | 386 | msleep(1000); |
273 | } /* end of for */ | 387 | } /* end of for */ |
274 | 388 | ||
275 | if (timeout_count == 0) | 389 | if (timeout_count <= 0) |
276 | DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n", | 390 | DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n", |
277 | ha->host_no, __func__)); | 391 | ha->host_no, __func__)); |
278 | 392 | ||
279 | if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) { | 393 | if (ha->firmware_state & FW_STATE_CONFIGURING_IP) { |
280 | DEBUG2(printk("scsi%ld: %s: FW is reporting its waiting to" | 394 | DEBUG2(printk("scsi%ld: %s: FW initialized, but is reporting " |
281 | " grab an IP address from DHCP server\n", | 395 | "it's waiting to configure an IP address\n", |
282 | ha->host_no, __func__)); | 396 | ha->host_no, __func__)); |
283 | ready = 1; | 397 | ready = 1; |
398 | } else if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) { | ||
399 | DEBUG2(printk("scsi%ld: %s: FW initialized, but " | ||
400 | "auto-discovery still in process\n", | ||
401 | ha->host_no, __func__)); | ||
284 | } | 402 | } |
285 | 403 | ||
286 | return ready; | 404 | return ready; |
@@ -419,6 +537,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, | |||
419 | } | 537 | } |
420 | 538 | ||
421 | status = QLA_SUCCESS; | 539 | status = QLA_SUCCESS; |
540 | ddb_entry->options = le16_to_cpu(fw_ddb_entry->options); | ||
422 | ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->tsid); | 541 | ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->tsid); |
423 | ddb_entry->task_mgmt_timeout = | 542 | ddb_entry->task_mgmt_timeout = |
424 | le16_to_cpu(fw_ddb_entry->def_timeout); | 543 | le16_to_cpu(fw_ddb_entry->def_timeout); |
@@ -442,11 +561,30 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, | |||
442 | memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0], | 561 | memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0], |
443 | min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr))); | 562 | min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr))); |
444 | 563 | ||
564 | ddb_entry->iscsi_max_burst_len = fw_ddb_entry->iscsi_max_burst_len; | ||
565 | ddb_entry->iscsi_max_outsnd_r2t = fw_ddb_entry->iscsi_max_outsnd_r2t; | ||
566 | ddb_entry->iscsi_first_burst_len = fw_ddb_entry->iscsi_first_burst_len; | ||
567 | ddb_entry->iscsi_max_rcv_data_seg_len = | ||
568 | fw_ddb_entry->iscsi_max_rcv_data_seg_len; | ||
569 | ddb_entry->iscsi_max_snd_data_seg_len = | ||
570 | fw_ddb_entry->iscsi_max_snd_data_seg_len; | ||
571 | |||
572 | if (ddb_entry->options & DDB_OPT_IPV6_DEVICE) { | ||
573 | memcpy(&ddb_entry->remote_ipv6_addr, | ||
574 | fw_ddb_entry->ip_addr, | ||
575 | min(sizeof(ddb_entry->remote_ipv6_addr), | ||
576 | sizeof(fw_ddb_entry->ip_addr))); | ||
577 | memcpy(&ddb_entry->link_local_ipv6_addr, | ||
578 | fw_ddb_entry->link_local_ipv6_addr, | ||
579 | min(sizeof(ddb_entry->link_local_ipv6_addr), | ||
580 | sizeof(fw_ddb_entry->link_local_ipv6_addr))); | ||
581 | } | ||
582 | |||
445 | DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n", | 583 | DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n", |
446 | ha->host_no, __func__, fw_ddb_index, | 584 | ha->host_no, __func__, fw_ddb_index, |
447 | ddb_entry->fw_ddb_device_state, status)); | 585 | ddb_entry->fw_ddb_device_state, status)); |
448 | 586 | ||
449 | exit_update_ddb: | 587 | exit_update_ddb: |
450 | if (fw_ddb_entry) | 588 | if (fw_ddb_entry) |
451 | dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), | 589 | dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), |
452 | fw_ddb_entry, fw_ddb_entry_dma); | 590 | fw_ddb_entry, fw_ddb_entry_dma); |
@@ -1166,7 +1304,7 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, | |||
1166 | * the ddb_list and wait for DHCP lease acquired aen to come in | 1304 | * the ddb_list and wait for DHCP lease acquired aen to come in |
1167 | * followed by 0x8014 aen" to trigger the tgt discovery process. | 1305 | * followed by 0x8014 aen" to trigger the tgt discovery process. |
1168 | */ | 1306 | */ |
1169 | if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) | 1307 | if (ha->firmware_state & FW_STATE_CONFIGURING_IP) |
1170 | goto exit_init_online; | 1308 | goto exit_init_online; |
1171 | 1309 | ||
1172 | /* Skip device discovery if ip and subnet is zero */ | 1310 | /* Skip device discovery if ip and subnet is zero */ |