diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-04-25 09:53:01 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-05-06 10:33:15 -0400 |
commit | 329f9bc735b4665d42267259b1612191f72c4d42 (patch) | |
tree | b696a632e19afa0d0e42012efd7992690f69e1a1 /drivers/scsi/lpfc/lpfc_hbadisc.c | |
parent | 2680eeaaa03e83a87ece2724e71f7cc816cd3ef0 (diff) |
[SCSI] lpfc 8.1.12 : Reference count node structures for node lifetime management
Reference count node structures for node lifetime management.
Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 107 |
1 files changed, 72 insertions, 35 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 164af8a7e95d..8ba2f4eadcdd 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -158,6 +158,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) | |||
158 | else { | 158 | else { |
159 | rdata->pnode = NULL; | 159 | rdata->pnode = NULL; |
160 | ndlp->rport = NULL; | 160 | ndlp->rport = NULL; |
161 | lpfc_nlp_put(ndlp); | ||
162 | put_device(&rport->dev); | ||
161 | } | 163 | } |
162 | 164 | ||
163 | return; | 165 | return; |
@@ -960,6 +962,7 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
960 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 962 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
961 | kfree(mp); | 963 | kfree(mp); |
962 | mempool_free( pmb, phba->mbox_mem_pool); | 964 | mempool_free( pmb, phba->mbox_mem_pool); |
965 | lpfc_nlp_put(ndlp); | ||
963 | 966 | ||
964 | return; | 967 | return; |
965 | } | 968 | } |
@@ -986,11 +989,14 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
986 | ndlp = (struct lpfc_nodelist *) pmb->context2; | 989 | ndlp = (struct lpfc_nodelist *) pmb->context2; |
987 | mp = (struct lpfc_dmabuf *) (pmb->context1); | 990 | mp = (struct lpfc_dmabuf *) (pmb->context1); |
988 | 991 | ||
992 | pmb->context1 = NULL; | ||
993 | pmb->context2 = NULL; | ||
994 | |||
989 | if (mb->mbxStatus) { | 995 | if (mb->mbxStatus) { |
990 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 996 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
991 | kfree(mp); | 997 | kfree(mp); |
992 | mempool_free( pmb, phba->mbox_mem_pool); | 998 | mempool_free(pmb, phba->mbox_mem_pool); |
993 | mempool_free( ndlp, phba->nlp_mem_pool); | 999 | lpfc_nlp_put(ndlp); |
994 | 1000 | ||
995 | /* FLOGI failed, so just use loop map to make discovery list */ | 1001 | /* FLOGI failed, so just use loop map to make discovery list */ |
996 | lpfc_disc_list_loopmap(phba); | 1002 | lpfc_disc_list_loopmap(phba); |
@@ -1000,12 +1006,12 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
1000 | return; | 1006 | return; |
1001 | } | 1007 | } |
1002 | 1008 | ||
1003 | pmb->context1 = NULL; | ||
1004 | |||
1005 | ndlp->nlp_rpi = mb->un.varWords[0]; | 1009 | ndlp->nlp_rpi = mb->un.varWords[0]; |
1006 | ndlp->nlp_type |= NLP_FABRIC; | 1010 | ndlp->nlp_type |= NLP_FABRIC; |
1007 | lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); | 1011 | lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); |
1008 | 1012 | ||
1013 | lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */ | ||
1014 | |||
1009 | if (phba->hba_state == LPFC_FABRIC_CFG_LINK) { | 1015 | if (phba->hba_state == LPFC_FABRIC_CFG_LINK) { |
1010 | /* This NPort has been assigned an NPort_ID by the fabric as a | 1016 | /* This NPort has been assigned an NPort_ID by the fabric as a |
1011 | * result of the completed fabric login. Issue a State Change | 1017 | * result of the completed fabric login. Issue a State Change |
@@ -1027,7 +1033,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
1027 | lpfc_disc_start(phba); | 1033 | lpfc_disc_start(phba); |
1028 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 1034 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
1029 | kfree(mp); | 1035 | kfree(mp); |
1030 | mempool_free( pmb, phba->mbox_mem_pool); | 1036 | mempool_free(pmb, phba->mbox_mem_pool); |
1031 | return; | 1037 | return; |
1032 | } else { | 1038 | } else { |
1033 | lpfc_nlp_init(phba, ndlp, NameServer_DID); | 1039 | lpfc_nlp_init(phba, ndlp, NameServer_DID); |
@@ -1050,7 +1056,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
1050 | 1056 | ||
1051 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 1057 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
1052 | kfree(mp); | 1058 | kfree(mp); |
1053 | mempool_free( pmb, phba->mbox_mem_pool); | 1059 | mempool_free(pmb, phba->mbox_mem_pool); |
1054 | return; | 1060 | return; |
1055 | } | 1061 | } |
1056 | 1062 | ||
@@ -1075,6 +1081,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
1075 | mp = (struct lpfc_dmabuf *) (pmb->context1); | 1081 | mp = (struct lpfc_dmabuf *) (pmb->context1); |
1076 | 1082 | ||
1077 | if (mb->mbxStatus) { | 1083 | if (mb->mbxStatus) { |
1084 | lpfc_nlp_put(ndlp); | ||
1078 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 1085 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
1079 | kfree(mp); | 1086 | kfree(mp); |
1080 | mempool_free(pmb, phba->mbox_mem_pool); | 1087 | mempool_free(pmb, phba->mbox_mem_pool); |
@@ -1110,6 +1117,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
1110 | lpfc_disc_start(phba); | 1117 | lpfc_disc_start(phba); |
1111 | } | 1118 | } |
1112 | 1119 | ||
1120 | lpfc_nlp_put(ndlp); | ||
1113 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 1121 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
1114 | kfree(mp); | 1122 | kfree(mp); |
1115 | mempool_free( pmb, phba->mbox_mem_pool); | 1123 | mempool_free( pmb, phba->mbox_mem_pool); |
@@ -1118,8 +1126,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
1118 | } | 1126 | } |
1119 | 1127 | ||
1120 | static void | 1128 | static void |
1121 | lpfc_register_remote_port(struct lpfc_hba * phba, | 1129 | lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) |
1122 | struct lpfc_nodelist * ndlp) | ||
1123 | { | 1130 | { |
1124 | struct fc_rport *rport; | 1131 | struct fc_rport *rport; |
1125 | struct lpfc_rport_data *rdata; | 1132 | struct lpfc_rport_data *rdata; |
@@ -1131,8 +1138,19 @@ lpfc_register_remote_port(struct lpfc_hba * phba, | |||
1131 | rport_ids.port_id = ndlp->nlp_DID; | 1138 | rport_ids.port_id = ndlp->nlp_DID; |
1132 | rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; | 1139 | rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; |
1133 | 1140 | ||
1141 | /* | ||
1142 | * We leave our node pointer in rport->dd_data when we unregister a | ||
1143 | * FCP target port. But fc_remote_port_add zeros the space to which | ||
1144 | * rport->dd_data points. So, if we're reusing a previously | ||
1145 | * registered port, drop the reference that we took the last time we | ||
1146 | * registered the port. | ||
1147 | */ | ||
1148 | if (ndlp->rport && ndlp->rport->dd_data && | ||
1149 | *(struct lpfc_rport_data **) ndlp->rport->dd_data) { | ||
1150 | lpfc_nlp_put(ndlp); | ||
1151 | } | ||
1134 | ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids); | 1152 | ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids); |
1135 | if (!rport) { | 1153 | if (!rport || !get_device(&rport->dev)) { |
1136 | dev_printk(KERN_WARNING, &phba->pcidev->dev, | 1154 | dev_printk(KERN_WARNING, &phba->pcidev->dev, |
1137 | "Warning: fc_remote_port_add failed\n"); | 1155 | "Warning: fc_remote_port_add failed\n"); |
1138 | return; | 1156 | return; |
@@ -1142,7 +1160,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba, | |||
1142 | rport->maxframe_size = ndlp->nlp_maxframe; | 1160 | rport->maxframe_size = ndlp->nlp_maxframe; |
1143 | rport->supported_classes = ndlp->nlp_class_sup; | 1161 | rport->supported_classes = ndlp->nlp_class_sup; |
1144 | rdata = rport->dd_data; | 1162 | rdata = rport->dd_data; |
1145 | rdata->pnode = ndlp; | 1163 | rdata->pnode = lpfc_nlp_get(ndlp); |
1146 | 1164 | ||
1147 | if (ndlp->nlp_type & NLP_FCP_TARGET) | 1165 | if (ndlp->nlp_type & NLP_FCP_TARGET) |
1148 | rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; | 1166 | rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; |
@@ -1162,8 +1180,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba, | |||
1162 | } | 1180 | } |
1163 | 1181 | ||
1164 | static void | 1182 | static void |
1165 | lpfc_unregister_remote_port(struct lpfc_hba * phba, | 1183 | lpfc_unregister_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) |
1166 | struct lpfc_nodelist * ndlp) | ||
1167 | { | 1184 | { |
1168 | struct fc_rport *rport = ndlp->rport; | 1185 | struct fc_rport *rport = ndlp->rport; |
1169 | struct lpfc_rport_data *rdata = rport->dd_data; | 1186 | struct lpfc_rport_data *rdata = rport->dd_data; |
@@ -1171,6 +1188,8 @@ lpfc_unregister_remote_port(struct lpfc_hba * phba, | |||
1171 | if (rport->scsi_target_id == -1) { | 1188 | if (rport->scsi_target_id == -1) { |
1172 | ndlp->rport = NULL; | 1189 | ndlp->rport = NULL; |
1173 | rdata->pnode = NULL; | 1190 | rdata->pnode = NULL; |
1191 | lpfc_nlp_put(ndlp); | ||
1192 | put_device(&rport->dev); | ||
1174 | } | 1193 | } |
1175 | 1194 | ||
1176 | fc_remote_port_delete(rport); | 1195 | fc_remote_port_delete(rport); |
@@ -1416,7 +1435,7 @@ lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) | |||
1416 | lpfc_nlp_counters(phba, ndlp->nlp_state, -1); | 1435 | lpfc_nlp_counters(phba, ndlp->nlp_state, -1); |
1417 | lpfc_delink_node(phba, ndlp); | 1436 | lpfc_delink_node(phba, ndlp); |
1418 | spin_unlock_irq(phba->host->host_lock); | 1437 | spin_unlock_irq(phba->host->host_lock); |
1419 | lpfc_nlp_remove(phba, ndlp); | 1438 | lpfc_nlp_put(ndlp); |
1420 | } | 1439 | } |
1421 | 1440 | ||
1422 | /* | 1441 | /* |
@@ -1654,6 +1673,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) | |||
1654 | } | 1673 | } |
1655 | list_del(&mb->list); | 1674 | list_del(&mb->list); |
1656 | mempool_free(mb, phba->mbox_mem_pool); | 1675 | mempool_free(mb, phba->mbox_mem_pool); |
1676 | lpfc_nlp_put(ndlp); | ||
1657 | } | 1677 | } |
1658 | } | 1678 | } |
1659 | spin_unlock_irq(phba->host->host_lock); | 1679 | spin_unlock_irq(phba->host->host_lock); |
@@ -1679,8 +1699,8 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) | |||
1679 | * If we are in the middle of using the nlp in the discovery state | 1699 | * If we are in the middle of using the nlp in the discovery state |
1680 | * machine, defer the free till we reach the end of the state machine. | 1700 | * machine, defer the free till we reach the end of the state machine. |
1681 | */ | 1701 | */ |
1682 | int | 1702 | static void |
1683 | lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) | 1703 | lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) |
1684 | { | 1704 | { |
1685 | struct lpfc_rport_data *rdata; | 1705 | struct lpfc_rport_data *rdata; |
1686 | 1706 | ||
@@ -1688,22 +1708,14 @@ lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) | |||
1688 | lpfc_cancel_retry_delay_tmo(phba, ndlp); | 1708 | lpfc_cancel_retry_delay_tmo(phba, ndlp); |
1689 | } | 1709 | } |
1690 | 1710 | ||
1691 | if (ndlp->nlp_disc_refcnt) { | 1711 | lpfc_freenode(phba, ndlp); |
1692 | spin_lock_irq(phba->host->host_lock); | ||
1693 | ndlp->nlp_flag |= NLP_DELAY_REMOVE; | ||
1694 | spin_unlock_irq(phba->host->host_lock); | ||
1695 | } else { | ||
1696 | lpfc_freenode(phba, ndlp); | ||
1697 | |||
1698 | if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) { | ||
1699 | rdata = ndlp->rport->dd_data; | ||
1700 | rdata->pnode = NULL; | ||
1701 | ndlp->rport = NULL; | ||
1702 | } | ||
1703 | 1712 | ||
1704 | mempool_free( ndlp, phba->nlp_mem_pool); | 1713 | if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) { |
1714 | put_device(&ndlp->rport->dev); | ||
1715 | rdata = ndlp->rport->dd_data; | ||
1716 | rdata->pnode = NULL; | ||
1717 | ndlp->rport = NULL; | ||
1705 | } | 1718 | } |
1706 | return 0; | ||
1707 | } | 1719 | } |
1708 | 1720 | ||
1709 | static int | 1721 | static int |
@@ -2069,14 +2081,14 @@ lpfc_disc_flush_list(struct lpfc_hba * phba) | |||
2069 | list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list, | 2081 | list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list, |
2070 | nlp_listp) { | 2082 | nlp_listp) { |
2071 | lpfc_free_tx(phba, ndlp); | 2083 | lpfc_free_tx(phba, ndlp); |
2072 | lpfc_nlp_remove(phba, ndlp); | 2084 | lpfc_nlp_put(ndlp); |
2073 | } | 2085 | } |
2074 | } | 2086 | } |
2075 | if (phba->fc_adisc_cnt) { | 2087 | if (phba->fc_adisc_cnt) { |
2076 | list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list, | 2088 | list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list, |
2077 | nlp_listp) { | 2089 | nlp_listp) { |
2078 | lpfc_free_tx(phba, ndlp); | 2090 | lpfc_free_tx(phba, ndlp); |
2079 | lpfc_nlp_remove(phba, ndlp); | 2091 | lpfc_nlp_put(ndlp); |
2080 | } | 2092 | } |
2081 | } | 2093 | } |
2082 | return; | 2094 | return; |
@@ -2195,7 +2207,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) | |||
2195 | /* Next look for NameServer ndlp */ | 2207 | /* Next look for NameServer ndlp */ |
2196 | ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID); | 2208 | ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID); |
2197 | if (ndlp) | 2209 | if (ndlp) |
2198 | lpfc_nlp_remove(phba, ndlp); | 2210 | lpfc_nlp_put(ndlp); |
2199 | /* Start discovery */ | 2211 | /* Start discovery */ |
2200 | lpfc_disc_start(phba); | 2212 | lpfc_disc_start(phba); |
2201 | break; | 2213 | break; |
@@ -2373,9 +2385,11 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
2373 | mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60); | 2385 | mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60); |
2374 | } | 2386 | } |
2375 | 2387 | ||
2388 | /* Mailbox took a reference to the node */ | ||
2389 | lpfc_nlp_put(ndlp); | ||
2376 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 2390 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
2377 | kfree(mp); | 2391 | kfree(mp); |
2378 | mempool_free( pmb, phba->mbox_mem_pool); | 2392 | mempool_free(pmb, phba->mbox_mem_pool); |
2379 | 2393 | ||
2380 | return; | 2394 | return; |
2381 | } | 2395 | } |
@@ -2460,8 +2474,7 @@ lpfc_findnode_wwpn(struct lpfc_hba * phba, uint32_t order, | |||
2460 | } | 2474 | } |
2461 | 2475 | ||
2462 | void | 2476 | void |
2463 | lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, | 2477 | lpfc_nlp_init(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did) |
2464 | uint32_t did) | ||
2465 | { | 2478 | { |
2466 | memset(ndlp, 0, sizeof (struct lpfc_nodelist)); | 2479 | memset(ndlp, 0, sizeof (struct lpfc_nodelist)); |
2467 | INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); | 2480 | INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); |
@@ -2471,5 +2484,29 @@ lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, | |||
2471 | ndlp->nlp_DID = did; | 2484 | ndlp->nlp_DID = did; |
2472 | ndlp->nlp_phba = phba; | 2485 | ndlp->nlp_phba = phba; |
2473 | ndlp->nlp_sid = NLP_NO_SID; | 2486 | ndlp->nlp_sid = NLP_NO_SID; |
2487 | kref_init(&ndlp->kref); | ||
2474 | return; | 2488 | return; |
2475 | } | 2489 | } |
2490 | |||
2491 | void | ||
2492 | lpfc_nlp_release(struct kref *kref) | ||
2493 | { | ||
2494 | struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, | ||
2495 | kref); | ||
2496 | lpfc_nlp_remove(ndlp->nlp_phba, ndlp); | ||
2497 | mempool_free(ndlp, ndlp->nlp_phba->nlp_mem_pool); | ||
2498 | } | ||
2499 | |||
2500 | struct lpfc_nodelist * | ||
2501 | lpfc_nlp_get(struct lpfc_nodelist *ndlp) | ||
2502 | { | ||
2503 | if (ndlp) | ||
2504 | kref_get(&ndlp->kref); | ||
2505 | return ndlp; | ||
2506 | } | ||
2507 | |||
2508 | int | ||
2509 | lpfc_nlp_put(struct lpfc_nodelist *ndlp) | ||
2510 | { | ||
2511 | return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0; | ||
2512 | } | ||