diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-10-27 13:37:43 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-11 19:22:33 -0500 |
commit | 87af33fe5f78c27cf9e43c6e586dd6efd4be3e40 (patch) | |
tree | e9960c6e95ed599672d5dcec0d3c4e428ae42799 /drivers/scsi/lpfc/lpfc_hbadisc.c | |
parent | 98c9ea5c026ee47efe2a0f595078dbf199d08f50 (diff) |
[SCSI] lpfc 8.2.3 : FC Discovery Fixes
FC Discovery Fixes:
- Fix up lpfc_drop_node() vs lpfc_nlp_not_used() usage
- Clear ADISC flag when unregistering RPI and REMOVE ndlps if in recovery.
- Fix usage of UNUSED list and ndlps
- Fix PLOGI race conditions
- Reset link if NameServer PLOGI errors occur
- Synchronize GID_FT queries with PLOGI receptions
Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 96 |
1 files changed, 45 insertions, 51 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index e181a98caf16..f64ce88e8a06 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -157,6 +157,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) | |||
157 | struct lpfc_vport *vport; | 157 | struct lpfc_vport *vport; |
158 | struct lpfc_hba *phba; | 158 | struct lpfc_hba *phba; |
159 | uint8_t *name; | 159 | uint8_t *name; |
160 | int put_node; | ||
161 | int put_rport; | ||
160 | int warn_on = 0; | 162 | int warn_on = 0; |
161 | 163 | ||
162 | rport = ndlp->rport; | 164 | rport = ndlp->rport; |
@@ -178,9 +180,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) | |||
178 | return; | 180 | return; |
179 | 181 | ||
180 | if (ndlp->nlp_type & NLP_FABRIC) { | 182 | if (ndlp->nlp_type & NLP_FABRIC) { |
181 | int put_node; | ||
182 | int put_rport; | ||
183 | |||
184 | /* We will clean up these Nodes in linkup */ | 183 | /* We will clean up these Nodes in linkup */ |
185 | put_node = rdata->pnode != NULL; | 184 | put_node = rdata->pnode != NULL; |
186 | put_rport = ndlp->rport != NULL; | 185 | put_rport = ndlp->rport != NULL; |
@@ -222,23 +221,20 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) | |||
222 | ndlp->nlp_state, ndlp->nlp_rpi); | 221 | ndlp->nlp_state, ndlp->nlp_rpi); |
223 | } | 222 | } |
224 | 223 | ||
224 | put_node = rdata->pnode != NULL; | ||
225 | put_rport = ndlp->rport != NULL; | ||
226 | rdata->pnode = NULL; | ||
227 | ndlp->rport = NULL; | ||
228 | if (put_node) | ||
229 | lpfc_nlp_put(ndlp); | ||
230 | if (put_rport) | ||
231 | put_device(&rport->dev); | ||
232 | |||
225 | if (!(vport->load_flag & FC_UNLOADING) && | 233 | if (!(vport->load_flag & FC_UNLOADING) && |
226 | !(ndlp->nlp_flag & NLP_DELAY_TMO) && | 234 | !(ndlp->nlp_flag & NLP_DELAY_TMO) && |
227 | !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && | 235 | !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && |
228 | (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) | 236 | (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) { |
229 | lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); | 237 | lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); |
230 | else { | ||
231 | int put_node; | ||
232 | int put_rport; | ||
233 | |||
234 | put_node = rdata->pnode != NULL; | ||
235 | put_rport = ndlp->rport != NULL; | ||
236 | rdata->pnode = NULL; | ||
237 | ndlp->rport = NULL; | ||
238 | if (put_node) | ||
239 | lpfc_nlp_put(ndlp); | ||
240 | if (put_rport) | ||
241 | put_device(&rport->dev); | ||
242 | } | 238 | } |
243 | } | 239 | } |
244 | 240 | ||
@@ -546,11 +542,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) | |||
546 | } | 542 | } |
547 | } | 543 | } |
548 | 544 | ||
549 | static void | 545 | void |
550 | lpfc_port_link_failure(struct lpfc_vport *vport) | 546 | lpfc_port_link_failure(struct lpfc_vport *vport) |
551 | { | 547 | { |
552 | struct lpfc_nodelist *ndlp, *next_ndlp; | ||
553 | |||
554 | /* Cleanup any outstanding RSCN activity */ | 548 | /* Cleanup any outstanding RSCN activity */ |
555 | lpfc_els_flush_rscn(vport); | 549 | lpfc_els_flush_rscn(vport); |
556 | 550 | ||
@@ -559,11 +553,6 @@ lpfc_port_link_failure(struct lpfc_vport *vport) | |||
559 | 553 | ||
560 | lpfc_cleanup_rpis(vport, 0); | 554 | lpfc_cleanup_rpis(vport, 0); |
561 | 555 | ||
562 | /* free any ndlp's on unused list */ | ||
563 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) | ||
564 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | ||
565 | lpfc_drop_node(vport, ndlp); | ||
566 | |||
567 | /* Turn off discovery timer if its running */ | 556 | /* Turn off discovery timer if its running */ |
568 | lpfc_can_disctmo(vport); | 557 | lpfc_can_disctmo(vport); |
569 | } | 558 | } |
@@ -670,7 +659,6 @@ static void | |||
670 | lpfc_linkup_port(struct lpfc_vport *vport) | 659 | lpfc_linkup_port(struct lpfc_vport *vport) |
671 | { | 660 | { |
672 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 661 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
673 | struct lpfc_nodelist *ndlp, *next_ndlp; | ||
674 | struct lpfc_hba *phba = vport->phba; | 662 | struct lpfc_hba *phba = vport->phba; |
675 | 663 | ||
676 | if ((vport->load_flag & FC_UNLOADING) != 0) | 664 | if ((vport->load_flag & FC_UNLOADING) != 0) |
@@ -697,11 +685,6 @@ lpfc_linkup_port(struct lpfc_vport *vport) | |||
697 | if (vport->fc_flag & FC_LBIT) | 685 | if (vport->fc_flag & FC_LBIT) |
698 | lpfc_linkup_cleanup_nodes(vport); | 686 | lpfc_linkup_cleanup_nodes(vport); |
699 | 687 | ||
700 | /* free any ndlp's in unused state */ | ||
701 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, | ||
702 | nlp_listp) | ||
703 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | ||
704 | lpfc_drop_node(vport, ndlp); | ||
705 | } | 688 | } |
706 | 689 | ||
707 | static int | 690 | static int |
@@ -1345,7 +1328,9 @@ out: | |||
1345 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 1328 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
1346 | kfree(mp); | 1329 | kfree(mp); |
1347 | mempool_free(pmb, phba->mbox_mem_pool); | 1330 | mempool_free(pmb, phba->mbox_mem_pool); |
1348 | lpfc_drop_node(vport, ndlp); | 1331 | |
1332 | /* If no other thread is using the ndlp, free it */ | ||
1333 | lpfc_nlp_not_used(ndlp); | ||
1349 | 1334 | ||
1350 | if (phba->fc_topology == TOPOLOGY_LOOP) { | 1335 | if (phba->fc_topology == TOPOLOGY_LOOP) { |
1351 | /* | 1336 | /* |
@@ -1605,16 +1590,6 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1605 | ndlp->nlp_type &= ~NLP_FC_NODE; | 1590 | ndlp->nlp_type &= ~NLP_FC_NODE; |
1606 | } | 1591 | } |
1607 | 1592 | ||
1608 | if ((old_state == NLP_STE_UNUSED_NODE) && | ||
1609 | (state != NLP_STE_UNUSED_NODE) && | ||
1610 | (ndlp->nlp_flag & NLP_DELAYED_RM)) { | ||
1611 | /* We are using the ndlp after all, so reverse | ||
1612 | * the delayed removal of it. | ||
1613 | */ | ||
1614 | ndlp->nlp_flag &= ~NLP_DELAYED_RM; | ||
1615 | lpfc_nlp_get(ndlp); | ||
1616 | } | ||
1617 | |||
1618 | if (list_empty(&ndlp->nlp_listp)) { | 1593 | if (list_empty(&ndlp->nlp_listp)) { |
1619 | spin_lock_irq(shost->host_lock); | 1594 | spin_lock_irq(shost->host_lock); |
1620 | list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); | 1595 | list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); |
@@ -1646,9 +1621,16 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1646 | void | 1621 | void |
1647 | lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | 1622 | lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) |
1648 | { | 1623 | { |
1624 | /* | ||
1625 | * Use of lpfc_drop_node and UNUSED list. lpfc_drop_node should | ||
1626 | * be used if we wish to issue the "last" lpfc_nlp_put() to remove | ||
1627 | * the ndlp from the vport. The ndlp resides on the UNUSED list | ||
1628 | * until ALL other outstanding threads have completed. Thus, if a | ||
1629 | * ndlp is on the UNUSED list already, we should never do another | ||
1630 | * lpfc_drop_node() on it. | ||
1631 | */ | ||
1649 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); | 1632 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); |
1650 | if (!(ndlp->nlp_flag & NLP_DELAYED_RM)) | 1633 | lpfc_nlp_put(ndlp); |
1651 | lpfc_nlp_put(ndlp); | ||
1652 | return; | 1634 | return; |
1653 | } | 1635 | } |
1654 | 1636 | ||
@@ -2116,6 +2098,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) | |||
2116 | } | 2098 | } |
2117 | if (vport->fc_flag & FC_RSCN_MODE) { | 2099 | if (vport->fc_flag & FC_RSCN_MODE) { |
2118 | if (lpfc_rscn_payload_check(vport, did)) { | 2100 | if (lpfc_rscn_payload_check(vport, did)) { |
2101 | /* If we've already recieved a PLOGI from this NPort | ||
2102 | * we don't need to try to discover it again. | ||
2103 | */ | ||
2104 | if (ndlp->nlp_flag & NLP_RCV_PLOGI) | ||
2105 | return NULL; | ||
2106 | |||
2119 | spin_lock_irq(shost->host_lock); | 2107 | spin_lock_irq(shost->host_lock); |
2120 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | 2108 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; |
2121 | spin_unlock_irq(shost->host_lock); | 2109 | spin_unlock_irq(shost->host_lock); |
@@ -2128,8 +2116,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) | |||
2128 | } else | 2116 | } else |
2129 | ndlp = NULL; | 2117 | ndlp = NULL; |
2130 | } else { | 2118 | } else { |
2119 | /* If we've already recieved a PLOGI from this NPort, | ||
2120 | * or we are already in the process of discovery on it, | ||
2121 | * we don't need to try to discover it again. | ||
2122 | */ | ||
2131 | if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE || | 2123 | if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE || |
2132 | ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) | 2124 | ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || |
2125 | ndlp->nlp_flag & NLP_RCV_PLOGI) | ||
2133 | return NULL; | 2126 | return NULL; |
2134 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | 2127 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); |
2135 | spin_lock_irq(shost->host_lock); | 2128 | spin_lock_irq(shost->host_lock); |
@@ -2497,6 +2490,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
2497 | if (ndlp->nlp_type & NLP_FABRIC) { | 2490 | if (ndlp->nlp_type & NLP_FABRIC) { |
2498 | /* Clean up the ndlp on Fabric connections */ | 2491 | /* Clean up the ndlp on Fabric connections */ |
2499 | lpfc_drop_node(vport, ndlp); | 2492 | lpfc_drop_node(vport, ndlp); |
2493 | |||
2500 | } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { | 2494 | } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { |
2501 | /* Fail outstanding IO now since device | 2495 | /* Fail outstanding IO now since device |
2502 | * is marked for PLOGI. | 2496 | * is marked for PLOGI. |
@@ -2515,7 +2509,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
2515 | /* Initial FLOGI timeout */ | 2509 | /* Initial FLOGI timeout */ |
2516 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, | 2510 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, |
2517 | "0222 Initial %s timeout\n", | 2511 | "0222 Initial %s timeout\n", |
2518 | vport->vpi ? "FLOGI" : "FDISC"); | 2512 | vport->vpi ? "FDISC" : "FLOGI"); |
2519 | 2513 | ||
2520 | /* Assume no Fabric and go on with discovery. | 2514 | /* Assume no Fabric and go on with discovery. |
2521 | * Check for outstanding ELS FLOGI to abort. | 2515 | * Check for outstanding ELS FLOGI to abort. |
@@ -2537,10 +2531,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
2537 | /* Next look for NameServer ndlp */ | 2531 | /* Next look for NameServer ndlp */ |
2538 | ndlp = lpfc_findnode_did(vport, NameServer_DID); | 2532 | ndlp = lpfc_findnode_did(vport, NameServer_DID); |
2539 | if (ndlp) | 2533 | if (ndlp) |
2540 | lpfc_nlp_put(ndlp); | 2534 | lpfc_els_abort(phba, ndlp); |
2541 | /* Start discovery */ | 2535 | |
2542 | lpfc_disc_start(vport); | 2536 | /* ReStart discovery */ |
2543 | break; | 2537 | goto restart_disc; |
2544 | 2538 | ||
2545 | case LPFC_NS_QRY: | 2539 | case LPFC_NS_QRY: |
2546 | /* Check for wait for NameServer Rsp timeout */ | 2540 | /* Check for wait for NameServer Rsp timeout */ |
@@ -2559,6 +2553,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
2559 | } | 2553 | } |
2560 | vport->fc_ns_retry = 0; | 2554 | vport->fc_ns_retry = 0; |
2561 | 2555 | ||
2556 | restart_disc: | ||
2562 | /* | 2557 | /* |
2563 | * Discovery is over. | 2558 | * Discovery is over. |
2564 | * set port_state to PORT_READY if SLI2. | 2559 | * set port_state to PORT_READY if SLI2. |
@@ -2731,8 +2726,7 @@ __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) | |||
2731 | struct lpfc_nodelist *ndlp; | 2726 | struct lpfc_nodelist *ndlp; |
2732 | 2727 | ||
2733 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { | 2728 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { |
2734 | if (ndlp->nlp_state != NLP_STE_UNUSED_NODE && | 2729 | if (filter(ndlp, param)) |
2735 | filter(ndlp, param)) | ||
2736 | return ndlp; | 2730 | return ndlp; |
2737 | } | 2731 | } |
2738 | return NULL; | 2732 | return NULL; |