aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_hbadisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c123
1 files changed, 77 insertions, 46 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 6f5bf8189950..e181a98caf16 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -107,7 +107,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
107 struct lpfc_nodelist * ndlp; 107 struct lpfc_nodelist * ndlp;
108 struct lpfc_vport *vport; 108 struct lpfc_vport *vport;
109 struct lpfc_hba *phba; 109 struct lpfc_hba *phba;
110 struct completion devloss_compl;
111 struct lpfc_work_evt *evtp; 110 struct lpfc_work_evt *evtp;
112 111
113 rdata = rport->dd_data; 112 rdata = rport->dd_data;
@@ -129,7 +128,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
129 "rport devlosscb: sid:x%x did:x%x flg:x%x", 128 "rport devlosscb: sid:x%x did:x%x flg:x%x",
130 ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); 129 ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
131 130
132 init_completion(&devloss_compl);
133 evtp = &ndlp->dev_loss_evt; 131 evtp = &ndlp->dev_loss_evt;
134 132
135 if (!list_empty(&evtp->evt_listp)) 133 if (!list_empty(&evtp->evt_listp))
@@ -137,7 +135,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
137 135
138 spin_lock_irq(&phba->hbalock); 136 spin_lock_irq(&phba->hbalock);
139 evtp->evt_arg1 = ndlp; 137 evtp->evt_arg1 = ndlp;
140 evtp->evt_arg2 = &devloss_compl;
141 evtp->evt = LPFC_EVT_DEV_LOSS; 138 evtp->evt = LPFC_EVT_DEV_LOSS;
142 list_add_tail(&evtp->evt_listp, &phba->work_list); 139 list_add_tail(&evtp->evt_listp, &phba->work_list);
143 if (phba->work_wait) 140 if (phba->work_wait)
@@ -145,8 +142,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
145 142
146 spin_unlock_irq(&phba->hbalock); 143 spin_unlock_irq(&phba->hbalock);
147 144
148 wait_for_completion(&devloss_compl);
149
150 return; 145 return;
151} 146}
152 147
@@ -260,7 +255,6 @@ lpfc_work_list_done(struct lpfc_hba *phba)
260{ 255{
261 struct lpfc_work_evt *evtp = NULL; 256 struct lpfc_work_evt *evtp = NULL;
262 struct lpfc_nodelist *ndlp; 257 struct lpfc_nodelist *ndlp;
263 struct lpfc_vport *vport;
264 int free_evt; 258 int free_evt;
265 259
266 spin_lock_irq(&phba->hbalock); 260 spin_lock_irq(&phba->hbalock);
@@ -270,24 +264,6 @@ lpfc_work_list_done(struct lpfc_hba *phba)
270 spin_unlock_irq(&phba->hbalock); 264 spin_unlock_irq(&phba->hbalock);
271 free_evt = 1; 265 free_evt = 1;
272 switch (evtp->evt) { 266 switch (evtp->evt) {
273 case LPFC_EVT_DEV_LOSS_DELAY:
274 free_evt = 0; /* evt is part of ndlp */
275 ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
276 vport = ndlp->vport;
277 if (!vport)
278 break;
279
280 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
281 "rport devlossdly:did:x%x flg:x%x",
282 ndlp->nlp_DID, ndlp->nlp_flag, 0);
283
284 if (!(vport->load_flag & FC_UNLOADING) &&
285 !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
286 !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
287 lpfc_disc_state_machine(vport, ndlp, NULL,
288 NLP_EVT_DEVICE_RM);
289 }
290 break;
291 case LPFC_EVT_ELS_RETRY: 267 case LPFC_EVT_ELS_RETRY:
292 ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); 268 ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
293 lpfc_els_retry_delay_handler(ndlp); 269 lpfc_els_retry_delay_handler(ndlp);
@@ -298,7 +274,6 @@ lpfc_work_list_done(struct lpfc_hba *phba)
298 lpfc_nlp_get(ndlp); 274 lpfc_nlp_get(ndlp);
299 lpfc_dev_loss_tmo_handler(ndlp); 275 lpfc_dev_loss_tmo_handler(ndlp);
300 free_evt = 0; 276 free_evt = 0;
301 complete((struct completion *)(evtp->evt_arg2));
302 lpfc_nlp_put(ndlp); 277 lpfc_nlp_put(ndlp);
303 break; 278 break;
304 case LPFC_EVT_ONLINE: 279 case LPFC_EVT_ONLINE:
@@ -552,7 +527,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
552 if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) 527 if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
553 continue; 528 continue;
554 529
555 if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) 530 if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) ||
531 ((vport->port_type == LPFC_NPIV_PORT) &&
532 (ndlp->nlp_DID == NameServer_DID)))
556 lpfc_unreg_rpi(vport, ndlp); 533 lpfc_unreg_rpi(vport, ndlp);
557 534
558 /* Leave Fabric nodes alone on link down */ 535 /* Leave Fabric nodes alone on link down */
@@ -570,16 +547,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
570} 547}
571 548
572static void 549static void
573lpfc_linkdown_port(struct lpfc_vport *vport) 550lpfc_port_link_failure(struct lpfc_vport *vport)
574{ 551{
575 struct lpfc_nodelist *ndlp, *next_ndlp; 552 struct lpfc_nodelist *ndlp, *next_ndlp;
576 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
577
578 fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0);
579
580 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
581 "Link Down: state:x%x rtry:x%x flg:x%x",
582 vport->port_state, vport->fc_ns_retry, vport->fc_flag);
583 553
584 /* Cleanup any outstanding RSCN activity */ 554 /* Cleanup any outstanding RSCN activity */
585 lpfc_els_flush_rscn(vport); 555 lpfc_els_flush_rscn(vport);
@@ -598,6 +568,21 @@ lpfc_linkdown_port(struct lpfc_vport *vport)
598 lpfc_can_disctmo(vport); 568 lpfc_can_disctmo(vport);
599} 569}
600 570
571static void
572lpfc_linkdown_port(struct lpfc_vport *vport)
573{
574 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
575
576 fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0);
577
578 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
579 "Link Down: state:x%x rtry:x%x flg:x%x",
580 vport->port_state, vport->fc_ns_retry, vport->fc_flag);
581
582 lpfc_port_link_failure(vport);
583
584}
585
601int 586int
602lpfc_linkdown(struct lpfc_hba *phba) 587lpfc_linkdown(struct lpfc_hba *phba)
603{ 588{
@@ -851,8 +836,6 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
851 * LPFC_FLOGI while waiting for FLOGI cmpl 836 * LPFC_FLOGI while waiting for FLOGI cmpl
852 */ 837 */
853 if (vport->port_state != LPFC_FLOGI) { 838 if (vport->port_state != LPFC_FLOGI) {
854 vport->port_state = LPFC_FLOGI;
855 lpfc_set_disctmo(vport);
856 lpfc_initial_flogi(vport); 839 lpfc_initial_flogi(vport);
857 } 840 }
858 return; 841 return;
@@ -1622,6 +1605,16 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1622 ndlp->nlp_type &= ~NLP_FC_NODE; 1605 ndlp->nlp_type &= ~NLP_FC_NODE;
1623 } 1606 }
1624 1607
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
1625 if (list_empty(&ndlp->nlp_listp)) { 1618 if (list_empty(&ndlp->nlp_listp)) {
1626 spin_lock_irq(shost->host_lock); 1619 spin_lock_irq(shost->host_lock);
1627 list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); 1620 list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes);
@@ -1654,7 +1647,9 @@ void
1654lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) 1647lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
1655{ 1648{
1656 lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); 1649 lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
1657 lpfc_nlp_put(ndlp); 1650 if (!(ndlp->nlp_flag & NLP_DELAYED_RM))
1651 lpfc_nlp_put(ndlp);
1652 return;
1658} 1653}
1659 1654
1660/* 1655/*
@@ -1975,11 +1970,6 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
1975 if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) 1970 if (!list_empty(&ndlp->dev_loss_evt.evt_listp))
1976 list_del_init(&ndlp->dev_loss_evt.evt_listp); 1971 list_del_init(&ndlp->dev_loss_evt.evt_listp);
1977 1972
1978 if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) {
1979 list_del_init(&ndlp->dev_loss_evt.evt_listp);
1980 complete((struct completion *)(ndlp->dev_loss_evt.evt_arg2));
1981 }
1982
1983 lpfc_unreg_rpi(vport, ndlp); 1973 lpfc_unreg_rpi(vport, ndlp);
1984 1974
1985 return 0; 1975 return 0;
@@ -2418,7 +2408,6 @@ lpfc_disc_flush_list(struct lpfc_vport *vport)
2418 if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || 2408 if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
2419 ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { 2409 ndlp->nlp_state == NLP_STE_ADISC_ISSUE) {
2420 lpfc_free_tx(phba, ndlp); 2410 lpfc_free_tx(phba, ndlp);
2421 lpfc_nlp_put(ndlp);
2422 } 2411 }
2423 } 2412 }
2424 } 2413 }
@@ -2516,8 +2505,6 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
2516 } 2505 }
2517 } 2506 }
2518 if (vport->port_state != LPFC_FLOGI) { 2507 if (vport->port_state != LPFC_FLOGI) {
2519 vport->port_state = LPFC_FLOGI;
2520 lpfc_set_disctmo(vport);
2521 lpfc_initial_flogi(vport); 2508 lpfc_initial_flogi(vport);
2522 } 2509 }
2523 break; 2510 break;
@@ -2828,6 +2815,9 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
2828 return; 2815 return;
2829} 2816}
2830 2817
2818/* This routine releases all resources associated with a specifc NPort's ndlp
2819 * and mempool_free's the nodelist.
2820 */
2831static void 2821static void
2832lpfc_nlp_release(struct kref *kref) 2822lpfc_nlp_release(struct kref *kref)
2833{ 2823{
@@ -2842,16 +2832,57 @@ lpfc_nlp_release(struct kref *kref)
2842 mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); 2832 mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool);
2843} 2833}
2844 2834
2835/* This routine bumps the reference count for a ndlp structure to ensure
2836 * that one discovery thread won't free a ndlp while another discovery thread
2837 * is using it.
2838 */
2845struct lpfc_nodelist * 2839struct lpfc_nodelist *
2846lpfc_nlp_get(struct lpfc_nodelist *ndlp) 2840lpfc_nlp_get(struct lpfc_nodelist *ndlp)
2847{ 2841{
2848 if (ndlp) 2842 if (ndlp) {
2843 lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
2844 "node get: did:x%x flg:x%x refcnt:x%x",
2845 ndlp->nlp_DID, ndlp->nlp_flag,
2846 atomic_read(&ndlp->kref.refcount));
2849 kref_get(&ndlp->kref); 2847 kref_get(&ndlp->kref);
2848 }
2850 return ndlp; 2849 return ndlp;
2851} 2850}
2852 2851
2852
2853/* This routine decrements the reference count for a ndlp structure. If the
2854 * count goes to 0, this indicates the the associated nodelist should be freed.
2855 */
2853int 2856int
2854lpfc_nlp_put(struct lpfc_nodelist *ndlp) 2857lpfc_nlp_put(struct lpfc_nodelist *ndlp)
2855{ 2858{
2859 if (ndlp) {
2860 lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
2861 "node put: did:x%x flg:x%x refcnt:x%x",
2862 ndlp->nlp_DID, ndlp->nlp_flag,
2863 atomic_read(&ndlp->kref.refcount));
2864 }
2856 return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0; 2865 return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0;
2857} 2866}
2867
2868/* This routine free's the specified nodelist if it is not in use
2869 * by any other discovery thread. This routine returns 1 if the ndlp
2870 * is not being used by anyone and has been freed. A return value of
2871 * 0 indicates it is being used by another discovery thread and the
2872 * refcount is left unchanged.
2873 */
2874int
2875lpfc_nlp_not_used(struct lpfc_nodelist *ndlp)
2876{
2877 lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
2878 "node not used: did:x%x flg:x%x refcnt:x%x",
2879 ndlp->nlp_DID, ndlp->nlp_flag,
2880 atomic_read(&ndlp->kref.refcount));
2881
2882 if (atomic_read(&ndlp->kref.refcount) == 1) {
2883 lpfc_nlp_put(ndlp);
2884 return 1;
2885 }
2886 return 0;
2887}
2888