Commit 87af33fe authored by James Smart's avatar James Smart Committed by James Bottomley

[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: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 98c9ea5c
...@@ -45,6 +45,7 @@ void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); ...@@ -45,6 +45,7 @@ void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove); void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove);
int lpfc_linkdown(struct lpfc_hba *); int lpfc_linkdown(struct lpfc_hba *);
void lpfc_port_link_failure(struct lpfc_vport *);
void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
...@@ -74,6 +75,7 @@ void lpfc_disc_list_loopmap(struct lpfc_vport *); ...@@ -74,6 +75,7 @@ void lpfc_disc_list_loopmap(struct lpfc_vport *);
void lpfc_disc_start(struct lpfc_vport *); void lpfc_disc_start(struct lpfc_vport *);
void lpfc_disc_flush_list(struct lpfc_vport *); void lpfc_disc_flush_list(struct lpfc_vport *);
void lpfc_cleanup_discovery_resources(struct lpfc_vport *); void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
void lpfc_cleanup(struct lpfc_vport *);
void lpfc_disc_timeout(unsigned long); void lpfc_disc_timeout(unsigned long);
struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
...@@ -91,6 +93,8 @@ void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); ...@@ -91,6 +93,8 @@ void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
struct serv_parm *, uint32_t); struct serv_parm *, uint32_t);
int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
void lpfc_more_plogi(struct lpfc_vport *);
void lpfc_end_rscn(struct lpfc_vport *);
int lpfc_els_chk_latt(struct lpfc_vport *); int lpfc_els_chk_latt(struct lpfc_vport *);
int lpfc_els_abort_flogi(struct lpfc_hba *); int lpfc_els_abort_flogi(struct lpfc_hba *);
int lpfc_initial_flogi(struct lpfc_vport *); int lpfc_initial_flogi(struct lpfc_vport *);
......
...@@ -103,7 +103,6 @@ struct lpfc_nodelist { ...@@ -103,7 +103,6 @@ struct lpfc_nodelist {
#define NLP_RM_DFLT_RPI 0x4000000 /* need to remove leftover dflt RPI */ #define NLP_RM_DFLT_RPI 0x4000000 /* need to remove leftover dflt RPI */
#define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */ #define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */
#define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */ #define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */
#define NLP_DELAYED_RM 0x20000000 /* Defer UNUSED List removal */
/* There are 4 different double linked lists nodelist entries can reside on. /* There are 4 different double linked lists nodelist entries can reside on.
* The Port Login (PLOGI) list and Address Discovery (ADISC) list are used * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used
......
This diff is collapsed.
...@@ -157,6 +157,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) ...@@ -157,6 +157,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
struct lpfc_vport *vport; struct lpfc_vport *vport;
struct lpfc_hba *phba; struct lpfc_hba *phba;
uint8_t *name; uint8_t *name;
int put_node;
int put_rport;
int warn_on = 0; int warn_on = 0;
rport = ndlp->rport; rport = ndlp->rport;
...@@ -178,9 +180,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) ...@@ -178,9 +180,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
return; return;
if (ndlp->nlp_type & NLP_FABRIC) { if (ndlp->nlp_type & NLP_FABRIC) {
int put_node;
int put_rport;
/* We will clean up these Nodes in linkup */ /* We will clean up these Nodes in linkup */
put_node = rdata->pnode != NULL; put_node = rdata->pnode != NULL;
put_rport = ndlp->rport != NULL; put_rport = ndlp->rport != NULL;
...@@ -222,15 +221,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) ...@@ -222,15 +221,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
ndlp->nlp_state, ndlp->nlp_rpi); ndlp->nlp_state, ndlp->nlp_rpi);
} }
if (!(vport->load_flag & FC_UNLOADING) &&
!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
!(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
(ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
else {
int put_node;
int put_rport;
put_node = rdata->pnode != NULL; put_node = rdata->pnode != NULL;
put_rport = ndlp->rport != NULL; put_rport = ndlp->rport != NULL;
rdata->pnode = NULL; rdata->pnode = NULL;
...@@ -239,6 +229,12 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) ...@@ -239,6 +229,12 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
lpfc_nlp_put(ndlp); lpfc_nlp_put(ndlp);
if (put_rport) if (put_rport)
put_device(&rport->dev); put_device(&rport->dev);
if (!(vport->load_flag & FC_UNLOADING) &&
!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
!(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
(ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) {
lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
} }
} }
...@@ -546,11 +542,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) ...@@ -546,11 +542,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
} }
} }
static void void
lpfc_port_link_failure(struct lpfc_vport *vport) lpfc_port_link_failure(struct lpfc_vport *vport)
{ {
struct lpfc_nodelist *ndlp, *next_ndlp;
/* Cleanup any outstanding RSCN activity */ /* Cleanup any outstanding RSCN activity */
lpfc_els_flush_rscn(vport); lpfc_els_flush_rscn(vport);
...@@ -559,11 +553,6 @@ lpfc_port_link_failure(struct lpfc_vport *vport) ...@@ -559,11 +553,6 @@ lpfc_port_link_failure(struct lpfc_vport *vport)
lpfc_cleanup_rpis(vport, 0); lpfc_cleanup_rpis(vport, 0);
/* free any ndlp's on unused list */
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
lpfc_drop_node(vport, ndlp);
/* Turn off discovery timer if its running */ /* Turn off discovery timer if its running */
lpfc_can_disctmo(vport); lpfc_can_disctmo(vport);
} }
...@@ -670,7 +659,6 @@ static void ...@@ -670,7 +659,6 @@ static void
lpfc_linkup_port(struct lpfc_vport *vport) lpfc_linkup_port(struct lpfc_vport *vport)
{ {
struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp, *next_ndlp;
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
if ((vport->load_flag & FC_UNLOADING) != 0) if ((vport->load_flag & FC_UNLOADING) != 0)
...@@ -697,11 +685,6 @@ lpfc_linkup_port(struct lpfc_vport *vport) ...@@ -697,11 +685,6 @@ lpfc_linkup_port(struct lpfc_vport *vport)
if (vport->fc_flag & FC_LBIT) if (vport->fc_flag & FC_LBIT)
lpfc_linkup_cleanup_nodes(vport); lpfc_linkup_cleanup_nodes(vport);
/* free any ndlp's in unused state */
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
nlp_listp)
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
lpfc_drop_node(vport, ndlp);
} }
static int static int
...@@ -1345,7 +1328,9 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ...@@ -1345,7 +1328,9 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
lpfc_mbuf_free(phba, mp->virt, mp->phys); lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp); kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool); mempool_free(pmb, phba->mbox_mem_pool);
lpfc_drop_node(vport, ndlp);
/* If no other thread is using the ndlp, free it */
lpfc_nlp_not_used(ndlp);
if (phba->fc_topology == TOPOLOGY_LOOP) { if (phba->fc_topology == TOPOLOGY_LOOP) {
/* /*
...@@ -1605,16 +1590,6 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1605,16 +1590,6 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_type &= ~NLP_FC_NODE; ndlp->nlp_type &= ~NLP_FC_NODE;
} }
if ((old_state == NLP_STE_UNUSED_NODE) &&
(state != NLP_STE_UNUSED_NODE) &&
(ndlp->nlp_flag & NLP_DELAYED_RM)) {
/* We are using the ndlp after all, so reverse
* the delayed removal of it.
*/
ndlp->nlp_flag &= ~NLP_DELAYED_RM;
lpfc_nlp_get(ndlp);
}
if (list_empty(&ndlp->nlp_listp)) { if (list_empty(&ndlp->nlp_listp)) {
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes);
...@@ -1646,8 +1621,15 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ...@@ -1646,8 +1621,15 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
void void
lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{ {
/*
* Use of lpfc_drop_node and UNUSED list. lpfc_drop_node should
* be used if we wish to issue the "last" lpfc_nlp_put() to remove
* the ndlp from the vport. The ndlp resides on the UNUSED list
* until ALL other outstanding threads have completed. Thus, if a
* ndlp is on the UNUSED list already, we should never do another
* lpfc_drop_node() on it.
*/
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
if (!(ndlp->nlp_flag & NLP_DELAYED_RM))
lpfc_nlp_put(ndlp); lpfc_nlp_put(ndlp);
return; return;
} }
...@@ -2116,6 +2098,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) ...@@ -2116,6 +2098,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
} }
if (vport->fc_flag & FC_RSCN_MODE) { if (vport->fc_flag & FC_RSCN_MODE) {
if (lpfc_rscn_payload_check(vport, did)) { if (lpfc_rscn_payload_check(vport, did)) {
/* If we've already recieved a PLOGI from this NPort
* we don't need to try to discover it again.
*/
if (ndlp->nlp_flag & NLP_RCV_PLOGI)
return NULL;
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC; ndlp->nlp_flag |= NLP_NPR_2B_DISC;
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
...@@ -2128,8 +2116,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) ...@@ -2128,8 +2116,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
} else } else
ndlp = NULL; ndlp = NULL;
} else { } else {
/* If we've already recieved a PLOGI from this NPort,
* or we are already in the process of discovery on it,
* we don't need to try to discover it again.
*/
if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE || if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
ndlp->nlp_flag & NLP_RCV_PLOGI)
return NULL; return NULL;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
...@@ -2497,6 +2490,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) ...@@ -2497,6 +2490,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
if (ndlp->nlp_type & NLP_FABRIC) { if (ndlp->nlp_type & NLP_FABRIC) {
/* Clean up the ndlp on Fabric connections */ /* Clean up the ndlp on Fabric connections */
lpfc_drop_node(vport, ndlp); lpfc_drop_node(vport, ndlp);
} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
/* Fail outstanding IO now since device /* Fail outstanding IO now since device
* is marked for PLOGI. * is marked for PLOGI.
...@@ -2515,7 +2509,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) ...@@ -2515,7 +2509,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
/* Initial FLOGI timeout */ /* Initial FLOGI timeout */
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
"0222 Initial %s timeout\n", "0222 Initial %s timeout\n",
vport->vpi ? "FLOGI" : "FDISC"); vport->vpi ? "FDISC" : "FLOGI");
/* Assume no Fabric and go on with discovery. /* Assume no Fabric and go on with discovery.
* Check for outstanding ELS FLOGI to abort. * Check for outstanding ELS FLOGI to abort.
...@@ -2537,10 +2531,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) ...@@ -2537,10 +2531,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
/* Next look for NameServer ndlp */ /* Next look for NameServer ndlp */
ndlp = lpfc_findnode_did(vport, NameServer_DID); ndlp = lpfc_findnode_did(vport, NameServer_DID);
if (ndlp) if (ndlp)
lpfc_nlp_put(ndlp); lpfc_els_abort(phba, ndlp);
/* Start discovery */
lpfc_disc_start(vport); /* ReStart discovery */
break; goto restart_disc;
case LPFC_NS_QRY: case LPFC_NS_QRY:
/* Check for wait for NameServer Rsp timeout */ /* Check for wait for NameServer Rsp timeout */
...@@ -2559,6 +2553,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) ...@@ -2559,6 +2553,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
} }
vport->fc_ns_retry = 0; vport->fc_ns_retry = 0;
restart_disc:
/* /*
* Discovery is over. * Discovery is over.
* set port_state to PORT_READY if SLI2. * 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,8 +2726,7 @@ __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
struct lpfc_nodelist *ndlp; struct lpfc_nodelist *ndlp;
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state != NLP_STE_UNUSED_NODE && if (filter(ndlp, param))
filter(ndlp, param))
return ndlp; return ndlp;
} }
return NULL; return NULL;
......
...@@ -1334,15 +1334,35 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit) ...@@ -1334,15 +1334,35 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
kfree(HashWorking); kfree(HashWorking);
} }
static void void
lpfc_cleanup(struct lpfc_vport *vport) lpfc_cleanup(struct lpfc_vport *vport)
{ {
struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp, *next_ndlp; struct lpfc_nodelist *ndlp, *next_ndlp;
/* clean up phba - lpfc specific */ if (phba->link_state > LPFC_LINK_DOWN)
lpfc_can_disctmo(vport); lpfc_port_link_failure(vport);
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
lpfc_nlp_put(ndlp); list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_type & NLP_FABRIC)
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY);
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RM);
}
/* At this point, ALL ndlp's should be gone */
while (!list_empty(&vport->fc_nodes)) {
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
nlp_listp) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
"0233 Nodelist x%x not free: %d\n",
ndlp->nlp_DID,
atomic_read(&ndlp->kref.refcount));
lpfc_drop_node(vport, ndlp);
}
}
return; return;
} }
...@@ -1463,6 +1483,8 @@ lpfc_offline_prep(struct lpfc_hba * phba) ...@@ -1463,6 +1483,8 @@ lpfc_offline_prep(struct lpfc_hba * phba)
{ {
struct lpfc_vport *vport = phba->pport; struct lpfc_vport *vport = phba->pport;
struct lpfc_nodelist *ndlp, *next_ndlp; struct lpfc_nodelist *ndlp, *next_ndlp;
struct lpfc_vport **vports;
int i;
if (vport->fc_flag & FC_OFFLINE_MODE) if (vport->fc_flag & FC_OFFLINE_MODE)
return; return;
...@@ -1471,10 +1493,32 @@ lpfc_offline_prep(struct lpfc_hba * phba) ...@@ -1471,10 +1493,32 @@ lpfc_offline_prep(struct lpfc_hba * phba)
lpfc_linkdown(phba); lpfc_linkdown(phba);
/* Issue an unreg_login to all nodes */ /* Issue an unreg_login to all nodes on all vports */
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) vports = lpfc_create_vport_work_array(phba);
if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) if (vports != NULL) {
lpfc_unreg_rpi(vport, ndlp); for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
struct Scsi_Host *shost;
shost = lpfc_shost_from_vport(vports[i]);
list_for_each_entry_safe(ndlp, next_ndlp,
&vports[i]->fc_nodes,
nlp_listp) {
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
continue;
if (ndlp->nlp_type & NLP_FABRIC) {
lpfc_disc_state_machine(vports[i], ndlp,
NULL, NLP_EVT_DEVICE_RECOVERY);
lpfc_disc_state_machine(vports[i], ndlp,
NULL, NLP_EVT_DEVICE_RM);
}
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
spin_unlock_irq(shost->host_lock);
lpfc_unreg_rpi(vports[i], ndlp);
}
}
}
lpfc_destroy_vport_work_array(vports);
lpfc_sli_flush_mbox_queue(phba); lpfc_sli_flush_mbox_queue(phba);
} }
...@@ -1508,7 +1552,6 @@ lpfc_offline(struct lpfc_hba *phba) ...@@ -1508,7 +1552,6 @@ lpfc_offline(struct lpfc_hba *phba)
if (vports != NULL) if (vports != NULL)
for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
shost = lpfc_shost_from_vport(vports[i]); shost = lpfc_shost_from_vport(vports[i]);
lpfc_cleanup(vports[i]);
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
vports[i]->work_port_events = 0; vports[i]->work_port_events = 0;
vports[i]->fc_flag |= FC_OFFLINE_MODE; vports[i]->fc_flag |= FC_OFFLINE_MODE;
...@@ -2061,6 +2104,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev) ...@@ -2061,6 +2104,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
fc_remove_host(shost); fc_remove_host(shost);
scsi_remove_host(shost); scsi_remove_host(shost);
lpfc_cleanup(vport);
/* /*
* Bring down the SLI Layer. This step disable all interrupts, * Bring down the SLI Layer. This step disable all interrupts,
* clears the rings, discards all mailbox commands, and resets * clears the rings, discards all mailbox commands, and resets
...@@ -2075,7 +2120,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev) ...@@ -2075,7 +2120,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
spin_unlock_irq(&phba->hbalock); spin_unlock_irq(&phba->hbalock);
lpfc_debugfs_terminate(vport); lpfc_debugfs_terminate(vport);
lpfc_cleanup(vport);
kthread_stop(phba->worker_thread); kthread_stop(phba->worker_thread);
......
...@@ -406,6 +406,41 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -406,6 +406,41 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp, mbox); ndlp, mbox);
return 1; return 1;
} }
/* If the remote NPort logs into us, before we can initiate
* discovery to them, cleanup the NPort from discovery accordingly.
*/
if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_DELAY_TMO;
spin_unlock_irq(shost->host_lock);
del_timer_sync(&ndlp->nlp_delayfunc);
ndlp->nlp_last_elscmd = 0;
if (!list_empty(&ndlp->els_retry_evt.evt_listp))
list_del_init(&ndlp->els_retry_evt.evt_listp);
if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
spin_unlock_irq(shost->host_lock);
if (vport->num_disc_nodes) {
/* Check to see if there are more
* PLOGIs to be sent
*/
lpfc_more_plogi(vport);
if (vport->num_disc_nodes == 0) {
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~FC_NDISC_ACTIVE;
spin_unlock_irq(shost->host_lock);
lpfc_can_disctmo(vport);
lpfc_end_rscn(vport);
}
}
}
}
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
return 1; return 1;
...@@ -500,12 +535,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -500,12 +535,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
}
ndlp->nlp_prev_state = ndlp->nlp_state; ndlp->nlp_prev_state = ndlp->nlp_state;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
} else {
ndlp->nlp_prev_state = ndlp->nlp_state;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
}
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC; ndlp->nlp_flag &= ~NLP_NPR_ADISC;
...@@ -593,6 +625,25 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -593,6 +625,25 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
return ndlp->nlp_state; return ndlp->nlp_state;
} }
static uint32_t
lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
void *arg, uint32_t evt)
{
/* This transition is only legal if we previously
* rcv'ed a PLOGI. Since we don't want 2 discovery threads
* working on the same NPortID, do nothing for this thread
* to stop it.
*/
if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
"0253 Illegal State Transition: node x%x "
"event x%x, state x%x Data: x%x x%x\n",
ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
ndlp->nlp_flag);
}
return ndlp->nlp_state;
}
/* Start of Discovery State Machine routines */ /* Start of Discovery State Machine routines */
static uint32_t static uint32_t
...@@ -604,11 +655,8 @@ lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -604,11 +655,8 @@ lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
cmdiocb = (struct lpfc_iocbq *) arg; cmdiocb = (struct lpfc_iocbq *) arg;
if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state; return ndlp->nlp_state;
} }
lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE; return NLP_STE_FREED_NODE;
} }
...@@ -617,7 +665,6 @@ lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -617,7 +665,6 @@ lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
void *arg, uint32_t evt) void *arg, uint32_t evt)
{ {
lpfc_issue_els_logo(vport, ndlp, 0); lpfc_issue_els_logo(vport, ndlp, 0);
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state; return ndlp->nlp_state;
} }
...@@ -632,7 +679,6 @@ lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -632,7 +679,6 @@ lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_flag |= NLP_LOGO_ACC; ndlp->nlp_flag |= NLP_LOGO_ACC;
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state; return ndlp->nlp_state;
} }
...@@ -641,7 +687,6 @@ static uint32_t ...@@ -641,7 +687,6 @@ static uint32_t
lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
void *arg, uint32_t evt) void *arg, uint32_t evt)
{ {
lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE; return NLP_STE_FREED_NODE;
} }
...@@ -649,7 +694,6 @@ static uint32_t ...@@ -649,7 +694,6 @@ static uint32_t
lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
void *arg, uint32_t evt) void *arg, uint32_t evt)
{ {
lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE; return NLP_STE_FREED_NODE;
} }
...@@ -864,7 +908,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ...@@ -864,7 +908,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
/* Free this node since the driver cannot login or has the wrong /* Free this node since the driver cannot login or has the wrong
sparm */ sparm */
lpfc_drop_node(vport, ndlp); lpfc_nlp_not_used(ndlp);
return NLP_STE_FREED_NODE; return NLP_STE_FREED_NODE;
} }
...@@ -1195,8 +1239,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, ...@@ -1195,8 +1239,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
* retry discovery. * retry discovery.
*/ */
if (mb->mbxStatus == MBXERR_RPI_FULL) { if (mb->mbxStatus == MBXERR_RPI_FULL) {
ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
return ndlp->nlp_state; return ndlp->nlp_state;
} }
...@@ -1376,7 +1420,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1376,7 +1420,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_issue_els_logo(vport, ndlp, 0); lpfc_issue_els_logo(vport, ndlp, 0);
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
return ndlp->nlp_state; return ndlp->nlp_state;
} }
...@@ -1751,7 +1795,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -1751,7 +1795,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
irsp = &rspiocb->iocb; irsp = &rspiocb->iocb;
if (irsp->ulpStatus) { if (irsp->ulpStatus) {
lpfc_drop_node(vport, ndlp); lpfc_nlp_not_used(ndlp);
return NLP_STE_FREED_NODE; return NLP_STE_FREED_NODE;
} }
return ndlp->nlp_state; return ndlp->nlp_state;
...@@ -1966,7 +2010,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) ...@@ -1966,7 +2010,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
lpfc_rcv_padisc_reglogin_issue, /* RCV_ADISC */ lpfc_rcv_padisc_reglogin_issue, /* RCV_ADISC */
lpfc_rcv_padisc_reglogin_issue, /* RCV_PDISC */ lpfc_rcv_padisc_reglogin_issue, /* RCV_PDISC */
lpfc_rcv_prlo_reglogin_issue, /* RCV_PRLO */ lpfc_rcv_prlo_reglogin_issue, /* RCV_PRLO */
lpfc_disc_illegal, /* CMPL_PLOGI */ lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */
lpfc_disc_illegal, /* CMPL_PRLI */ lpfc_disc_illegal, /* CMPL_PRLI */
lpfc_disc_illegal, /* CMPL_LOGO */ lpfc_disc_illegal, /* CMPL_LOGO */
lpfc_disc_illegal, /* CMPL_ADISC */ lpfc_disc_illegal, /* CMPL_ADISC */
...@@ -1980,7 +2024,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) ...@@ -1980,7 +2024,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
lpfc_rcv_padisc_prli_issue, /* RCV_ADISC */ lpfc_rcv_padisc_prli_issue, /* RCV_ADISC */
lpfc_rcv_padisc_prli_issue, /* RCV_PDISC */ lpfc_rcv_padisc_prli_issue, /* RCV_PDISC */
lpfc_rcv_prlo_prli_issue, /* RCV_PRLO */ lpfc_rcv_prlo_prli_issue, /* RCV_PRLO */
lpfc_disc_illegal, /* CMPL_PLOGI */ lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */
lpfc_cmpl_prli_prli_issue, /* CMPL_PRLI */ lpfc_cmpl_prli_prli_issue, /* CMPL_PRLI */
lpfc_disc_illegal, /* CMPL_LOGO */ lpfc_disc_illegal, /* CMPL_LOGO */
lpfc_disc_illegal, /* CMPL_ADISC */ lpfc_disc_illegal, /* CMPL_ADISC */
......
...@@ -445,7 +445,6 @@ int ...@@ -445,7 +445,6 @@ int
lpfc_vport_delete(struct fc_vport *fc_vport) lpfc_vport_delete(struct fc_vport *fc_vport)
{ {
struct lpfc_nodelist *ndlp = NULL; struct lpfc_nodelist *ndlp = NULL;
struct lpfc_nodelist *next_ndlp;
struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost; struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost;
struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
...@@ -531,23 +530,20 @@ lpfc_vport_delete(struct fc_vport *fc_vport) ...@@ -531,23 +530,20 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
} }
skip_logo: skip_logo:
lpfc_cleanup(vport);
lpfc_sli_host_down(vport); lpfc_sli_host_down(vport);
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY);
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RM);
}
lpfc_stop_vport_timers(vport); lpfc_stop_vport_timers(vport);
lpfc_unreg_all_rpis(vport); lpfc_unreg_all_rpis(vport);
if (!(phba->pport->load_flag & FC_UNLOADING)) {
lpfc_unreg_default_rpis(vport); lpfc_unreg_default_rpis(vport);
/* /*
* Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi)
* scsi_host_put() to release the vport. * does the scsi_host_put() to release the vport.
*/ */
lpfc_mbx_unreg_vpi(vport); lpfc_mbx_unreg_vpi(vport);
}
lpfc_free_vpi(phba, vport->vpi); lpfc_free_vpi(phba, vport->vpi);
vport->work_port_events = 0; vport->work_port_events = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment