diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 328 |
1 files changed, 269 insertions, 59 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index dc042bd97baa..bd572d6b60af 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2004-2007 Emulex. All rights reserved. * | 4 | * Copyright (C) 2004-2008 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * | 7 | * Portions Copyright (C) 2004-2005 Christoph Hellwig * |
@@ -272,9 +272,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) | |||
272 | if (!(vport->load_flag & FC_UNLOADING) && | 272 | if (!(vport->load_flag & FC_UNLOADING) && |
273 | !(ndlp->nlp_flag & NLP_DELAY_TMO) && | 273 | !(ndlp->nlp_flag & NLP_DELAY_TMO) && |
274 | !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && | 274 | !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && |
275 | (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) { | 275 | (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) |
276 | lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); | 276 | lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); |
277 | } | ||
278 | } | 277 | } |
279 | 278 | ||
280 | 279 | ||
@@ -566,9 +565,10 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) | |||
566 | int rc; | 565 | int rc; |
567 | 566 | ||
568 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { | 567 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { |
568 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
569 | continue; | ||
569 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | 570 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) |
570 | continue; | 571 | continue; |
571 | |||
572 | if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) || | 572 | if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) || |
573 | ((vport->port_type == LPFC_NPIV_PORT) && | 573 | ((vport->port_type == LPFC_NPIV_PORT) && |
574 | (ndlp->nlp_DID == NameServer_DID))) | 574 | (ndlp->nlp_DID == NameServer_DID))) |
@@ -629,9 +629,8 @@ lpfc_linkdown(struct lpfc_hba *phba) | |||
629 | LPFC_MBOXQ_t *mb; | 629 | LPFC_MBOXQ_t *mb; |
630 | int i; | 630 | int i; |
631 | 631 | ||
632 | if (phba->link_state == LPFC_LINK_DOWN) { | 632 | if (phba->link_state == LPFC_LINK_DOWN) |
633 | return 0; | 633 | return 0; |
634 | } | ||
635 | spin_lock_irq(&phba->hbalock); | 634 | spin_lock_irq(&phba->hbalock); |
636 | if (phba->link_state > LPFC_LINK_DOWN) { | 635 | if (phba->link_state > LPFC_LINK_DOWN) { |
637 | phba->link_state = LPFC_LINK_DOWN; | 636 | phba->link_state = LPFC_LINK_DOWN; |
@@ -684,20 +683,21 @@ lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport) | |||
684 | struct lpfc_nodelist *ndlp; | 683 | struct lpfc_nodelist *ndlp; |
685 | 684 | ||
686 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { | 685 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { |
686 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
687 | continue; | ||
687 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | 688 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) |
688 | continue; | 689 | continue; |
689 | |||
690 | if (ndlp->nlp_type & NLP_FABRIC) { | 690 | if (ndlp->nlp_type & NLP_FABRIC) { |
691 | /* On Linkup its safe to clean up the ndlp | 691 | /* On Linkup its safe to clean up the ndlp |
692 | * from Fabric connections. | 692 | * from Fabric connections. |
693 | */ | 693 | */ |
694 | if (ndlp->nlp_DID != Fabric_DID) | 694 | if (ndlp->nlp_DID != Fabric_DID) |
695 | lpfc_unreg_rpi(vport, ndlp); | 695 | lpfc_unreg_rpi(vport, ndlp); |
696 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | 696 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); |
697 | } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { | 697 | } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { |
698 | /* Fail outstanding IO now since device is | 698 | /* Fail outstanding IO now since device is |
699 | * marked for PLOGI. | 699 | * marked for PLOGI. |
700 | */ | 700 | */ |
701 | lpfc_unreg_rpi(vport, ndlp); | 701 | lpfc_unreg_rpi(vport, ndlp); |
702 | } | 702 | } |
703 | } | 703 | } |
@@ -799,21 +799,9 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
799 | writel(control, phba->HCregaddr); | 799 | writel(control, phba->HCregaddr); |
800 | readl(phba->HCregaddr); /* flush */ | 800 | readl(phba->HCregaddr); /* flush */ |
801 | spin_unlock_irq(&phba->hbalock); | 801 | spin_unlock_irq(&phba->hbalock); |
802 | mempool_free(pmb, phba->mbox_mem_pool); | ||
802 | return; | 803 | return; |
803 | 804 | ||
804 | vport->num_disc_nodes = 0; | ||
805 | /* go thru NPR nodes and issue ELS PLOGIs */ | ||
806 | if (vport->fc_npr_cnt) | ||
807 | lpfc_els_disc_plogi(vport); | ||
808 | |||
809 | if (!vport->num_disc_nodes) { | ||
810 | spin_lock_irq(shost->host_lock); | ||
811 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
812 | spin_unlock_irq(shost->host_lock); | ||
813 | } | ||
814 | |||
815 | vport->port_state = LPFC_VPORT_READY; | ||
816 | |||
817 | out: | 805 | out: |
818 | /* Device Discovery completes */ | 806 | /* Device Discovery completes */ |
819 | lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, | 807 | lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, |
@@ -1133,7 +1121,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1133 | if (la->attType == AT_LINK_UP) { | 1121 | if (la->attType == AT_LINK_UP) { |
1134 | phba->fc_stat.LinkUp++; | 1122 | phba->fc_stat.LinkUp++; |
1135 | if (phba->link_flag & LS_LOOPBACK_MODE) { | 1123 | if (phba->link_flag & LS_LOOPBACK_MODE) { |
1136 | lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, | 1124 | lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, |
1137 | "1306 Link Up Event in loop back mode " | 1125 | "1306 Link Up Event in loop back mode " |
1138 | "x%x received Data: x%x x%x x%x x%x\n", | 1126 | "x%x received Data: x%x x%x x%x x%x\n", |
1139 | la->eventTag, phba->fc_eventTag, | 1127 | la->eventTag, phba->fc_eventTag, |
@@ -1150,11 +1138,21 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1150 | lpfc_mbx_process_link_up(phba, la); | 1138 | lpfc_mbx_process_link_up(phba, la); |
1151 | } else { | 1139 | } else { |
1152 | phba->fc_stat.LinkDown++; | 1140 | phba->fc_stat.LinkDown++; |
1153 | lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, | 1141 | if (phba->link_flag & LS_LOOPBACK_MODE) { |
1142 | lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, | ||
1143 | "1308 Link Down Event in loop back mode " | ||
1144 | "x%x received " | ||
1145 | "Data: x%x x%x x%x\n", | ||
1146 | la->eventTag, phba->fc_eventTag, | ||
1147 | phba->pport->port_state, vport->fc_flag); | ||
1148 | } | ||
1149 | else { | ||
1150 | lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, | ||
1154 | "1305 Link Down Event x%x received " | 1151 | "1305 Link Down Event x%x received " |
1155 | "Data: x%x x%x x%x\n", | 1152 | "Data: x%x x%x x%x\n", |
1156 | la->eventTag, phba->fc_eventTag, | 1153 | la->eventTag, phba->fc_eventTag, |
1157 | phba->pport->port_state, vport->fc_flag); | 1154 | phba->pport->port_state, vport->fc_flag); |
1155 | } | ||
1158 | lpfc_mbx_issue_link_down(phba); | 1156 | lpfc_mbx_issue_link_down(phba); |
1159 | } | 1157 | } |
1160 | 1158 | ||
@@ -1305,7 +1303,6 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1305 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 1303 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
1306 | kfree(mp); | 1304 | kfree(mp); |
1307 | mempool_free(pmb, phba->mbox_mem_pool); | 1305 | mempool_free(pmb, phba->mbox_mem_pool); |
1308 | lpfc_nlp_put(ndlp); | ||
1309 | 1306 | ||
1310 | if (phba->fc_topology == TOPOLOGY_LOOP) { | 1307 | if (phba->fc_topology == TOPOLOGY_LOOP) { |
1311 | /* FLOGI failed, use loop map to make discovery list */ | 1308 | /* FLOGI failed, use loop map to make discovery list */ |
@@ -1313,6 +1310,10 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1313 | 1310 | ||
1314 | /* Start discovery */ | 1311 | /* Start discovery */ |
1315 | lpfc_disc_start(vport); | 1312 | lpfc_disc_start(vport); |
1313 | /* Decrement the reference count to ndlp after the | ||
1314 | * reference to the ndlp are done. | ||
1315 | */ | ||
1316 | lpfc_nlp_put(ndlp); | ||
1316 | return; | 1317 | return; |
1317 | } | 1318 | } |
1318 | 1319 | ||
@@ -1320,6 +1321,10 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1320 | lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, | 1321 | lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, |
1321 | "0258 Register Fabric login error: 0x%x\n", | 1322 | "0258 Register Fabric login error: 0x%x\n", |
1322 | mb->mbxStatus); | 1323 | mb->mbxStatus); |
1324 | /* Decrement the reference count to ndlp after the reference | ||
1325 | * to the ndlp are done. | ||
1326 | */ | ||
1327 | lpfc_nlp_put(ndlp); | ||
1323 | return; | 1328 | return; |
1324 | } | 1329 | } |
1325 | 1330 | ||
@@ -1327,8 +1332,6 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1327 | ndlp->nlp_type |= NLP_FABRIC; | 1332 | ndlp->nlp_type |= NLP_FABRIC; |
1328 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); | 1333 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); |
1329 | 1334 | ||
1330 | lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */ | ||
1331 | |||
1332 | if (vport->port_state == LPFC_FABRIC_CFG_LINK) { | 1335 | if (vport->port_state == LPFC_FABRIC_CFG_LINK) { |
1333 | vports = lpfc_create_vport_work_array(phba); | 1336 | vports = lpfc_create_vport_work_array(phba); |
1334 | if (vports != NULL) | 1337 | if (vports != NULL) |
@@ -1356,6 +1359,11 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1356 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 1359 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
1357 | kfree(mp); | 1360 | kfree(mp); |
1358 | mempool_free(pmb, phba->mbox_mem_pool); | 1361 | mempool_free(pmb, phba->mbox_mem_pool); |
1362 | |||
1363 | /* Drop the reference count from the mbox at the end after | ||
1364 | * all the current reference to the ndlp have been done. | ||
1365 | */ | ||
1366 | lpfc_nlp_put(ndlp); | ||
1359 | return; | 1367 | return; |
1360 | } | 1368 | } |
1361 | 1369 | ||
@@ -1463,9 +1471,8 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1463 | * registered the port. | 1471 | * registered the port. |
1464 | */ | 1472 | */ |
1465 | if (ndlp->rport && ndlp->rport->dd_data && | 1473 | if (ndlp->rport && ndlp->rport->dd_data && |
1466 | ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) { | 1474 | ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) |
1467 | lpfc_nlp_put(ndlp); | 1475 | lpfc_nlp_put(ndlp); |
1468 | } | ||
1469 | 1476 | ||
1470 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, | 1477 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, |
1471 | "rport add: did:x%x flg:x%x type x%x", | 1478 | "rport add: did:x%x flg:x%x type x%x", |
@@ -1660,6 +1667,18 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1660 | } | 1667 | } |
1661 | 1668 | ||
1662 | void | 1669 | void |
1670 | lpfc_enqueue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | ||
1671 | { | ||
1672 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
1673 | |||
1674 | if (list_empty(&ndlp->nlp_listp)) { | ||
1675 | spin_lock_irq(shost->host_lock); | ||
1676 | list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); | ||
1677 | spin_unlock_irq(shost->host_lock); | ||
1678 | } | ||
1679 | } | ||
1680 | |||
1681 | void | ||
1663 | lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | 1682 | lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) |
1664 | { | 1683 | { |
1665 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 1684 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
@@ -1672,7 +1691,80 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1672 | list_del_init(&ndlp->nlp_listp); | 1691 | list_del_init(&ndlp->nlp_listp); |
1673 | spin_unlock_irq(shost->host_lock); | 1692 | spin_unlock_irq(shost->host_lock); |
1674 | lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, | 1693 | lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, |
1675 | NLP_STE_UNUSED_NODE); | 1694 | NLP_STE_UNUSED_NODE); |
1695 | } | ||
1696 | |||
1697 | void | ||
1698 | lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | ||
1699 | { | ||
1700 | if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) | ||
1701 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
1702 | if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) | ||
1703 | lpfc_nlp_counters(vport, ndlp->nlp_state, -1); | ||
1704 | lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, | ||
1705 | NLP_STE_UNUSED_NODE); | ||
1706 | } | ||
1707 | |||
1708 | struct lpfc_nodelist * | ||
1709 | lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||
1710 | int state) | ||
1711 | { | ||
1712 | struct lpfc_hba *phba = vport->phba; | ||
1713 | uint32_t did; | ||
1714 | unsigned long flags; | ||
1715 | |||
1716 | if (!ndlp) | ||
1717 | return NULL; | ||
1718 | |||
1719 | spin_lock_irqsave(&phba->ndlp_lock, flags); | ||
1720 | /* The ndlp should not be in memory free mode */ | ||
1721 | if (NLP_CHK_FREE_REQ(ndlp)) { | ||
1722 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
1723 | lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, | ||
1724 | "0277 lpfc_enable_node: ndlp:x%p " | ||
1725 | "usgmap:x%x refcnt:%d\n", | ||
1726 | (void *)ndlp, ndlp->nlp_usg_map, | ||
1727 | atomic_read(&ndlp->kref.refcount)); | ||
1728 | return NULL; | ||
1729 | } | ||
1730 | /* The ndlp should not already be in active mode */ | ||
1731 | if (NLP_CHK_NODE_ACT(ndlp)) { | ||
1732 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
1733 | lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, | ||
1734 | "0278 lpfc_enable_node: ndlp:x%p " | ||
1735 | "usgmap:x%x refcnt:%d\n", | ||
1736 | (void *)ndlp, ndlp->nlp_usg_map, | ||
1737 | atomic_read(&ndlp->kref.refcount)); | ||
1738 | return NULL; | ||
1739 | } | ||
1740 | |||
1741 | /* Keep the original DID */ | ||
1742 | did = ndlp->nlp_DID; | ||
1743 | |||
1744 | /* re-initialize ndlp except of ndlp linked list pointer */ | ||
1745 | memset((((char *)ndlp) + sizeof (struct list_head)), 0, | ||
1746 | sizeof (struct lpfc_nodelist) - sizeof (struct list_head)); | ||
1747 | INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); | ||
1748 | INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); | ||
1749 | init_timer(&ndlp->nlp_delayfunc); | ||
1750 | ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; | ||
1751 | ndlp->nlp_delayfunc.data = (unsigned long)ndlp; | ||
1752 | ndlp->nlp_DID = did; | ||
1753 | ndlp->vport = vport; | ||
1754 | ndlp->nlp_sid = NLP_NO_SID; | ||
1755 | /* ndlp management re-initialize */ | ||
1756 | kref_init(&ndlp->kref); | ||
1757 | NLP_INT_NODE_ACT(ndlp); | ||
1758 | |||
1759 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
1760 | |||
1761 | if (state != NLP_STE_UNUSED_NODE) | ||
1762 | lpfc_nlp_set_state(vport, ndlp, state); | ||
1763 | |||
1764 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, | ||
1765 | "node enable: did:x%x", | ||
1766 | ndlp->nlp_DID, 0, 0); | ||
1767 | return ndlp; | ||
1676 | } | 1768 | } |
1677 | 1769 | ||
1678 | void | 1770 | void |
@@ -1972,7 +2064,21 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1972 | "Data: x%x x%x x%x\n", | 2064 | "Data: x%x x%x x%x\n", |
1973 | ndlp->nlp_DID, ndlp->nlp_flag, | 2065 | ndlp->nlp_DID, ndlp->nlp_flag, |
1974 | ndlp->nlp_state, ndlp->nlp_rpi); | 2066 | ndlp->nlp_state, ndlp->nlp_rpi); |
1975 | lpfc_dequeue_node(vport, ndlp); | 2067 | if (NLP_CHK_FREE_REQ(ndlp)) { |
2068 | lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, | ||
2069 | "0280 lpfc_cleanup_node: ndlp:x%p " | ||
2070 | "usgmap:x%x refcnt:%d\n", | ||
2071 | (void *)ndlp, ndlp->nlp_usg_map, | ||
2072 | atomic_read(&ndlp->kref.refcount)); | ||
2073 | lpfc_dequeue_node(vport, ndlp); | ||
2074 | } else { | ||
2075 | lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, | ||
2076 | "0281 lpfc_cleanup_node: ndlp:x%p " | ||
2077 | "usgmap:x%x refcnt:%d\n", | ||
2078 | (void *)ndlp, ndlp->nlp_usg_map, | ||
2079 | atomic_read(&ndlp->kref.refcount)); | ||
2080 | lpfc_disable_node(vport, ndlp); | ||
2081 | } | ||
1976 | 2082 | ||
1977 | /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ | 2083 | /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ |
1978 | if ((mb = phba->sli.mbox_active)) { | 2084 | if ((mb = phba->sli.mbox_active)) { |
@@ -1994,12 +2100,16 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1994 | } | 2100 | } |
1995 | list_del(&mb->list); | 2101 | list_del(&mb->list); |
1996 | mempool_free(mb, phba->mbox_mem_pool); | 2102 | mempool_free(mb, phba->mbox_mem_pool); |
1997 | lpfc_nlp_put(ndlp); | 2103 | /* We shall not invoke the lpfc_nlp_put to decrement |
2104 | * the ndlp reference count as we are in the process | ||
2105 | * of lpfc_nlp_release. | ||
2106 | */ | ||
1998 | } | 2107 | } |
1999 | } | 2108 | } |
2000 | spin_unlock_irq(&phba->hbalock); | 2109 | spin_unlock_irq(&phba->hbalock); |
2001 | 2110 | ||
2002 | lpfc_els_abort(phba,ndlp); | 2111 | lpfc_els_abort(phba, ndlp); |
2112 | |||
2003 | spin_lock_irq(shost->host_lock); | 2113 | spin_lock_irq(shost->host_lock); |
2004 | ndlp->nlp_flag &= ~NLP_DELAY_TMO; | 2114 | ndlp->nlp_flag &= ~NLP_DELAY_TMO; |
2005 | spin_unlock_irq(shost->host_lock); | 2115 | spin_unlock_irq(shost->host_lock); |
@@ -2057,7 +2167,6 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
2057 | } | 2167 | } |
2058 | } | 2168 | } |
2059 | } | 2169 | } |
2060 | |||
2061 | lpfc_cleanup_node(vport, ndlp); | 2170 | lpfc_cleanup_node(vport, ndlp); |
2062 | 2171 | ||
2063 | /* | 2172 | /* |
@@ -2182,7 +2291,16 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) | |||
2182 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | 2291 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; |
2183 | spin_unlock_irq(shost->host_lock); | 2292 | spin_unlock_irq(shost->host_lock); |
2184 | return ndlp; | 2293 | return ndlp; |
2294 | } else if (!NLP_CHK_NODE_ACT(ndlp)) { | ||
2295 | ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE); | ||
2296 | if (!ndlp) | ||
2297 | return NULL; | ||
2298 | spin_lock_irq(shost->host_lock); | ||
2299 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | ||
2300 | spin_unlock_irq(shost->host_lock); | ||
2301 | return ndlp; | ||
2185 | } | 2302 | } |
2303 | |||
2186 | if (vport->fc_flag & FC_RSCN_MODE) { | 2304 | if (vport->fc_flag & FC_RSCN_MODE) { |
2187 | if (lpfc_rscn_payload_check(vport, did)) { | 2305 | if (lpfc_rscn_payload_check(vport, did)) { |
2188 | /* If we've already recieved a PLOGI from this NPort | 2306 | /* If we've already recieved a PLOGI from this NPort |
@@ -2363,6 +2481,7 @@ lpfc_disc_start(struct lpfc_vport *vport) | |||
2363 | * continue discovery. | 2481 | * continue discovery. |
2364 | */ | 2482 | */ |
2365 | if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && | 2483 | if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && |
2484 | !(vport->fc_flag & FC_PT2PT) && | ||
2366 | !(vport->fc_flag & FC_RSCN_MODE)) { | 2485 | !(vport->fc_flag & FC_RSCN_MODE)) { |
2367 | lpfc_issue_reg_vpi(phba, vport); | 2486 | lpfc_issue_reg_vpi(phba, vport); |
2368 | return; | 2487 | return; |
@@ -2485,6 +2604,8 @@ lpfc_disc_flush_list(struct lpfc_vport *vport) | |||
2485 | if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) { | 2604 | if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) { |
2486 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, | 2605 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, |
2487 | nlp_listp) { | 2606 | nlp_listp) { |
2607 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
2608 | continue; | ||
2488 | if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || | 2609 | if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || |
2489 | ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { | 2610 | ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { |
2490 | lpfc_free_tx(phba, ndlp); | 2611 | lpfc_free_tx(phba, ndlp); |
@@ -2572,6 +2693,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
2572 | /* Start discovery by sending FLOGI, clean up old rpis */ | 2693 | /* Start discovery by sending FLOGI, clean up old rpis */ |
2573 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, | 2694 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, |
2574 | nlp_listp) { | 2695 | nlp_listp) { |
2696 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
2697 | continue; | ||
2575 | if (ndlp->nlp_state != NLP_STE_NPR_NODE) | 2698 | if (ndlp->nlp_state != NLP_STE_NPR_NODE) |
2576 | continue; | 2699 | continue; |
2577 | if (ndlp->nlp_type & NLP_FABRIC) { | 2700 | if (ndlp->nlp_type & NLP_FABRIC) { |
@@ -2618,7 +2741,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
2618 | "NameServer login\n"); | 2741 | "NameServer login\n"); |
2619 | /* Next look for NameServer ndlp */ | 2742 | /* Next look for NameServer ndlp */ |
2620 | ndlp = lpfc_findnode_did(vport, NameServer_DID); | 2743 | ndlp = lpfc_findnode_did(vport, NameServer_DID); |
2621 | if (ndlp) | 2744 | if (ndlp && NLP_CHK_NODE_ACT(ndlp)) |
2622 | lpfc_els_abort(phba, ndlp); | 2745 | lpfc_els_abort(phba, ndlp); |
2623 | 2746 | ||
2624 | /* ReStart discovery */ | 2747 | /* ReStart discovery */ |
@@ -2897,6 +3020,7 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
2897 | ndlp->nlp_sid = NLP_NO_SID; | 3020 | ndlp->nlp_sid = NLP_NO_SID; |
2898 | INIT_LIST_HEAD(&ndlp->nlp_listp); | 3021 | INIT_LIST_HEAD(&ndlp->nlp_listp); |
2899 | kref_init(&ndlp->kref); | 3022 | kref_init(&ndlp->kref); |
3023 | NLP_INT_NODE_ACT(ndlp); | ||
2900 | 3024 | ||
2901 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, | 3025 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, |
2902 | "node init: did:x%x", | 3026 | "node init: did:x%x", |
@@ -2911,6 +3035,8 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
2911 | static void | 3035 | static void |
2912 | lpfc_nlp_release(struct kref *kref) | 3036 | lpfc_nlp_release(struct kref *kref) |
2913 | { | 3037 | { |
3038 | struct lpfc_hba *phba; | ||
3039 | unsigned long flags; | ||
2914 | struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, | 3040 | struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, |
2915 | kref); | 3041 | kref); |
2916 | 3042 | ||
@@ -2918,8 +3044,24 @@ lpfc_nlp_release(struct kref *kref) | |||
2918 | "node release: did:x%x flg:x%x type:x%x", | 3044 | "node release: did:x%x flg:x%x type:x%x", |
2919 | ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); | 3045 | ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); |
2920 | 3046 | ||
3047 | lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, | ||
3048 | "0279 lpfc_nlp_release: ndlp:x%p " | ||
3049 | "usgmap:x%x refcnt:%d\n", | ||
3050 | (void *)ndlp, ndlp->nlp_usg_map, | ||
3051 | atomic_read(&ndlp->kref.refcount)); | ||
3052 | |||
3053 | /* remove ndlp from action. */ | ||
2921 | lpfc_nlp_remove(ndlp->vport, ndlp); | 3054 | lpfc_nlp_remove(ndlp->vport, ndlp); |
2922 | mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); | 3055 | |
3056 | /* clear the ndlp active flag for all release cases */ | ||
3057 | phba = ndlp->vport->phba; | ||
3058 | spin_lock_irqsave(&phba->ndlp_lock, flags); | ||
3059 | NLP_CLR_NODE_ACT(ndlp); | ||
3060 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
3061 | |||
3062 | /* free ndlp memory for final ndlp release */ | ||
3063 | if (NLP_CHK_FREE_REQ(ndlp)) | ||
3064 | mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); | ||
2923 | } | 3065 | } |
2924 | 3066 | ||
2925 | /* This routine bumps the reference count for a ndlp structure to ensure | 3067 | /* This routine bumps the reference count for a ndlp structure to ensure |
@@ -2929,37 +3071,108 @@ lpfc_nlp_release(struct kref *kref) | |||
2929 | struct lpfc_nodelist * | 3071 | struct lpfc_nodelist * |
2930 | lpfc_nlp_get(struct lpfc_nodelist *ndlp) | 3072 | lpfc_nlp_get(struct lpfc_nodelist *ndlp) |
2931 | { | 3073 | { |
3074 | struct lpfc_hba *phba; | ||
3075 | unsigned long flags; | ||
3076 | |||
2932 | if (ndlp) { | 3077 | if (ndlp) { |
2933 | lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, | 3078 | lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, |
2934 | "node get: did:x%x flg:x%x refcnt:x%x", | 3079 | "node get: did:x%x flg:x%x refcnt:x%x", |
2935 | ndlp->nlp_DID, ndlp->nlp_flag, | 3080 | ndlp->nlp_DID, ndlp->nlp_flag, |
2936 | atomic_read(&ndlp->kref.refcount)); | 3081 | atomic_read(&ndlp->kref.refcount)); |
2937 | kref_get(&ndlp->kref); | 3082 | /* The check of ndlp usage to prevent incrementing the |
3083 | * ndlp reference count that is in the process of being | ||
3084 | * released. | ||
3085 | */ | ||
3086 | phba = ndlp->vport->phba; | ||
3087 | spin_lock_irqsave(&phba->ndlp_lock, flags); | ||
3088 | if (!NLP_CHK_NODE_ACT(ndlp) || NLP_CHK_FREE_ACK(ndlp)) { | ||
3089 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
3090 | lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, | ||
3091 | "0276 lpfc_nlp_get: ndlp:x%p " | ||
3092 | "usgmap:x%x refcnt:%d\n", | ||
3093 | (void *)ndlp, ndlp->nlp_usg_map, | ||
3094 | atomic_read(&ndlp->kref.refcount)); | ||
3095 | return NULL; | ||
3096 | } else | ||
3097 | kref_get(&ndlp->kref); | ||
3098 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
2938 | } | 3099 | } |
2939 | return ndlp; | 3100 | return ndlp; |
2940 | } | 3101 | } |
2941 | 3102 | ||
2942 | |||
2943 | /* This routine decrements the reference count for a ndlp structure. If the | 3103 | /* This routine decrements the reference count for a ndlp structure. If the |
2944 | * count goes to 0, this indicates the the associated nodelist should be freed. | 3104 | * count goes to 0, this indicates the the associated nodelist should be |
3105 | * freed. Returning 1 indicates the ndlp resource has been released; on the | ||
3106 | * other hand, returning 0 indicates the ndlp resource has not been released | ||
3107 | * yet. | ||
2945 | */ | 3108 | */ |
2946 | int | 3109 | int |
2947 | lpfc_nlp_put(struct lpfc_nodelist *ndlp) | 3110 | lpfc_nlp_put(struct lpfc_nodelist *ndlp) |
2948 | { | 3111 | { |
2949 | if (ndlp) { | 3112 | struct lpfc_hba *phba; |
2950 | lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, | 3113 | unsigned long flags; |
2951 | "node put: did:x%x flg:x%x refcnt:x%x", | 3114 | |
2952 | ndlp->nlp_DID, ndlp->nlp_flag, | 3115 | if (!ndlp) |
2953 | atomic_read(&ndlp->kref.refcount)); | 3116 | return 1; |
3117 | |||
3118 | lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, | ||
3119 | "node put: did:x%x flg:x%x refcnt:x%x", | ||
3120 | ndlp->nlp_DID, ndlp->nlp_flag, | ||
3121 | atomic_read(&ndlp->kref.refcount)); | ||
3122 | phba = ndlp->vport->phba; | ||
3123 | spin_lock_irqsave(&phba->ndlp_lock, flags); | ||
3124 | /* Check the ndlp memory free acknowledge flag to avoid the | ||
3125 | * possible race condition that kref_put got invoked again | ||
3126 | * after previous one has done ndlp memory free. | ||
3127 | */ | ||
3128 | if (NLP_CHK_FREE_ACK(ndlp)) { | ||
3129 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
3130 | lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, | ||
3131 | "0274 lpfc_nlp_put: ndlp:x%p " | ||
3132 | "usgmap:x%x refcnt:%d\n", | ||
3133 | (void *)ndlp, ndlp->nlp_usg_map, | ||
3134 | atomic_read(&ndlp->kref.refcount)); | ||
3135 | return 1; | ||
2954 | } | 3136 | } |
2955 | return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0; | 3137 | /* Check the ndlp inactivate log flag to avoid the possible |
3138 | * race condition that kref_put got invoked again after ndlp | ||
3139 | * is already in inactivating state. | ||
3140 | */ | ||
3141 | if (NLP_CHK_IACT_REQ(ndlp)) { | ||
3142 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
3143 | lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, | ||
3144 | "0275 lpfc_nlp_put: ndlp:x%p " | ||
3145 | "usgmap:x%x refcnt:%d\n", | ||
3146 | (void *)ndlp, ndlp->nlp_usg_map, | ||
3147 | atomic_read(&ndlp->kref.refcount)); | ||
3148 | return 1; | ||
3149 | } | ||
3150 | /* For last put, mark the ndlp usage flags to make sure no | ||
3151 | * other kref_get and kref_put on the same ndlp shall get | ||
3152 | * in between the process when the final kref_put has been | ||
3153 | * invoked on this ndlp. | ||
3154 | */ | ||
3155 | if (atomic_read(&ndlp->kref.refcount) == 1) { | ||
3156 | /* Indicate ndlp is put to inactive state. */ | ||
3157 | NLP_SET_IACT_REQ(ndlp); | ||
3158 | /* Acknowledge ndlp memory free has been seen. */ | ||
3159 | if (NLP_CHK_FREE_REQ(ndlp)) | ||
3160 | NLP_SET_FREE_ACK(ndlp); | ||
3161 | } | ||
3162 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
3163 | /* Note, the kref_put returns 1 when decrementing a reference | ||
3164 | * count that was 1, it invokes the release callback function, | ||
3165 | * but it still left the reference count as 1 (not actually | ||
3166 | * performs the last decrementation). Otherwise, it actually | ||
3167 | * decrements the reference count and returns 0. | ||
3168 | */ | ||
3169 | return kref_put(&ndlp->kref, lpfc_nlp_release); | ||
2956 | } | 3170 | } |
2957 | 3171 | ||
2958 | /* This routine free's the specified nodelist if it is not in use | 3172 | /* This routine free's the specified nodelist if it is not in use |
2959 | * by any other discovery thread. This routine returns 1 if the ndlp | 3173 | * by any other discovery thread. This routine returns 1 if the |
2960 | * is not being used by anyone and has been freed. A return value of | 3174 | * ndlp has been freed. A return value of 0 indicates the ndlp is |
2961 | * 0 indicates it is being used by another discovery thread and the | 3175 | * not yet been released. |
2962 | * refcount is left unchanged. | ||
2963 | */ | 3176 | */ |
2964 | int | 3177 | int |
2965 | lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) | 3178 | lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) |
@@ -2968,11 +3181,8 @@ lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) | |||
2968 | "node not used: did:x%x flg:x%x refcnt:x%x", | 3181 | "node not used: did:x%x flg:x%x refcnt:x%x", |
2969 | ndlp->nlp_DID, ndlp->nlp_flag, | 3182 | ndlp->nlp_DID, ndlp->nlp_flag, |
2970 | atomic_read(&ndlp->kref.refcount)); | 3183 | atomic_read(&ndlp->kref.refcount)); |
2971 | 3184 | if (atomic_read(&ndlp->kref.refcount) == 1) | |
2972 | if (atomic_read(&ndlp->kref.refcount) == 1) { | 3185 | if (lpfc_nlp_put(ndlp)) |
2973 | lpfc_nlp_put(ndlp); | 3186 | return 1; |
2974 | return 1; | ||
2975 | } | ||
2976 | return 0; | 3187 | return 0; |
2977 | } | 3188 | } |
2978 | |||