diff options
author | James Smart <James.Smart@Emulex.Com> | 2008-02-08 18:49:26 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-02-11 18:52:57 -0500 |
commit | e47c9093531d3406a8ae38acca4ce207ef70cc0e (patch) | |
tree | cb115ec0b7981a100ef39ecfc68a36aa7e3e0f2e /drivers/scsi/lpfc | |
parent | 4660c8ed5aaed99d82785499f034a8cc9199866d (diff) |
[SCSI] lpfc 8.2.5 : Correct ndlp referencing issues
Correct ndlp referencing issues:
- Fix ndlp kref issues due to race conditions between threads
- Fix cancel els delay retry event which missed an ndlp reference count
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 5 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 6 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 39 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 33 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 237 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 296 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 41 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 39 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_vport.c | 70 |
11 files changed, 630 insertions, 142 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 83567b9755b4..572c525ad2b5 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -595,6 +595,8 @@ struct lpfc_hba { | |||
595 | unsigned long last_completion_time; | 595 | unsigned long last_completion_time; |
596 | struct timer_list hb_tmofunc; | 596 | struct timer_list hb_tmofunc; |
597 | uint8_t hb_outstanding; | 597 | uint8_t hb_outstanding; |
598 | /* ndlp reference management */ | ||
599 | spinlock_t ndlp_lock; | ||
598 | /* | 600 | /* |
599 | * Following bit will be set for all buffer tags which are not | 601 | * Following bit will be set for all buffer tags which are not |
600 | * associated with any HBQ. | 602 | * associated with any HBQ. |
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 4bae4a2ed2f1..ef061d97a222 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -1191,7 +1191,7 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) | |||
1191 | shost = lpfc_shost_from_vport(vport); | 1191 | shost = lpfc_shost_from_vport(vport); |
1192 | spin_lock_irq(shost->host_lock); | 1192 | spin_lock_irq(shost->host_lock); |
1193 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) | 1193 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) |
1194 | if (ndlp->rport) | 1194 | if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport) |
1195 | ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo; | 1195 | ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo; |
1196 | spin_unlock_irq(shost->host_lock); | 1196 | spin_unlock_irq(shost->host_lock); |
1197 | } | 1197 | } |
@@ -2384,7 +2384,8 @@ lpfc_get_node_by_target(struct scsi_target *starget) | |||
2384 | spin_lock_irq(shost->host_lock); | 2384 | spin_lock_irq(shost->host_lock); |
2385 | /* Search for this, mapped, target ID */ | 2385 | /* Search for this, mapped, target ID */ |
2386 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { | 2386 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { |
2387 | if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && | 2387 | if (NLP_CHK_NODE_ACT(ndlp) && |
2388 | ndlp->nlp_state == NLP_STE_MAPPED_NODE && | ||
2388 | starget->id == ndlp->nlp_sid) { | 2389 | starget->id == ndlp->nlp_sid) { |
2389 | spin_unlock_irq(shost->host_lock); | 2390 | spin_unlock_irq(shost->host_lock); |
2390 | return ndlp; | 2391 | return ndlp; |
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 50fcb7c930bc..848d97744b4d 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -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 | * * | 7 | * * |
@@ -53,7 +53,11 @@ void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *); | |||
53 | void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); | 53 | void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); |
54 | void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); | 54 | void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); |
55 | void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); | 55 | void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); |
56 | void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *); | ||
56 | void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *); | 57 | void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *); |
58 | void lpfc_disable_node(struct lpfc_vport *, struct lpfc_nodelist *); | ||
59 | struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *, | ||
60 | struct lpfc_nodelist *, int); | ||
57 | void lpfc_nlp_set_state(struct lpfc_vport *, struct lpfc_nodelist *, int); | 61 | void lpfc_nlp_set_state(struct lpfc_vport *, struct lpfc_nodelist *, int); |
58 | void lpfc_drop_node(struct lpfc_vport *, struct lpfc_nodelist *); | 62 | void lpfc_drop_node(struct lpfc_vport *, struct lpfc_nodelist *); |
59 | void lpfc_set_disctmo(struct lpfc_vport *); | 63 | void lpfc_set_disctmo(struct lpfc_vport *); |
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 92441ce610ed..aea8d33f6d09 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.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 | * * | 7 | * * |
@@ -294,7 +294,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, | |||
294 | /* Save for completion so we can release these resources */ | 294 | /* Save for completion so we can release these resources */ |
295 | geniocb->context1 = (uint8_t *) inp; | 295 | geniocb->context1 = (uint8_t *) inp; |
296 | geniocb->context2 = (uint8_t *) outp; | 296 | geniocb->context2 = (uint8_t *) outp; |
297 | geniocb->context_un.ndlp = ndlp; | 297 | geniocb->context_un.ndlp = lpfc_nlp_get(ndlp); |
298 | 298 | ||
299 | /* Fill in payload, bp points to frame payload */ | 299 | /* Fill in payload, bp points to frame payload */ |
300 | icmd->ulpCommand = CMD_GEN_REQUEST64_CR; | 300 | icmd->ulpCommand = CMD_GEN_REQUEST64_CR; |
@@ -489,8 +489,10 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) | |||
489 | */ | 489 | */ |
490 | ndlp = lpfc_findnode_did(vport, | 490 | ndlp = lpfc_findnode_did(vport, |
491 | Did); | 491 | Did); |
492 | if (ndlp && (ndlp->nlp_type & | 492 | if (ndlp && |
493 | NLP_FCP_TARGET)) | 493 | NLP_CHK_NODE_ACT(ndlp) |
494 | && (ndlp->nlp_type & | ||
495 | NLP_FCP_TARGET)) | ||
494 | lpfc_setup_disc_node | 496 | lpfc_setup_disc_node |
495 | (vport, Did); | 497 | (vport, Did); |
496 | else if (lpfc_ns_cmd(vport, | 498 | else if (lpfc_ns_cmd(vport, |
@@ -1064,7 +1066,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, | |||
1064 | int rc = 0; | 1066 | int rc = 0; |
1065 | 1067 | ||
1066 | ndlp = lpfc_findnode_did(vport, NameServer_DID); | 1068 | ndlp = lpfc_findnode_did(vport, NameServer_DID); |
1067 | if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) { | 1069 | if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) |
1070 | || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) { | ||
1068 | rc=1; | 1071 | rc=1; |
1069 | goto ns_cmd_exit; | 1072 | goto ns_cmd_exit; |
1070 | } | 1073 | } |
@@ -1213,8 +1216,9 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, | |||
1213 | cmpl = lpfc_cmpl_ct_cmd_rff_id; | 1216 | cmpl = lpfc_cmpl_ct_cmd_rff_id; |
1214 | break; | 1217 | break; |
1215 | } | 1218 | } |
1216 | lpfc_nlp_get(ndlp); | 1219 | /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count |
1217 | 1220 | * to hold ndlp reference for the corresponding callback function. | |
1221 | */ | ||
1218 | if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) { | 1222 | if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) { |
1219 | /* On success, The cmpl function will free the buffers */ | 1223 | /* On success, The cmpl function will free the buffers */ |
1220 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, | 1224 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, |
@@ -1222,9 +1226,13 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, | |||
1222 | cmdcode, ndlp->nlp_DID, 0); | 1226 | cmdcode, ndlp->nlp_DID, 0); |
1223 | return 0; | 1227 | return 0; |
1224 | } | 1228 | } |
1225 | |||
1226 | rc=6; | 1229 | rc=6; |
1230 | |||
1231 | /* Decrement ndlp reference count to release ndlp reference held | ||
1232 | * for the failed command's callback function. | ||
1233 | */ | ||
1227 | lpfc_nlp_put(ndlp); | 1234 | lpfc_nlp_put(ndlp); |
1235 | |||
1228 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | 1236 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); |
1229 | ns_cmd_free_bmp: | 1237 | ns_cmd_free_bmp: |
1230 | kfree(bmp); | 1238 | kfree(bmp); |
@@ -1271,6 +1279,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
1271 | } | 1279 | } |
1272 | 1280 | ||
1273 | ndlp = lpfc_findnode_did(vport, FDMI_DID); | 1281 | ndlp = lpfc_findnode_did(vport, FDMI_DID); |
1282 | if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) | ||
1283 | goto fail_out; | ||
1284 | |||
1274 | if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { | 1285 | if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { |
1275 | /* FDMI rsp failed */ | 1286 | /* FDMI rsp failed */ |
1276 | lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, | 1287 | lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, |
@@ -1294,6 +1305,8 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
1294 | lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA); | 1305 | lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA); |
1295 | break; | 1306 | break; |
1296 | } | 1307 | } |
1308 | |||
1309 | fail_out: | ||
1297 | lpfc_ct_free_iocb(phba, cmdiocb); | 1310 | lpfc_ct_free_iocb(phba, cmdiocb); |
1298 | return; | 1311 | return; |
1299 | } | 1312 | } |
@@ -1650,12 +1663,18 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) | |||
1650 | bpl->tus.w = le32_to_cpu(bpl->tus.w); | 1663 | bpl->tus.w = le32_to_cpu(bpl->tus.w); |
1651 | 1664 | ||
1652 | cmpl = lpfc_cmpl_ct_cmd_fdmi; | 1665 | cmpl = lpfc_cmpl_ct_cmd_fdmi; |
1653 | lpfc_nlp_get(ndlp); | ||
1654 | 1666 | ||
1667 | /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count | ||
1668 | * to hold ndlp reference for the corresponding callback function. | ||
1669 | */ | ||
1655 | if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0)) | 1670 | if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0)) |
1656 | return 0; | 1671 | return 0; |
1657 | 1672 | ||
1673 | /* Decrement ndlp reference count to release ndlp reference held | ||
1674 | * for the failed command's callback function. | ||
1675 | */ | ||
1658 | lpfc_nlp_put(ndlp); | 1676 | lpfc_nlp_put(ndlp); |
1677 | |||
1659 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | 1678 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); |
1660 | fdmi_cmd_free_bmp: | 1679 | fdmi_cmd_free_bmp: |
1661 | kfree(bmp); | 1680 | kfree(bmp); |
@@ -1698,7 +1717,7 @@ lpfc_fdmi_timeout_handler(struct lpfc_vport *vport) | |||
1698 | struct lpfc_nodelist *ndlp; | 1717 | struct lpfc_nodelist *ndlp; |
1699 | 1718 | ||
1700 | ndlp = lpfc_findnode_did(vport, FDMI_DID); | 1719 | ndlp = lpfc_findnode_did(vport, FDMI_DID); |
1701 | if (ndlp) { | 1720 | if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { |
1702 | if (init_utsname()->nodename[0] != '\0') | 1721 | if (init_utsname()->nodename[0] != '\0') |
1703 | lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA); | 1722 | lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA); |
1704 | else | 1723 | else |
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index cfe81c50529a..8eb007309599 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h | |||
@@ -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 | * * | 7 | * * |
@@ -73,6 +73,12 @@ struct lpfc_nodelist { | |||
73 | uint8_t nlp_fcp_info; /* class info, bits 0-3 */ | 73 | uint8_t nlp_fcp_info; /* class info, bits 0-3 */ |
74 | #define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */ | 74 | #define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */ |
75 | 75 | ||
76 | uint16_t nlp_usg_map; /* ndlp management usage bitmap */ | ||
77 | #define NLP_USG_NODE_ACT_BIT 0x1 /* Indicate ndlp is actively used */ | ||
78 | #define NLP_USG_IACT_REQ_BIT 0x2 /* Request to inactivate ndlp */ | ||
79 | #define NLP_USG_FREE_REQ_BIT 0x4 /* Request to invoke ndlp memory free */ | ||
80 | #define NLP_USG_FREE_ACK_BIT 0x8 /* Indicate ndlp memory free invoked */ | ||
81 | |||
76 | struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ | 82 | struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ |
77 | struct fc_rport *rport; /* Corresponding FC transport | 83 | struct fc_rport *rport; /* Corresponding FC transport |
78 | port structure */ | 84 | port structure */ |
@@ -105,6 +111,31 @@ struct lpfc_nodelist { | |||
105 | #define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */ | 111 | #define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */ |
106 | #define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */ | 112 | #define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */ |
107 | 113 | ||
114 | /* ndlp usage management macros */ | ||
115 | #define NLP_CHK_NODE_ACT(ndlp) (((ndlp)->nlp_usg_map \ | ||
116 | & NLP_USG_NODE_ACT_BIT) \ | ||
117 | && \ | ||
118 | !((ndlp)->nlp_usg_map \ | ||
119 | & NLP_USG_FREE_ACK_BIT)) | ||
120 | #define NLP_SET_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ | ||
121 | |= NLP_USG_NODE_ACT_BIT) | ||
122 | #define NLP_INT_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ | ||
123 | = NLP_USG_NODE_ACT_BIT) | ||
124 | #define NLP_CLR_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ | ||
125 | &= ~NLP_USG_NODE_ACT_BIT) | ||
126 | #define NLP_CHK_IACT_REQ(ndlp) ((ndlp)->nlp_usg_map \ | ||
127 | & NLP_USG_IACT_REQ_BIT) | ||
128 | #define NLP_SET_IACT_REQ(ndlp) ((ndlp)->nlp_usg_map \ | ||
129 | |= NLP_USG_IACT_REQ_BIT) | ||
130 | #define NLP_CHK_FREE_REQ(ndlp) ((ndlp)->nlp_usg_map \ | ||
131 | & NLP_USG_FREE_REQ_BIT) | ||
132 | #define NLP_SET_FREE_REQ(ndlp) ((ndlp)->nlp_usg_map \ | ||
133 | |= NLP_USG_FREE_REQ_BIT) | ||
134 | #define NLP_CHK_FREE_ACK(ndlp) ((ndlp)->nlp_usg_map \ | ||
135 | & NLP_USG_FREE_ACK_BIT) | ||
136 | #define NLP_SET_FREE_ACK(ndlp) ((ndlp)->nlp_usg_map \ | ||
137 | |= NLP_USG_FREE_ACK_BIT) | ||
138 | |||
108 | /* There are 4 different double linked lists nodelist entries can reside on. | 139 | /* There are 4 different double linked lists nodelist entries can reside on. |
109 | * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used | 140 | * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used |
110 | * when Link Up discovery or Registered State Change Notification (RSCN) | 141 | * when Link Up discovery or Registered State Change Notification (RSCN) |
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index c6b739dc6bc3..39268e6a1a05 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.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 * |
@@ -113,6 +113,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, | |||
113 | 113 | ||
114 | if (elsiocb == NULL) | 114 | if (elsiocb == NULL) |
115 | return NULL; | 115 | return NULL; |
116 | |||
116 | icmd = &elsiocb->iocb; | 117 | icmd = &elsiocb->iocb; |
117 | 118 | ||
118 | /* fill in BDEs for command */ | 119 | /* fill in BDEs for command */ |
@@ -134,9 +135,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, | |||
134 | if (!prsp || !prsp->virt) | 135 | if (!prsp || !prsp->virt) |
135 | goto els_iocb_free_prsp_exit; | 136 | goto els_iocb_free_prsp_exit; |
136 | INIT_LIST_HEAD(&prsp->list); | 137 | INIT_LIST_HEAD(&prsp->list); |
137 | } else { | 138 | } else |
138 | prsp = NULL; | 139 | prsp = NULL; |
139 | } | ||
140 | 140 | ||
141 | /* Allocate buffer for Buffer ptr list */ | 141 | /* Allocate buffer for Buffer ptr list */ |
142 | pbuflist = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); | 142 | pbuflist = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); |
@@ -246,7 +246,7 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) | |||
246 | 246 | ||
247 | sp = &phba->fc_fabparam; | 247 | sp = &phba->fc_fabparam; |
248 | ndlp = lpfc_findnode_did(vport, Fabric_DID); | 248 | ndlp = lpfc_findnode_did(vport, Fabric_DID); |
249 | if (!ndlp) { | 249 | if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { |
250 | err = 1; | 250 | err = 1; |
251 | goto fail; | 251 | goto fail; |
252 | } | 252 | } |
@@ -282,6 +282,9 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) | |||
282 | 282 | ||
283 | mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login; | 283 | mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login; |
284 | mbox->vport = vport; | 284 | mbox->vport = vport; |
285 | /* increment the reference count on ndlp to hold reference | ||
286 | * for the callback routine. | ||
287 | */ | ||
285 | mbox->context2 = lpfc_nlp_get(ndlp); | 288 | mbox->context2 = lpfc_nlp_get(ndlp); |
286 | 289 | ||
287 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); | 290 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); |
@@ -293,6 +296,9 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) | |||
293 | return 0; | 296 | return 0; |
294 | 297 | ||
295 | fail_issue_reg_login: | 298 | fail_issue_reg_login: |
299 | /* decrement the reference count on ndlp just incremented | ||
300 | * for the failed mbox command. | ||
301 | */ | ||
296 | lpfc_nlp_put(ndlp); | 302 | lpfc_nlp_put(ndlp); |
297 | mp = (struct lpfc_dmabuf *) mbox->context1; | 303 | mp = (struct lpfc_dmabuf *) mbox->context1; |
298 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 304 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
@@ -381,6 +387,8 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
381 | */ | 387 | */ |
382 | list_for_each_entry_safe(np, next_np, | 388 | list_for_each_entry_safe(np, next_np, |
383 | &vport->fc_nodes, nlp_listp) { | 389 | &vport->fc_nodes, nlp_listp) { |
390 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
391 | continue; | ||
384 | if ((np->nlp_state != NLP_STE_NPR_NODE) || | 392 | if ((np->nlp_state != NLP_STE_NPR_NODE) || |
385 | !(np->nlp_flag & NLP_NPR_ADISC)) | 393 | !(np->nlp_flag & NLP_NPR_ADISC)) |
386 | continue; | 394 | continue; |
@@ -456,6 +464,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
456 | mempool_free(mbox, phba->mbox_mem_pool); | 464 | mempool_free(mbox, phba->mbox_mem_pool); |
457 | goto fail; | 465 | goto fail; |
458 | } | 466 | } |
467 | /* Decrement ndlp reference count indicating that ndlp can be | ||
468 | * safely released when other references to it are done. | ||
469 | */ | ||
459 | lpfc_nlp_put(ndlp); | 470 | lpfc_nlp_put(ndlp); |
460 | 471 | ||
461 | ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID); | 472 | ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID); |
@@ -467,22 +478,29 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
467 | ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); | 478 | ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); |
468 | if (!ndlp) | 479 | if (!ndlp) |
469 | goto fail; | 480 | goto fail; |
470 | |||
471 | lpfc_nlp_init(vport, ndlp, PT2PT_RemoteID); | 481 | lpfc_nlp_init(vport, ndlp, PT2PT_RemoteID); |
482 | } else if (!NLP_CHK_NODE_ACT(ndlp)) { | ||
483 | ndlp = lpfc_enable_node(vport, ndlp, | ||
484 | NLP_STE_UNUSED_NODE); | ||
485 | if(!ndlp) | ||
486 | goto fail; | ||
472 | } | 487 | } |
473 | 488 | ||
474 | memcpy(&ndlp->nlp_portname, &sp->portName, | 489 | memcpy(&ndlp->nlp_portname, &sp->portName, |
475 | sizeof(struct lpfc_name)); | 490 | sizeof(struct lpfc_name)); |
476 | memcpy(&ndlp->nlp_nodename, &sp->nodeName, | 491 | memcpy(&ndlp->nlp_nodename, &sp->nodeName, |
477 | sizeof(struct lpfc_name)); | 492 | sizeof(struct lpfc_name)); |
493 | /* Set state will put ndlp onto node list if not already done */ | ||
478 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | 494 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); |
479 | spin_lock_irq(shost->host_lock); | 495 | spin_lock_irq(shost->host_lock); |
480 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | 496 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; |
481 | spin_unlock_irq(shost->host_lock); | 497 | spin_unlock_irq(shost->host_lock); |
482 | } else { | 498 | } else |
483 | /* This side will wait for the PLOGI */ | 499 | /* This side will wait for the PLOGI, decrement ndlp reference |
500 | * count indicating that ndlp can be released when other | ||
501 | * references to it are done. | ||
502 | */ | ||
484 | lpfc_nlp_put(ndlp); | 503 | lpfc_nlp_put(ndlp); |
485 | } | ||
486 | 504 | ||
487 | /* If we are pt2pt with another NPort, force NPIV off! */ | 505 | /* If we are pt2pt with another NPort, force NPIV off! */ |
488 | phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; | 506 | phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; |
@@ -728,16 +746,21 @@ lpfc_initial_flogi(struct lpfc_vport *vport) | |||
728 | if (!ndlp) | 746 | if (!ndlp) |
729 | return 0; | 747 | return 0; |
730 | lpfc_nlp_init(vport, ndlp, Fabric_DID); | 748 | lpfc_nlp_init(vport, ndlp, Fabric_DID); |
731 | } else { | 749 | /* Put ndlp onto node list */ |
732 | lpfc_dequeue_node(vport, ndlp); | 750 | lpfc_enqueue_node(vport, ndlp); |
751 | } else if (!NLP_CHK_NODE_ACT(ndlp)) { | ||
752 | /* re-setup ndlp without removing from node list */ | ||
753 | ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); | ||
754 | if (!ndlp) | ||
755 | return 0; | ||
733 | } | 756 | } |
734 | 757 | ||
735 | if (lpfc_issue_els_flogi(vport, ndlp, 0)) { | 758 | if (lpfc_issue_els_flogi(vport, ndlp, 0)) |
736 | /* This decrement of reference count to node shall kick off | 759 | /* This decrement of reference count to node shall kick off |
737 | * the release of the node. | 760 | * the release of the node. |
738 | */ | 761 | */ |
739 | lpfc_nlp_put(ndlp); | 762 | lpfc_nlp_put(ndlp); |
740 | } | 763 | |
741 | return 1; | 764 | return 1; |
742 | } | 765 | } |
743 | 766 | ||
@@ -755,9 +778,15 @@ lpfc_initial_fdisc(struct lpfc_vport *vport) | |||
755 | if (!ndlp) | 778 | if (!ndlp) |
756 | return 0; | 779 | return 0; |
757 | lpfc_nlp_init(vport, ndlp, Fabric_DID); | 780 | lpfc_nlp_init(vport, ndlp, Fabric_DID); |
758 | } else { | 781 | /* Put ndlp onto node list */ |
759 | lpfc_dequeue_node(vport, ndlp); | 782 | lpfc_enqueue_node(vport, ndlp); |
783 | } else if (!NLP_CHK_NODE_ACT(ndlp)) { | ||
784 | /* re-setup ndlp without removing from node list */ | ||
785 | ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); | ||
786 | if (!ndlp) | ||
787 | return 0; | ||
760 | } | 788 | } |
789 | |||
761 | if (lpfc_issue_els_fdisc(vport, ndlp, 0)) { | 790 | if (lpfc_issue_els_fdisc(vport, ndlp, 0)) { |
762 | /* decrement node reference count to trigger the release of | 791 | /* decrement node reference count to trigger the release of |
763 | * the node. | 792 | * the node. |
@@ -816,7 +845,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, | |||
816 | */ | 845 | */ |
817 | new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName); | 846 | new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName); |
818 | 847 | ||
819 | if (new_ndlp == ndlp) | 848 | if (new_ndlp == ndlp && NLP_CHK_NODE_ACT(new_ndlp)) |
820 | return ndlp; | 849 | return ndlp; |
821 | 850 | ||
822 | if (!new_ndlp) { | 851 | if (!new_ndlp) { |
@@ -827,8 +856,12 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, | |||
827 | new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC); | 856 | new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC); |
828 | if (!new_ndlp) | 857 | if (!new_ndlp) |
829 | return ndlp; | 858 | return ndlp; |
830 | |||
831 | lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID); | 859 | lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID); |
860 | } else if (!NLP_CHK_NODE_ACT(new_ndlp)) { | ||
861 | new_ndlp = lpfc_enable_node(vport, new_ndlp, | ||
862 | NLP_STE_UNUSED_NODE); | ||
863 | if (!new_ndlp) | ||
864 | return ndlp; | ||
832 | } | 865 | } |
833 | 866 | ||
834 | lpfc_unreg_rpi(vport, new_ndlp); | 867 | lpfc_unreg_rpi(vport, new_ndlp); |
@@ -839,6 +872,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, | |||
839 | new_ndlp->nlp_flag |= NLP_NPR_2B_DISC; | 872 | new_ndlp->nlp_flag |= NLP_NPR_2B_DISC; |
840 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | 873 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; |
841 | 874 | ||
875 | /* Set state will put new_ndlp on to node list if not already done */ | ||
842 | lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); | 876 | lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); |
843 | 877 | ||
844 | /* Move this back to NPR state */ | 878 | /* Move this back to NPR state */ |
@@ -912,7 +946,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
912 | irsp->un.elsreq64.remoteID); | 946 | irsp->un.elsreq64.remoteID); |
913 | 947 | ||
914 | ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); | 948 | ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); |
915 | if (!ndlp) { | 949 | if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { |
916 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | 950 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, |
917 | "0136 PLOGI completes to NPort x%x " | 951 | "0136 PLOGI completes to NPort x%x " |
918 | "with no ndlp. Data: x%x x%x x%x\n", | 952 | "with no ndlp. Data: x%x x%x x%x\n", |
@@ -962,12 +996,11 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
962 | } | 996 | } |
963 | /* PLOGI failed */ | 997 | /* PLOGI failed */ |
964 | /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ | 998 | /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ |
965 | if (lpfc_error_lost_link(irsp)) { | 999 | if (lpfc_error_lost_link(irsp)) |
966 | rc = NLP_STE_FREED_NODE; | 1000 | rc = NLP_STE_FREED_NODE; |
967 | } else { | 1001 | else |
968 | rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb, | 1002 | rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb, |
969 | NLP_EVT_CMPL_PLOGI); | 1003 | NLP_EVT_CMPL_PLOGI); |
970 | } | ||
971 | } else { | 1004 | } else { |
972 | /* Good status, call state machine */ | 1005 | /* Good status, call state machine */ |
973 | prsp = list_entry(((struct lpfc_dmabuf *) | 1006 | prsp = list_entry(((struct lpfc_dmabuf *) |
@@ -1015,8 +1048,10 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) | |||
1015 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ | 1048 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ |
1016 | 1049 | ||
1017 | ndlp = lpfc_findnode_did(vport, did); | 1050 | ndlp = lpfc_findnode_did(vport, did); |
1018 | /* If ndlp if not NULL, we will bump the reference count on it */ | 1051 | if (ndlp && !NLP_CHK_NODE_ACT(ndlp)) |
1052 | ndlp = NULL; | ||
1019 | 1053 | ||
1054 | /* If ndlp is not NULL, we will bump the reference count on it */ | ||
1020 | cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); | 1055 | cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); |
1021 | elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did, | 1056 | elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did, |
1022 | ELS_CMD_PLOGI); | 1057 | ELS_CMD_PLOGI); |
@@ -1097,18 +1132,15 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
1097 | } | 1132 | } |
1098 | /* PRLI failed */ | 1133 | /* PRLI failed */ |
1099 | /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ | 1134 | /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ |
1100 | if (lpfc_error_lost_link(irsp)) { | 1135 | if (lpfc_error_lost_link(irsp)) |
1101 | goto out; | 1136 | goto out; |
1102 | } else { | 1137 | else |
1103 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, | 1138 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, |
1104 | NLP_EVT_CMPL_PRLI); | 1139 | NLP_EVT_CMPL_PRLI); |
1105 | } | 1140 | } else |
1106 | } else { | ||
1107 | /* Good status, call state machine */ | 1141 | /* Good status, call state machine */ |
1108 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, | 1142 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, |
1109 | NLP_EVT_CMPL_PRLI); | 1143 | NLP_EVT_CMPL_PRLI); |
1110 | } | ||
1111 | |||
1112 | out: | 1144 | out: |
1113 | lpfc_els_free_iocb(phba, cmdiocb); | 1145 | lpfc_els_free_iocb(phba, cmdiocb); |
1114 | return; | 1146 | return; |
@@ -1275,15 +1307,13 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
1275 | } | 1307 | } |
1276 | /* ADISC failed */ | 1308 | /* ADISC failed */ |
1277 | /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ | 1309 | /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ |
1278 | if (!lpfc_error_lost_link(irsp)) { | 1310 | if (!lpfc_error_lost_link(irsp)) |
1279 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, | 1311 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, |
1280 | NLP_EVT_CMPL_ADISC); | 1312 | NLP_EVT_CMPL_ADISC); |
1281 | } | 1313 | } else |
1282 | } else { | ||
1283 | /* Good status, call state machine */ | 1314 | /* Good status, call state machine */ |
1284 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, | 1315 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, |
1285 | NLP_EVT_CMPL_ADISC); | 1316 | NLP_EVT_CMPL_ADISC); |
1286 | } | ||
1287 | 1317 | ||
1288 | if (disc && vport->num_disc_nodes) { | 1318 | if (disc && vport->num_disc_nodes) { |
1289 | /* Check to see if there are more ADISCs to be sent */ | 1319 | /* Check to see if there are more ADISCs to be sent */ |
@@ -1443,14 +1473,12 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
1443 | else | 1473 | else |
1444 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, | 1474 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, |
1445 | NLP_EVT_CMPL_LOGO); | 1475 | NLP_EVT_CMPL_LOGO); |
1446 | } else { | 1476 | } else |
1447 | /* Good status, call state machine. | 1477 | /* Good status, call state machine. |
1448 | * This will unregister the rpi if needed. | 1478 | * This will unregister the rpi if needed. |
1449 | */ | 1479 | */ |
1450 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, | 1480 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, |
1451 | NLP_EVT_CMPL_LOGO); | 1481 | NLP_EVT_CMPL_LOGO); |
1452 | } | ||
1453 | |||
1454 | out: | 1482 | out: |
1455 | lpfc_els_free_iocb(phba, cmdiocb); | 1483 | lpfc_els_free_iocb(phba, cmdiocb); |
1456 | return; | 1484 | return; |
@@ -1556,11 +1584,19 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) | |||
1556 | psli = &phba->sli; | 1584 | psli = &phba->sli; |
1557 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ | 1585 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ |
1558 | cmdsize = (sizeof(uint32_t) + sizeof(SCR)); | 1586 | cmdsize = (sizeof(uint32_t) + sizeof(SCR)); |
1559 | ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); | ||
1560 | if (!ndlp) | ||
1561 | return 1; | ||
1562 | 1587 | ||
1563 | lpfc_nlp_init(vport, ndlp, nportid); | 1588 | ndlp = lpfc_findnode_did(vport, nportid); |
1589 | if (!ndlp) { | ||
1590 | ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); | ||
1591 | if (!ndlp) | ||
1592 | return 1; | ||
1593 | lpfc_nlp_init(vport, ndlp, nportid); | ||
1594 | lpfc_enqueue_node(vport, ndlp); | ||
1595 | } else if (!NLP_CHK_NODE_ACT(ndlp)) { | ||
1596 | ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); | ||
1597 | if (!ndlp) | ||
1598 | return 1; | ||
1599 | } | ||
1564 | 1600 | ||
1565 | elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, | 1601 | elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, |
1566 | ndlp->nlp_DID, ELS_CMD_SCR); | 1602 | ndlp->nlp_DID, ELS_CMD_SCR); |
@@ -1623,11 +1659,19 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) | |||
1623 | psli = &phba->sli; | 1659 | psli = &phba->sli; |
1624 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ | 1660 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ |
1625 | cmdsize = (sizeof(uint32_t) + sizeof(FARP)); | 1661 | cmdsize = (sizeof(uint32_t) + sizeof(FARP)); |
1626 | ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); | ||
1627 | if (!ndlp) | ||
1628 | return 1; | ||
1629 | 1662 | ||
1630 | lpfc_nlp_init(vport, ndlp, nportid); | 1663 | ndlp = lpfc_findnode_did(vport, nportid); |
1664 | if (!ndlp) { | ||
1665 | ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); | ||
1666 | if (!ndlp) | ||
1667 | return 1; | ||
1668 | lpfc_nlp_init(vport, ndlp, nportid); | ||
1669 | lpfc_enqueue_node(vport, ndlp); | ||
1670 | } else if (!NLP_CHK_NODE_ACT(ndlp)) { | ||
1671 | ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); | ||
1672 | if (!ndlp) | ||
1673 | return 1; | ||
1674 | } | ||
1631 | 1675 | ||
1632 | elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, | 1676 | elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, |
1633 | ndlp->nlp_DID, ELS_CMD_RNID); | 1677 | ndlp->nlp_DID, ELS_CMD_RNID); |
@@ -1657,7 +1701,7 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) | |||
1657 | memcpy(&fp->RportName, &vport->fc_portname, sizeof(struct lpfc_name)); | 1701 | memcpy(&fp->RportName, &vport->fc_portname, sizeof(struct lpfc_name)); |
1658 | memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); | 1702 | memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); |
1659 | ondlp = lpfc_findnode_did(vport, nportid); | 1703 | ondlp = lpfc_findnode_did(vport, nportid); |
1660 | if (ondlp) { | 1704 | if (ondlp && NLP_CHK_NODE_ACT(ondlp)) { |
1661 | memcpy(&fp->OportName, &ondlp->nlp_portname, | 1705 | memcpy(&fp->OportName, &ondlp->nlp_portname, |
1662 | sizeof(struct lpfc_name)); | 1706 | sizeof(struct lpfc_name)); |
1663 | memcpy(&fp->OnodeName, &ondlp->nlp_nodename, | 1707 | memcpy(&fp->OnodeName, &ondlp->nlp_nodename, |
@@ -1690,6 +1734,7 @@ void | |||
1690 | lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) | 1734 | lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) |
1691 | { | 1735 | { |
1692 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 1736 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
1737 | struct lpfc_work_evt *evtp; | ||
1693 | 1738 | ||
1694 | spin_lock_irq(shost->host_lock); | 1739 | spin_lock_irq(shost->host_lock); |
1695 | nlp->nlp_flag &= ~NLP_DELAY_TMO; | 1740 | nlp->nlp_flag &= ~NLP_DELAY_TMO; |
@@ -1697,8 +1742,12 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) | |||
1697 | del_timer_sync(&nlp->nlp_delayfunc); | 1742 | del_timer_sync(&nlp->nlp_delayfunc); |
1698 | nlp->nlp_last_elscmd = 0; | 1743 | nlp->nlp_last_elscmd = 0; |
1699 | 1744 | ||
1700 | if (!list_empty(&nlp->els_retry_evt.evt_listp)) | 1745 | if (!list_empty(&nlp->els_retry_evt.evt_listp)) { |
1701 | list_del_init(&nlp->els_retry_evt.evt_listp); | 1746 | list_del_init(&nlp->els_retry_evt.evt_listp); |
1747 | /* Decrement nlp reference count held for the delayed retry */ | ||
1748 | evtp = &nlp->els_retry_evt; | ||
1749 | lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); | ||
1750 | } | ||
1702 | 1751 | ||
1703 | if (nlp->nlp_flag & NLP_NPR_2B_DISC) { | 1752 | if (nlp->nlp_flag & NLP_NPR_2B_DISC) { |
1704 | spin_lock_irq(shost->host_lock); | 1753 | spin_lock_irq(shost->host_lock); |
@@ -1842,13 +1891,14 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
1842 | cmd = *elscmd++; | 1891 | cmd = *elscmd++; |
1843 | } | 1892 | } |
1844 | 1893 | ||
1845 | if (ndlp) | 1894 | if (ndlp && NLP_CHK_NODE_ACT(ndlp)) |
1846 | did = ndlp->nlp_DID; | 1895 | did = ndlp->nlp_DID; |
1847 | else { | 1896 | else { |
1848 | /* We should only hit this case for retrying PLOGI */ | 1897 | /* We should only hit this case for retrying PLOGI */ |
1849 | did = irsp->un.elsreq64.remoteID; | 1898 | did = irsp->un.elsreq64.remoteID; |
1850 | ndlp = lpfc_findnode_did(vport, did); | 1899 | ndlp = lpfc_findnode_did(vport, did); |
1851 | if (!ndlp && (cmd != ELS_CMD_PLOGI)) | 1900 | if ((!ndlp || !NLP_CHK_NODE_ACT(ndlp)) |
1901 | && (cmd != ELS_CMD_PLOGI)) | ||
1852 | return 1; | 1902 | return 1; |
1853 | } | 1903 | } |
1854 | 1904 | ||
@@ -2322,6 +2372,9 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
2322 | if ((rspiocb->iocb.ulpStatus == 0) | 2372 | if ((rspiocb->iocb.ulpStatus == 0) |
2323 | && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { | 2373 | && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { |
2324 | lpfc_unreg_rpi(vport, ndlp); | 2374 | lpfc_unreg_rpi(vport, ndlp); |
2375 | /* Increment reference count to ndlp to hold the | ||
2376 | * reference to ndlp for the callback function. | ||
2377 | */ | ||
2325 | mbox->context2 = lpfc_nlp_get(ndlp); | 2378 | mbox->context2 = lpfc_nlp_get(ndlp); |
2326 | mbox->vport = vport; | 2379 | mbox->vport = vport; |
2327 | if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) { | 2380 | if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) { |
@@ -2335,9 +2388,13 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
2335 | NLP_STE_REG_LOGIN_ISSUE); | 2388 | NLP_STE_REG_LOGIN_ISSUE); |
2336 | } | 2389 | } |
2337 | if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) | 2390 | if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) |
2338 | != MBX_NOT_FINISHED) { | 2391 | != MBX_NOT_FINISHED) |
2339 | goto out; | 2392 | goto out; |
2340 | } | 2393 | else |
2394 | /* Decrement the ndlp reference count we | ||
2395 | * set for this failed mailbox command. | ||
2396 | */ | ||
2397 | lpfc_nlp_put(ndlp); | ||
2341 | 2398 | ||
2342 | /* ELS rsp: Cannot issue reg_login for <NPortid> */ | 2399 | /* ELS rsp: Cannot issue reg_login for <NPortid> */ |
2343 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | 2400 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, |
@@ -2796,6 +2853,8 @@ lpfc_els_disc_adisc(struct lpfc_vport *vport) | |||
2796 | 2853 | ||
2797 | /* go thru NPR nodes and issue any remaining ELS ADISCs */ | 2854 | /* go thru NPR nodes and issue any remaining ELS ADISCs */ |
2798 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { | 2855 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { |
2856 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
2857 | continue; | ||
2799 | if (ndlp->nlp_state == NLP_STE_NPR_NODE && | 2858 | if (ndlp->nlp_state == NLP_STE_NPR_NODE && |
2800 | (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && | 2859 | (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && |
2801 | (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) { | 2860 | (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) { |
@@ -2833,6 +2892,8 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) | |||
2833 | 2892 | ||
2834 | /* go thru NPR nodes and issue any remaining ELS PLOGIs */ | 2893 | /* go thru NPR nodes and issue any remaining ELS PLOGIs */ |
2835 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { | 2894 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { |
2895 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
2896 | continue; | ||
2836 | if (ndlp->nlp_state == NLP_STE_NPR_NODE && | 2897 | if (ndlp->nlp_state == NLP_STE_NPR_NODE && |
2837 | (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && | 2898 | (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && |
2838 | (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 && | 2899 | (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 && |
@@ -2943,7 +3004,8 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) | |||
2943 | */ | 3004 | */ |
2944 | 3005 | ||
2945 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { | 3006 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { |
2946 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE || | 3007 | if (!NLP_CHK_NODE_ACT(ndlp) || |
3008 | ndlp->nlp_state == NLP_STE_UNUSED_NODE || | ||
2947 | lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0) | 3009 | lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0) |
2948 | continue; | 3010 | continue; |
2949 | 3011 | ||
@@ -3145,7 +3207,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) | |||
3145 | vport->num_disc_nodes = 0; | 3207 | vport->num_disc_nodes = 0; |
3146 | 3208 | ||
3147 | ndlp = lpfc_findnode_did(vport, NameServer_DID); | 3209 | ndlp = lpfc_findnode_did(vport, NameServer_DID); |
3148 | if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { | 3210 | if (ndlp && NLP_CHK_NODE_ACT(ndlp) |
3211 | && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { | ||
3149 | /* Good ndlp, issue CT Request to NameServer */ | 3212 | /* Good ndlp, issue CT Request to NameServer */ |
3150 | if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0) == 0) | 3213 | if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0) == 0) |
3151 | /* Wait for NameServer query cmpl before we can | 3214 | /* Wait for NameServer query cmpl before we can |
@@ -3155,25 +3218,35 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) | |||
3155 | /* If login to NameServer does not exist, issue one */ | 3218 | /* If login to NameServer does not exist, issue one */ |
3156 | /* Good status, issue PLOGI to NameServer */ | 3219 | /* Good status, issue PLOGI to NameServer */ |
3157 | ndlp = lpfc_findnode_did(vport, NameServer_DID); | 3220 | ndlp = lpfc_findnode_did(vport, NameServer_DID); |
3158 | if (ndlp) | 3221 | if (ndlp && NLP_CHK_NODE_ACT(ndlp)) |
3159 | /* Wait for NameServer login cmpl before we can | 3222 | /* Wait for NameServer login cmpl before we can |
3160 | continue */ | 3223 | continue */ |
3161 | return 1; | 3224 | return 1; |
3162 | 3225 | ||
3163 | ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); | 3226 | if (ndlp) { |
3164 | if (!ndlp) { | 3227 | ndlp = lpfc_enable_node(vport, ndlp, |
3165 | lpfc_els_flush_rscn(vport); | 3228 | NLP_STE_PLOGI_ISSUE); |
3166 | return 0; | 3229 | if (!ndlp) { |
3230 | lpfc_els_flush_rscn(vport); | ||
3231 | return 0; | ||
3232 | } | ||
3233 | ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; | ||
3167 | } else { | 3234 | } else { |
3235 | ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); | ||
3236 | if (!ndlp) { | ||
3237 | lpfc_els_flush_rscn(vport); | ||
3238 | return 0; | ||
3239 | } | ||
3168 | lpfc_nlp_init(vport, ndlp, NameServer_DID); | 3240 | lpfc_nlp_init(vport, ndlp, NameServer_DID); |
3169 | ndlp->nlp_type |= NLP_FABRIC; | ||
3170 | ndlp->nlp_prev_state = ndlp->nlp_state; | 3241 | ndlp->nlp_prev_state = ndlp->nlp_state; |
3171 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); | 3242 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); |
3172 | lpfc_issue_els_plogi(vport, NameServer_DID, 0); | ||
3173 | /* Wait for NameServer login cmpl before we can | ||
3174 | continue */ | ||
3175 | return 1; | ||
3176 | } | 3243 | } |
3244 | ndlp->nlp_type |= NLP_FABRIC; | ||
3245 | lpfc_issue_els_plogi(vport, NameServer_DID, 0); | ||
3246 | /* Wait for NameServer login cmpl before we can | ||
3247 | * continue | ||
3248 | */ | ||
3249 | return 1; | ||
3177 | } | 3250 | } |
3178 | 3251 | ||
3179 | lpfc_els_flush_rscn(vport); | 3252 | lpfc_els_flush_rscn(vport); |
@@ -3672,6 +3745,8 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
3672 | 3745 | ||
3673 | list_for_each_entry_safe(ndlp, next_ndlp, | 3746 | list_for_each_entry_safe(ndlp, next_ndlp, |
3674 | &vport->fc_nodes, nlp_listp) { | 3747 | &vport->fc_nodes, nlp_listp) { |
3748 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
3749 | continue; | ||
3675 | if (ndlp->nlp_state != NLP_STE_NPR_NODE) | 3750 | if (ndlp->nlp_state != NLP_STE_NPR_NODE) |
3676 | continue; | 3751 | continue; |
3677 | if (ndlp->nlp_type & NLP_FABRIC) { | 3752 | if (ndlp->nlp_type & NLP_FABRIC) { |
@@ -3697,6 +3772,8 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
3697 | */ | 3772 | */ |
3698 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, | 3773 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, |
3699 | nlp_listp) { | 3774 | nlp_listp) { |
3775 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
3776 | continue; | ||
3700 | if (ndlp->nlp_state != NLP_STE_NPR_NODE) | 3777 | if (ndlp->nlp_state != NLP_STE_NPR_NODE) |
3701 | continue; | 3778 | continue; |
3702 | 3779 | ||
@@ -3936,7 +4013,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3936 | uint32_t cmd, did, newnode, rjt_err = 0; | 4013 | uint32_t cmd, did, newnode, rjt_err = 0; |
3937 | IOCB_t *icmd = &elsiocb->iocb; | 4014 | IOCB_t *icmd = &elsiocb->iocb; |
3938 | 4015 | ||
3939 | if (vport == NULL || elsiocb->context2 == NULL) | 4016 | if (!vport || !(elsiocb->context2)) |
3940 | goto dropit; | 4017 | goto dropit; |
3941 | 4018 | ||
3942 | newnode = 0; | 4019 | newnode = 0; |
@@ -3971,14 +4048,20 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3971 | lpfc_nlp_init(vport, ndlp, did); | 4048 | lpfc_nlp_init(vport, ndlp, did); |
3972 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | 4049 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); |
3973 | newnode = 1; | 4050 | newnode = 1; |
3974 | if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) { | 4051 | if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) |
3975 | ndlp->nlp_type |= NLP_FABRIC; | 4052 | ndlp->nlp_type |= NLP_FABRIC; |
4053 | } else { | ||
4054 | if (!NLP_CHK_NODE_ACT(ndlp)) { | ||
4055 | ndlp = lpfc_enable_node(vport, ndlp, | ||
4056 | NLP_STE_UNUSED_NODE); | ||
4057 | if (!ndlp) | ||
4058 | goto dropit; | ||
3976 | } | 4059 | } |
3977 | } | ||
3978 | else { | ||
3979 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { | 4060 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { |
3980 | /* This is simular to the new node path */ | 4061 | /* This is simular to the new node path */ |
3981 | lpfc_nlp_get(ndlp); | 4062 | ndlp = lpfc_nlp_get(ndlp); |
4063 | if (!ndlp) | ||
4064 | goto dropit; | ||
3982 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | 4065 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); |
3983 | newnode = 1; | 4066 | newnode = 1; |
3984 | } | 4067 | } |
@@ -3987,6 +4070,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3987 | phba->fc_stat.elsRcvFrame++; | 4070 | phba->fc_stat.elsRcvFrame++; |
3988 | if (elsiocb->context1) | 4071 | if (elsiocb->context1) |
3989 | lpfc_nlp_put(elsiocb->context1); | 4072 | lpfc_nlp_put(elsiocb->context1); |
4073 | |||
3990 | elsiocb->context1 = lpfc_nlp_get(ndlp); | 4074 | elsiocb->context1 = lpfc_nlp_get(ndlp); |
3991 | elsiocb->vport = vport; | 4075 | elsiocb->vport = vport; |
3992 | 4076 | ||
@@ -4314,6 +4398,18 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) | |||
4314 | } | 4398 | } |
4315 | lpfc_nlp_init(vport, ndlp, NameServer_DID); | 4399 | lpfc_nlp_init(vport, ndlp, NameServer_DID); |
4316 | ndlp->nlp_type |= NLP_FABRIC; | 4400 | ndlp->nlp_type |= NLP_FABRIC; |
4401 | } else if (!NLP_CHK_NODE_ACT(ndlp)) { | ||
4402 | ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); | ||
4403 | if (!ndlp) { | ||
4404 | if (phba->fc_topology == TOPOLOGY_LOOP) { | ||
4405 | lpfc_disc_start(vport); | ||
4406 | return; | ||
4407 | } | ||
4408 | lpfc_vport_set_state(vport, FC_VPORT_FAILED); | ||
4409 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | ||
4410 | "0348 NameServer login: node freed\n"); | ||
4411 | return; | ||
4412 | } | ||
4317 | } | 4413 | } |
4318 | 4414 | ||
4319 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); | 4415 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); |
@@ -4471,7 +4567,6 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
4471 | irsp->ulpStatus, irsp->un.ulpWord[4]); | 4567 | irsp->ulpStatus, irsp->un.ulpWord[4]); |
4472 | if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING) | 4568 | if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING) |
4473 | lpfc_vport_set_state(vport, FC_VPORT_FAILED); | 4569 | lpfc_vport_set_state(vport, FC_VPORT_FAILED); |
4474 | |||
4475 | lpfc_nlp_put(ndlp); | 4570 | lpfc_nlp_put(ndlp); |
4476 | /* giving up on FDISC. Cancel discovery timer */ | 4571 | /* giving up on FDISC. Cancel discovery timer */ |
4477 | lpfc_can_disctmo(vport); | 4572 | lpfc_can_disctmo(vport); |
@@ -4492,8 +4587,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
4492 | */ | 4587 | */ |
4493 | list_for_each_entry_safe(np, next_np, | 4588 | list_for_each_entry_safe(np, next_np, |
4494 | &vport->fc_nodes, nlp_listp) { | 4589 | &vport->fc_nodes, nlp_listp) { |
4495 | if (np->nlp_state != NLP_STE_NPR_NODE | 4590 | if (!NLP_CHK_NODE_ACT(ndlp) || |
4496 | || !(np->nlp_flag & NLP_NPR_ADISC)) | 4591 | (np->nlp_state != NLP_STE_NPR_NODE) || |
4592 | !(np->nlp_flag & NLP_NPR_ADISC)) | ||
4497 | continue; | 4593 | continue; |
4498 | spin_lock_irq(shost->host_lock); | 4594 | spin_lock_irq(shost->host_lock); |
4499 | np->nlp_flag &= ~NLP_NPR_ADISC; | 4595 | np->nlp_flag &= ~NLP_NPR_ADISC; |
@@ -4599,6 +4695,8 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
4599 | { | 4695 | { |
4600 | struct lpfc_vport *vport = cmdiocb->vport; | 4696 | struct lpfc_vport *vport = cmdiocb->vport; |
4601 | IOCB_t *irsp; | 4697 | IOCB_t *irsp; |
4698 | struct lpfc_nodelist *ndlp; | ||
4699 | ndlp = (struct lpfc_nodelist *)cmdiocb->context1; | ||
4602 | 4700 | ||
4603 | irsp = &rspiocb->iocb; | 4701 | irsp = &rspiocb->iocb; |
4604 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, | 4702 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, |
@@ -4607,6 +4705,9 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
4607 | 4705 | ||
4608 | lpfc_els_free_iocb(phba, cmdiocb); | 4706 | lpfc_els_free_iocb(phba, cmdiocb); |
4609 | vport->unreg_vpi_cmpl = VPORT_ERROR; | 4707 | vport->unreg_vpi_cmpl = VPORT_ERROR; |
4708 | |||
4709 | /* Trigger the release of the ndlp after logo */ | ||
4710 | lpfc_nlp_put(ndlp); | ||
4610 | } | 4711 | } |
4611 | 4712 | ||
4612 | int | 4713 | int |
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index dc042bd97baa..1ee3e62c78a7 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))) |
@@ -684,20 +684,21 @@ lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport) | |||
684 | struct lpfc_nodelist *ndlp; | 684 | struct lpfc_nodelist *ndlp; |
685 | 685 | ||
686 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { | 686 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { |
687 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
688 | continue; | ||
687 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | 689 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) |
688 | continue; | 690 | continue; |
689 | |||
690 | if (ndlp->nlp_type & NLP_FABRIC) { | 691 | if (ndlp->nlp_type & NLP_FABRIC) { |
691 | /* On Linkup its safe to clean up the ndlp | 692 | /* On Linkup its safe to clean up the ndlp |
692 | * from Fabric connections. | 693 | * from Fabric connections. |
693 | */ | 694 | */ |
694 | if (ndlp->nlp_DID != Fabric_DID) | 695 | if (ndlp->nlp_DID != Fabric_DID) |
695 | lpfc_unreg_rpi(vport, ndlp); | 696 | lpfc_unreg_rpi(vport, ndlp); |
696 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | 697 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); |
697 | } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { | 698 | } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { |
698 | /* Fail outstanding IO now since device is | 699 | /* Fail outstanding IO now since device is |
699 | * marked for PLOGI. | 700 | * marked for PLOGI. |
700 | */ | 701 | */ |
701 | lpfc_unreg_rpi(vport, ndlp); | 702 | lpfc_unreg_rpi(vport, ndlp); |
702 | } | 703 | } |
703 | } | 704 | } |
@@ -1305,7 +1306,6 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1305 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 1306 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
1306 | kfree(mp); | 1307 | kfree(mp); |
1307 | mempool_free(pmb, phba->mbox_mem_pool); | 1308 | mempool_free(pmb, phba->mbox_mem_pool); |
1308 | lpfc_nlp_put(ndlp); | ||
1309 | 1309 | ||
1310 | if (phba->fc_topology == TOPOLOGY_LOOP) { | 1310 | if (phba->fc_topology == TOPOLOGY_LOOP) { |
1311 | /* FLOGI failed, use loop map to make discovery list */ | 1311 | /* FLOGI failed, use loop map to make discovery list */ |
@@ -1313,6 +1313,10 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1313 | 1313 | ||
1314 | /* Start discovery */ | 1314 | /* Start discovery */ |
1315 | lpfc_disc_start(vport); | 1315 | lpfc_disc_start(vport); |
1316 | /* Decrement the reference count to ndlp after the | ||
1317 | * reference to the ndlp are done. | ||
1318 | */ | ||
1319 | lpfc_nlp_put(ndlp); | ||
1316 | return; | 1320 | return; |
1317 | } | 1321 | } |
1318 | 1322 | ||
@@ -1320,6 +1324,10 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1320 | lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, | 1324 | lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, |
1321 | "0258 Register Fabric login error: 0x%x\n", | 1325 | "0258 Register Fabric login error: 0x%x\n", |
1322 | mb->mbxStatus); | 1326 | mb->mbxStatus); |
1327 | /* Decrement the reference count to ndlp after the reference | ||
1328 | * to the ndlp are done. | ||
1329 | */ | ||
1330 | lpfc_nlp_put(ndlp); | ||
1323 | return; | 1331 | return; |
1324 | } | 1332 | } |
1325 | 1333 | ||
@@ -1327,8 +1335,6 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1327 | ndlp->nlp_type |= NLP_FABRIC; | 1335 | ndlp->nlp_type |= NLP_FABRIC; |
1328 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); | 1336 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); |
1329 | 1337 | ||
1330 | lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */ | ||
1331 | |||
1332 | if (vport->port_state == LPFC_FABRIC_CFG_LINK) { | 1338 | if (vport->port_state == LPFC_FABRIC_CFG_LINK) { |
1333 | vports = lpfc_create_vport_work_array(phba); | 1339 | vports = lpfc_create_vport_work_array(phba); |
1334 | if (vports != NULL) | 1340 | if (vports != NULL) |
@@ -1356,6 +1362,11 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1356 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 1362 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
1357 | kfree(mp); | 1363 | kfree(mp); |
1358 | mempool_free(pmb, phba->mbox_mem_pool); | 1364 | mempool_free(pmb, phba->mbox_mem_pool); |
1365 | |||
1366 | /* Drop the reference count from the mbox at the end after | ||
1367 | * all the current reference to the ndlp have been done. | ||
1368 | */ | ||
1369 | lpfc_nlp_put(ndlp); | ||
1359 | return; | 1370 | return; |
1360 | } | 1371 | } |
1361 | 1372 | ||
@@ -1463,9 +1474,8 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1463 | * registered the port. | 1474 | * registered the port. |
1464 | */ | 1475 | */ |
1465 | if (ndlp->rport && ndlp->rport->dd_data && | 1476 | if (ndlp->rport && ndlp->rport->dd_data && |
1466 | ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) { | 1477 | ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) |
1467 | lpfc_nlp_put(ndlp); | 1478 | lpfc_nlp_put(ndlp); |
1468 | } | ||
1469 | 1479 | ||
1470 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, | 1480 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, |
1471 | "rport add: did:x%x flg:x%x type x%x", | 1481 | "rport add: did:x%x flg:x%x type x%x", |
@@ -1660,6 +1670,18 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1660 | } | 1670 | } |
1661 | 1671 | ||
1662 | void | 1672 | void |
1673 | lpfc_enqueue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | ||
1674 | { | ||
1675 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
1676 | |||
1677 | if (list_empty(&ndlp->nlp_listp)) { | ||
1678 | spin_lock_irq(shost->host_lock); | ||
1679 | list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); | ||
1680 | spin_unlock_irq(shost->host_lock); | ||
1681 | } | ||
1682 | } | ||
1683 | |||
1684 | void | ||
1663 | lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | 1685 | lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) |
1664 | { | 1686 | { |
1665 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 1687 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
@@ -1672,7 +1694,80 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1672 | list_del_init(&ndlp->nlp_listp); | 1694 | list_del_init(&ndlp->nlp_listp); |
1673 | spin_unlock_irq(shost->host_lock); | 1695 | spin_unlock_irq(shost->host_lock); |
1674 | lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, | 1696 | lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, |
1675 | NLP_STE_UNUSED_NODE); | 1697 | NLP_STE_UNUSED_NODE); |
1698 | } | ||
1699 | |||
1700 | void | ||
1701 | lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | ||
1702 | { | ||
1703 | if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) | ||
1704 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
1705 | if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) | ||
1706 | lpfc_nlp_counters(vport, ndlp->nlp_state, -1); | ||
1707 | lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, | ||
1708 | NLP_STE_UNUSED_NODE); | ||
1709 | } | ||
1710 | |||
1711 | struct lpfc_nodelist * | ||
1712 | lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||
1713 | int state) | ||
1714 | { | ||
1715 | struct lpfc_hba *phba = vport->phba; | ||
1716 | uint32_t did; | ||
1717 | unsigned long flags; | ||
1718 | |||
1719 | if (!ndlp) | ||
1720 | return NULL; | ||
1721 | |||
1722 | spin_lock_irqsave(&phba->ndlp_lock, flags); | ||
1723 | /* The ndlp should not be in memory free mode */ | ||
1724 | if (NLP_CHK_FREE_REQ(ndlp)) { | ||
1725 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
1726 | lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, | ||
1727 | "0277 lpfc_enable_node: ndlp:x%p " | ||
1728 | "usgmap:x%x refcnt:%d\n", | ||
1729 | (void *)ndlp, ndlp->nlp_usg_map, | ||
1730 | atomic_read(&ndlp->kref.refcount)); | ||
1731 | return NULL; | ||
1732 | } | ||
1733 | /* The ndlp should not already be in active mode */ | ||
1734 | if (NLP_CHK_NODE_ACT(ndlp)) { | ||
1735 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
1736 | lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, | ||
1737 | "0278 lpfc_enable_node: ndlp:x%p " | ||
1738 | "usgmap:x%x refcnt:%d\n", | ||
1739 | (void *)ndlp, ndlp->nlp_usg_map, | ||
1740 | atomic_read(&ndlp->kref.refcount)); | ||
1741 | return NULL; | ||
1742 | } | ||
1743 | |||
1744 | /* Keep the original DID */ | ||
1745 | did = ndlp->nlp_DID; | ||
1746 | |||
1747 | /* re-initialize ndlp except of ndlp linked list pointer */ | ||
1748 | memset((((char *)ndlp) + sizeof (struct list_head)), 0, | ||
1749 | sizeof (struct lpfc_nodelist) - sizeof (struct list_head)); | ||
1750 | INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); | ||
1751 | INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); | ||
1752 | init_timer(&ndlp->nlp_delayfunc); | ||
1753 | ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; | ||
1754 | ndlp->nlp_delayfunc.data = (unsigned long)ndlp; | ||
1755 | ndlp->nlp_DID = did; | ||
1756 | ndlp->vport = vport; | ||
1757 | ndlp->nlp_sid = NLP_NO_SID; | ||
1758 | /* ndlp management re-initialize */ | ||
1759 | kref_init(&ndlp->kref); | ||
1760 | NLP_INT_NODE_ACT(ndlp); | ||
1761 | |||
1762 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
1763 | |||
1764 | if (state != NLP_STE_UNUSED_NODE) | ||
1765 | lpfc_nlp_set_state(vport, ndlp, state); | ||
1766 | |||
1767 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, | ||
1768 | "node enable: did:x%x", | ||
1769 | ndlp->nlp_DID, 0, 0); | ||
1770 | return ndlp; | ||
1676 | } | 1771 | } |
1677 | 1772 | ||
1678 | void | 1773 | void |
@@ -1972,7 +2067,21 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1972 | "Data: x%x x%x x%x\n", | 2067 | "Data: x%x x%x x%x\n", |
1973 | ndlp->nlp_DID, ndlp->nlp_flag, | 2068 | ndlp->nlp_DID, ndlp->nlp_flag, |
1974 | ndlp->nlp_state, ndlp->nlp_rpi); | 2069 | ndlp->nlp_state, ndlp->nlp_rpi); |
1975 | lpfc_dequeue_node(vport, ndlp); | 2070 | if (NLP_CHK_FREE_REQ(ndlp)) { |
2071 | lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, | ||
2072 | "0280 lpfc_cleanup_node: ndlp:x%p " | ||
2073 | "usgmap:x%x refcnt:%d\n", | ||
2074 | (void *)ndlp, ndlp->nlp_usg_map, | ||
2075 | atomic_read(&ndlp->kref.refcount)); | ||
2076 | lpfc_dequeue_node(vport, ndlp); | ||
2077 | } else { | ||
2078 | lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, | ||
2079 | "0281 lpfc_cleanup_node: ndlp:x%p " | ||
2080 | "usgmap:x%x refcnt:%d\n", | ||
2081 | (void *)ndlp, ndlp->nlp_usg_map, | ||
2082 | atomic_read(&ndlp->kref.refcount)); | ||
2083 | lpfc_disable_node(vport, ndlp); | ||
2084 | } | ||
1976 | 2085 | ||
1977 | /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ | 2086 | /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ |
1978 | if ((mb = phba->sli.mbox_active)) { | 2087 | if ((mb = phba->sli.mbox_active)) { |
@@ -1994,12 +2103,16 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1994 | } | 2103 | } |
1995 | list_del(&mb->list); | 2104 | list_del(&mb->list); |
1996 | mempool_free(mb, phba->mbox_mem_pool); | 2105 | mempool_free(mb, phba->mbox_mem_pool); |
1997 | lpfc_nlp_put(ndlp); | 2106 | /* We shall not invoke the lpfc_nlp_put to decrement |
2107 | * the ndlp reference count as we are in the process | ||
2108 | * of lpfc_nlp_release. | ||
2109 | */ | ||
1998 | } | 2110 | } |
1999 | } | 2111 | } |
2000 | spin_unlock_irq(&phba->hbalock); | 2112 | spin_unlock_irq(&phba->hbalock); |
2001 | 2113 | ||
2002 | lpfc_els_abort(phba,ndlp); | 2114 | lpfc_els_abort(phba, ndlp); |
2115 | |||
2003 | spin_lock_irq(shost->host_lock); | 2116 | spin_lock_irq(shost->host_lock); |
2004 | ndlp->nlp_flag &= ~NLP_DELAY_TMO; | 2117 | ndlp->nlp_flag &= ~NLP_DELAY_TMO; |
2005 | spin_unlock_irq(shost->host_lock); | 2118 | spin_unlock_irq(shost->host_lock); |
@@ -2057,7 +2170,6 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
2057 | } | 2170 | } |
2058 | } | 2171 | } |
2059 | } | 2172 | } |
2060 | |||
2061 | lpfc_cleanup_node(vport, ndlp); | 2173 | lpfc_cleanup_node(vport, ndlp); |
2062 | 2174 | ||
2063 | /* | 2175 | /* |
@@ -2182,7 +2294,16 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) | |||
2182 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | 2294 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; |
2183 | spin_unlock_irq(shost->host_lock); | 2295 | spin_unlock_irq(shost->host_lock); |
2184 | return ndlp; | 2296 | return ndlp; |
2297 | } else if (!NLP_CHK_NODE_ACT(ndlp)) { | ||
2298 | ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE); | ||
2299 | if (!ndlp) | ||
2300 | return NULL; | ||
2301 | spin_lock_irq(shost->host_lock); | ||
2302 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | ||
2303 | spin_unlock_irq(shost->host_lock); | ||
2304 | return ndlp; | ||
2185 | } | 2305 | } |
2306 | |||
2186 | if (vport->fc_flag & FC_RSCN_MODE) { | 2307 | if (vport->fc_flag & FC_RSCN_MODE) { |
2187 | if (lpfc_rscn_payload_check(vport, did)) { | 2308 | if (lpfc_rscn_payload_check(vport, did)) { |
2188 | /* If we've already recieved a PLOGI from this NPort | 2309 | /* If we've already recieved a PLOGI from this NPort |
@@ -2485,6 +2606,8 @@ lpfc_disc_flush_list(struct lpfc_vport *vport) | |||
2485 | if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) { | 2606 | if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) { |
2486 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, | 2607 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, |
2487 | nlp_listp) { | 2608 | nlp_listp) { |
2609 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
2610 | continue; | ||
2488 | if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || | 2611 | if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || |
2489 | ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { | 2612 | ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { |
2490 | lpfc_free_tx(phba, ndlp); | 2613 | lpfc_free_tx(phba, ndlp); |
@@ -2572,6 +2695,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
2572 | /* Start discovery by sending FLOGI, clean up old rpis */ | 2695 | /* Start discovery by sending FLOGI, clean up old rpis */ |
2573 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, | 2696 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, |
2574 | nlp_listp) { | 2697 | nlp_listp) { |
2698 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
2699 | continue; | ||
2575 | if (ndlp->nlp_state != NLP_STE_NPR_NODE) | 2700 | if (ndlp->nlp_state != NLP_STE_NPR_NODE) |
2576 | continue; | 2701 | continue; |
2577 | if (ndlp->nlp_type & NLP_FABRIC) { | 2702 | if (ndlp->nlp_type & NLP_FABRIC) { |
@@ -2618,7 +2743,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
2618 | "NameServer login\n"); | 2743 | "NameServer login\n"); |
2619 | /* Next look for NameServer ndlp */ | 2744 | /* Next look for NameServer ndlp */ |
2620 | ndlp = lpfc_findnode_did(vport, NameServer_DID); | 2745 | ndlp = lpfc_findnode_did(vport, NameServer_DID); |
2621 | if (ndlp) | 2746 | if (ndlp && NLP_CHK_NODE_ACT(ndlp)) |
2622 | lpfc_els_abort(phba, ndlp); | 2747 | lpfc_els_abort(phba, ndlp); |
2623 | 2748 | ||
2624 | /* ReStart discovery */ | 2749 | /* ReStart discovery */ |
@@ -2897,6 +3022,7 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
2897 | ndlp->nlp_sid = NLP_NO_SID; | 3022 | ndlp->nlp_sid = NLP_NO_SID; |
2898 | INIT_LIST_HEAD(&ndlp->nlp_listp); | 3023 | INIT_LIST_HEAD(&ndlp->nlp_listp); |
2899 | kref_init(&ndlp->kref); | 3024 | kref_init(&ndlp->kref); |
3025 | NLP_INT_NODE_ACT(ndlp); | ||
2900 | 3026 | ||
2901 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, | 3027 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, |
2902 | "node init: did:x%x", | 3028 | "node init: did:x%x", |
@@ -2911,6 +3037,8 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
2911 | static void | 3037 | static void |
2912 | lpfc_nlp_release(struct kref *kref) | 3038 | lpfc_nlp_release(struct kref *kref) |
2913 | { | 3039 | { |
3040 | struct lpfc_hba *phba; | ||
3041 | unsigned long flags; | ||
2914 | struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, | 3042 | struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, |
2915 | kref); | 3043 | kref); |
2916 | 3044 | ||
@@ -2918,8 +3046,24 @@ lpfc_nlp_release(struct kref *kref) | |||
2918 | "node release: did:x%x flg:x%x type:x%x", | 3046 | "node release: did:x%x flg:x%x type:x%x", |
2919 | ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); | 3047 | ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); |
2920 | 3048 | ||
3049 | lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, | ||
3050 | "0279 lpfc_nlp_release: ndlp:x%p " | ||
3051 | "usgmap:x%x refcnt:%d\n", | ||
3052 | (void *)ndlp, ndlp->nlp_usg_map, | ||
3053 | atomic_read(&ndlp->kref.refcount)); | ||
3054 | |||
3055 | /* remove ndlp from action. */ | ||
2921 | lpfc_nlp_remove(ndlp->vport, ndlp); | 3056 | lpfc_nlp_remove(ndlp->vport, ndlp); |
2922 | mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); | 3057 | |
3058 | /* clear the ndlp active flag for all release cases */ | ||
3059 | phba = ndlp->vport->phba; | ||
3060 | spin_lock_irqsave(&phba->ndlp_lock, flags); | ||
3061 | NLP_CLR_NODE_ACT(ndlp); | ||
3062 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
3063 | |||
3064 | /* free ndlp memory for final ndlp release */ | ||
3065 | if (NLP_CHK_FREE_REQ(ndlp)) | ||
3066 | mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); | ||
2923 | } | 3067 | } |
2924 | 3068 | ||
2925 | /* This routine bumps the reference count for a ndlp structure to ensure | 3069 | /* This routine bumps the reference count for a ndlp structure to ensure |
@@ -2929,37 +3073,108 @@ lpfc_nlp_release(struct kref *kref) | |||
2929 | struct lpfc_nodelist * | 3073 | struct lpfc_nodelist * |
2930 | lpfc_nlp_get(struct lpfc_nodelist *ndlp) | 3074 | lpfc_nlp_get(struct lpfc_nodelist *ndlp) |
2931 | { | 3075 | { |
3076 | struct lpfc_hba *phba; | ||
3077 | unsigned long flags; | ||
3078 | |||
2932 | if (ndlp) { | 3079 | if (ndlp) { |
2933 | lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, | 3080 | lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, |
2934 | "node get: did:x%x flg:x%x refcnt:x%x", | 3081 | "node get: did:x%x flg:x%x refcnt:x%x", |
2935 | ndlp->nlp_DID, ndlp->nlp_flag, | 3082 | ndlp->nlp_DID, ndlp->nlp_flag, |
2936 | atomic_read(&ndlp->kref.refcount)); | 3083 | atomic_read(&ndlp->kref.refcount)); |
2937 | kref_get(&ndlp->kref); | 3084 | /* The check of ndlp usage to prevent incrementing the |
3085 | * ndlp reference count that is in the process of being | ||
3086 | * released. | ||
3087 | */ | ||
3088 | phba = ndlp->vport->phba; | ||
3089 | spin_lock_irqsave(&phba->ndlp_lock, flags); | ||
3090 | if (!NLP_CHK_NODE_ACT(ndlp) || NLP_CHK_FREE_ACK(ndlp)) { | ||
3091 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
3092 | lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, | ||
3093 | "0276 lpfc_nlp_get: ndlp:x%p " | ||
3094 | "usgmap:x%x refcnt:%d\n", | ||
3095 | (void *)ndlp, ndlp->nlp_usg_map, | ||
3096 | atomic_read(&ndlp->kref.refcount)); | ||
3097 | return NULL; | ||
3098 | } else | ||
3099 | kref_get(&ndlp->kref); | ||
3100 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
2938 | } | 3101 | } |
2939 | return ndlp; | 3102 | return ndlp; |
2940 | } | 3103 | } |
2941 | 3104 | ||
2942 | |||
2943 | /* This routine decrements the reference count for a ndlp structure. If the | 3105 | /* 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. | 3106 | * count goes to 0, this indicates the the associated nodelist should be |
3107 | * freed. Returning 1 indicates the ndlp resource has been released; on the | ||
3108 | * other hand, returning 0 indicates the ndlp resource has not been released | ||
3109 | * yet. | ||
2945 | */ | 3110 | */ |
2946 | int | 3111 | int |
2947 | lpfc_nlp_put(struct lpfc_nodelist *ndlp) | 3112 | lpfc_nlp_put(struct lpfc_nodelist *ndlp) |
2948 | { | 3113 | { |
2949 | if (ndlp) { | 3114 | struct lpfc_hba *phba; |
2950 | lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, | 3115 | unsigned long flags; |
2951 | "node put: did:x%x flg:x%x refcnt:x%x", | 3116 | |
2952 | ndlp->nlp_DID, ndlp->nlp_flag, | 3117 | if (!ndlp) |
2953 | atomic_read(&ndlp->kref.refcount)); | 3118 | return 1; |
3119 | |||
3120 | lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, | ||
3121 | "node put: did:x%x flg:x%x refcnt:x%x", | ||
3122 | ndlp->nlp_DID, ndlp->nlp_flag, | ||
3123 | atomic_read(&ndlp->kref.refcount)); | ||
3124 | phba = ndlp->vport->phba; | ||
3125 | spin_lock_irqsave(&phba->ndlp_lock, flags); | ||
3126 | /* Check the ndlp memory free acknowledge flag to avoid the | ||
3127 | * possible race condition that kref_put got invoked again | ||
3128 | * after previous one has done ndlp memory free. | ||
3129 | */ | ||
3130 | if (NLP_CHK_FREE_ACK(ndlp)) { | ||
3131 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
3132 | lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, | ||
3133 | "0274 lpfc_nlp_put: ndlp:x%p " | ||
3134 | "usgmap:x%x refcnt:%d\n", | ||
3135 | (void *)ndlp, ndlp->nlp_usg_map, | ||
3136 | atomic_read(&ndlp->kref.refcount)); | ||
3137 | return 1; | ||
3138 | } | ||
3139 | /* Check the ndlp inactivate log flag to avoid the possible | ||
3140 | * race condition that kref_put got invoked again after ndlp | ||
3141 | * is already in inactivating state. | ||
3142 | */ | ||
3143 | if (NLP_CHK_IACT_REQ(ndlp)) { | ||
3144 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
3145 | lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, | ||
3146 | "0275 lpfc_nlp_put: ndlp:x%p " | ||
3147 | "usgmap:x%x refcnt:%d\n", | ||
3148 | (void *)ndlp, ndlp->nlp_usg_map, | ||
3149 | atomic_read(&ndlp->kref.refcount)); | ||
3150 | return 1; | ||
2954 | } | 3151 | } |
2955 | return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0; | 3152 | /* For last put, mark the ndlp usage flags to make sure no |
3153 | * other kref_get and kref_put on the same ndlp shall get | ||
3154 | * in between the process when the final kref_put has been | ||
3155 | * invoked on this ndlp. | ||
3156 | */ | ||
3157 | if (atomic_read(&ndlp->kref.refcount) == 1) { | ||
3158 | /* Indicate ndlp is put to inactive state. */ | ||
3159 | NLP_SET_IACT_REQ(ndlp); | ||
3160 | /* Acknowledge ndlp memory free has been seen. */ | ||
3161 | if (NLP_CHK_FREE_REQ(ndlp)) | ||
3162 | NLP_SET_FREE_ACK(ndlp); | ||
3163 | } | ||
3164 | spin_unlock_irqrestore(&phba->ndlp_lock, flags); | ||
3165 | /* Note, the kref_put returns 1 when decrementing a reference | ||
3166 | * count that was 1, it invokes the release callback function, | ||
3167 | * but it still left the reference count as 1 (not actually | ||
3168 | * performs the last decrementation). Otherwise, it actually | ||
3169 | * decrements the reference count and returns 0. | ||
3170 | */ | ||
3171 | return kref_put(&ndlp->kref, lpfc_nlp_release); | ||
2956 | } | 3172 | } |
2957 | 3173 | ||
2958 | /* This routine free's the specified nodelist if it is not in use | 3174 | /* 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 | 3175 | * 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 | 3176 | * 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 | 3177 | * not yet been released. |
2962 | * refcount is left unchanged. | ||
2963 | */ | 3178 | */ |
2964 | int | 3179 | int |
2965 | lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) | 3180 | lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) |
@@ -2968,11 +3183,8 @@ lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) | |||
2968 | "node not used: did:x%x flg:x%x refcnt:x%x", | 3183 | "node not used: did:x%x flg:x%x refcnt:x%x", |
2969 | ndlp->nlp_DID, ndlp->nlp_flag, | 3184 | ndlp->nlp_DID, ndlp->nlp_flag, |
2970 | atomic_read(&ndlp->kref.refcount)); | 3185 | atomic_read(&ndlp->kref.refcount)); |
2971 | 3186 | if (atomic_read(&ndlp->kref.refcount) == 1) | |
2972 | if (atomic_read(&ndlp->kref.refcount) == 1) { | 3187 | if (lpfc_nlp_put(ndlp)) |
2973 | lpfc_nlp_put(ndlp); | 3188 | return 1; |
2974 | return 1; | ||
2975 | } | ||
2976 | return 0; | 3189 | return 0; |
2977 | } | 3190 | } |
2978 | |||
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 6cfeba7454d4..e0363bef6d29 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.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 * |
@@ -1422,9 +1422,32 @@ lpfc_cleanup(struct lpfc_vport *vport) | |||
1422 | lpfc_port_link_failure(vport); | 1422 | lpfc_port_link_failure(vport); |
1423 | 1423 | ||
1424 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { | 1424 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { |
1425 | if (!NLP_CHK_NODE_ACT(ndlp)) { | ||
1426 | ndlp = lpfc_enable_node(vport, ndlp, | ||
1427 | NLP_STE_UNUSED_NODE); | ||
1428 | if (!ndlp) | ||
1429 | continue; | ||
1430 | spin_lock_irq(&phba->ndlp_lock); | ||
1431 | NLP_SET_FREE_REQ(ndlp); | ||
1432 | spin_unlock_irq(&phba->ndlp_lock); | ||
1433 | /* Trigger the release of the ndlp memory */ | ||
1434 | lpfc_nlp_put(ndlp); | ||
1435 | continue; | ||
1436 | } | ||
1437 | spin_lock_irq(&phba->ndlp_lock); | ||
1438 | if (NLP_CHK_FREE_REQ(ndlp)) { | ||
1439 | /* The ndlp should not be in memory free mode already */ | ||
1440 | spin_unlock_irq(&phba->ndlp_lock); | ||
1441 | continue; | ||
1442 | } else | ||
1443 | /* Indicate request for freeing ndlp memory */ | ||
1444 | NLP_SET_FREE_REQ(ndlp); | ||
1445 | spin_unlock_irq(&phba->ndlp_lock); | ||
1446 | |||
1425 | if (ndlp->nlp_type & NLP_FABRIC) | 1447 | if (ndlp->nlp_type & NLP_FABRIC) |
1426 | lpfc_disc_state_machine(vport, ndlp, NULL, | 1448 | lpfc_disc_state_machine(vport, ndlp, NULL, |
1427 | NLP_EVT_DEVICE_RECOVERY); | 1449 | NLP_EVT_DEVICE_RECOVERY); |
1450 | |||
1428 | lpfc_disc_state_machine(vport, ndlp, NULL, | 1451 | lpfc_disc_state_machine(vport, ndlp, NULL, |
1429 | NLP_EVT_DEVICE_RM); | 1452 | NLP_EVT_DEVICE_RM); |
1430 | } | 1453 | } |
@@ -1438,6 +1461,17 @@ lpfc_cleanup(struct lpfc_vport *vport) | |||
1438 | if (i++ > 3000) { | 1461 | if (i++ > 3000) { |
1439 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, | 1462 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, |
1440 | "0233 Nodelist not empty\n"); | 1463 | "0233 Nodelist not empty\n"); |
1464 | list_for_each_entry_safe(ndlp, next_ndlp, | ||
1465 | &vport->fc_nodes, nlp_listp) { | ||
1466 | lpfc_printf_vlog(ndlp->vport, KERN_ERR, | ||
1467 | LOG_NODE, | ||
1468 | "0282: did:x%x ndlp:x%p " | ||
1469 | "usgmap:x%x refcnt:%d\n", | ||
1470 | ndlp->nlp_DID, (void *)ndlp, | ||
1471 | ndlp->nlp_usg_map, | ||
1472 | atomic_read( | ||
1473 | &ndlp->kref.refcount)); | ||
1474 | } | ||
1441 | break; | 1475 | break; |
1442 | } | 1476 | } |
1443 | 1477 | ||
@@ -1586,6 +1620,8 @@ lpfc_offline_prep(struct lpfc_hba * phba) | |||
1586 | list_for_each_entry_safe(ndlp, next_ndlp, | 1620 | list_for_each_entry_safe(ndlp, next_ndlp, |
1587 | &vports[i]->fc_nodes, | 1621 | &vports[i]->fc_nodes, |
1588 | nlp_listp) { | 1622 | nlp_listp) { |
1623 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
1624 | continue; | ||
1589 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | 1625 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) |
1590 | continue; | 1626 | continue; |
1591 | if (ndlp->nlp_type & NLP_FABRIC) { | 1627 | if (ndlp->nlp_type & NLP_FABRIC) { |
@@ -1905,6 +1941,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
1905 | 1941 | ||
1906 | spin_lock_init(&phba->hbalock); | 1942 | spin_lock_init(&phba->hbalock); |
1907 | 1943 | ||
1944 | /* Initialize ndlp management spinlock */ | ||
1945 | spin_lock_init(&phba->ndlp_lock); | ||
1946 | |||
1908 | phba->pcidev = pdev; | 1947 | phba->pcidev = pdev; |
1909 | 1948 | ||
1910 | /* Assign an unused board number */ | 1949 | /* Assign an unused board number */ |
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 4a0e3406e37a..01d548375811 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.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 * |
@@ -249,6 +249,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
249 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 249 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
250 | struct lpfc_hba *phba = vport->phba; | 250 | struct lpfc_hba *phba = vport->phba; |
251 | struct lpfc_dmabuf *pcmd; | 251 | struct lpfc_dmabuf *pcmd; |
252 | struct lpfc_work_evt *evtp; | ||
252 | uint32_t *lp; | 253 | uint32_t *lp; |
253 | IOCB_t *icmd; | 254 | IOCB_t *icmd; |
254 | struct serv_parm *sp; | 255 | struct serv_parm *sp; |
@@ -435,8 +436,14 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
435 | del_timer_sync(&ndlp->nlp_delayfunc); | 436 | del_timer_sync(&ndlp->nlp_delayfunc); |
436 | ndlp->nlp_last_elscmd = 0; | 437 | ndlp->nlp_last_elscmd = 0; |
437 | 438 | ||
438 | if (!list_empty(&ndlp->els_retry_evt.evt_listp)) | 439 | if (!list_empty(&ndlp->els_retry_evt.evt_listp)) { |
439 | list_del_init(&ndlp->els_retry_evt.evt_listp); | 440 | list_del_init(&ndlp->els_retry_evt.evt_listp); |
441 | /* Decrement ndlp reference count held for the | ||
442 | * delayed retry | ||
443 | */ | ||
444 | evtp = &ndlp->els_retry_evt; | ||
445 | lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); | ||
446 | } | ||
440 | 447 | ||
441 | if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { | 448 | if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { |
442 | spin_lock_irq(shost->host_lock); | 449 | spin_lock_irq(shost->host_lock); |
@@ -656,7 +663,7 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
656 | void *arg, uint32_t evt) | 663 | void *arg, uint32_t evt) |
657 | { | 664 | { |
658 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, | 665 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, |
659 | "0253 Illegal State Transition: node x%x " | 666 | "0271 Illegal State Transition: node x%x " |
660 | "event x%x, state x%x Data: x%x x%x\n", | 667 | "event x%x, state x%x Data: x%x x%x\n", |
661 | ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, | 668 | ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, |
662 | ndlp->nlp_flag); | 669 | ndlp->nlp_flag); |
@@ -674,7 +681,7 @@ lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
674 | */ | 681 | */ |
675 | if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { | 682 | if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { |
676 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, | 683 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, |
677 | "0253 Illegal State Transition: node x%x " | 684 | "0272 Illegal State Transition: node x%x " |
678 | "event x%x, state x%x Data: x%x x%x\n", | 685 | "event x%x, state x%x Data: x%x x%x\n", |
679 | ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, | 686 | ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, |
680 | ndlp->nlp_flag); | 687 | ndlp->nlp_flag); |
@@ -2144,8 +2151,11 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
2144 | uint32_t cur_state, rc; | 2151 | uint32_t cur_state, rc; |
2145 | uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *, | 2152 | uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *, |
2146 | uint32_t); | 2153 | uint32_t); |
2154 | uint32_t got_ndlp = 0; | ||
2155 | |||
2156 | if (lpfc_nlp_get(ndlp)) | ||
2157 | got_ndlp = 1; | ||
2147 | 2158 | ||
2148 | lpfc_nlp_get(ndlp); | ||
2149 | cur_state = ndlp->nlp_state; | 2159 | cur_state = ndlp->nlp_state; |
2150 | 2160 | ||
2151 | /* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */ | 2161 | /* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */ |
@@ -2162,15 +2172,24 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
2162 | rc = (func) (vport, ndlp, arg, evt); | 2172 | rc = (func) (vport, ndlp, arg, evt); |
2163 | 2173 | ||
2164 | /* DSM out state <rc> on NPort <nlp_DID> */ | 2174 | /* DSM out state <rc> on NPort <nlp_DID> */ |
2165 | lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, | 2175 | if (got_ndlp) { |
2176 | lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, | ||
2166 | "0212 DSM out state %d on NPort x%x Data: x%x\n", | 2177 | "0212 DSM out state %d on NPort x%x Data: x%x\n", |
2167 | rc, ndlp->nlp_DID, ndlp->nlp_flag); | 2178 | rc, ndlp->nlp_DID, ndlp->nlp_flag); |
2168 | 2179 | ||
2169 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, | 2180 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, |
2170 | "DSM out: ste:%d did:x%x flg:x%x", | 2181 | "DSM out: ste:%d did:x%x flg:x%x", |
2171 | rc, ndlp->nlp_DID, ndlp->nlp_flag); | 2182 | rc, ndlp->nlp_DID, ndlp->nlp_flag); |
2183 | /* Decrement the ndlp reference count held for this function */ | ||
2184 | lpfc_nlp_put(ndlp); | ||
2185 | } else { | ||
2186 | lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, | ||
2187 | "0212 DSM out state %d on NPort free\n", rc); | ||
2172 | 2188 | ||
2173 | lpfc_nlp_put(ndlp); | 2189 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, |
2190 | "DSM out: ste:%d did:x%x flg:x%x", | ||
2191 | rc, 0, 0); | ||
2192 | } | ||
2174 | 2193 | ||
2175 | return rc; | 2194 | return rc; |
2176 | } | 2195 | } |
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index fc5c3a42b05a..70255c11d3ad 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.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 * |
@@ -1283,6 +1283,8 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | |||
1283 | match = 0; | 1283 | match = 0; |
1284 | spin_lock_irq(shost->host_lock); | 1284 | spin_lock_irq(shost->host_lock); |
1285 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { | 1285 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { |
1286 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
1287 | continue; | ||
1286 | if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && | 1288 | if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && |
1287 | i == ndlp->nlp_sid && | 1289 | i == ndlp->nlp_sid && |
1288 | ndlp->rport) { | 1290 | ndlp->rport) { |
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 9fad7663c117..86d05beb00b8 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.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-2006 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 * |
@@ -327,7 +327,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) | |||
327 | * up and ready to FDISC. | 327 | * up and ready to FDISC. |
328 | */ | 328 | */ |
329 | ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); | 329 | ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); |
330 | if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { | 330 | if (ndlp && NLP_CHK_NODE_ACT(ndlp) && |
331 | ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { | ||
331 | if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { | 332 | if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { |
332 | lpfc_set_disctmo(vport); | 333 | lpfc_set_disctmo(vport); |
333 | lpfc_initial_fdisc(vport); | 334 | lpfc_initial_fdisc(vport); |
@@ -358,7 +359,8 @@ disable_vport(struct fc_vport *fc_vport) | |||
358 | long timeout; | 359 | long timeout; |
359 | 360 | ||
360 | ndlp = lpfc_findnode_did(vport, Fabric_DID); | 361 | ndlp = lpfc_findnode_did(vport, Fabric_DID); |
361 | if (ndlp && phba->link_state >= LPFC_LINK_UP) { | 362 | if (ndlp && NLP_CHK_NODE_ACT(ndlp) |
363 | && phba->link_state >= LPFC_LINK_UP) { | ||
362 | vport->unreg_vpi_cmpl = VPORT_INVAL; | 364 | vport->unreg_vpi_cmpl = VPORT_INVAL; |
363 | timeout = msecs_to_jiffies(phba->fc_ratov * 2000); | 365 | timeout = msecs_to_jiffies(phba->fc_ratov * 2000); |
364 | if (!lpfc_issue_els_npiv_logo(vport, ndlp)) | 366 | if (!lpfc_issue_els_npiv_logo(vport, ndlp)) |
@@ -372,6 +374,8 @@ disable_vport(struct fc_vport *fc_vport) | |||
372 | * calling lpfc_cleanup_rpis(vport, 1) | 374 | * calling lpfc_cleanup_rpis(vport, 1) |
373 | */ | 375 | */ |
374 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { | 376 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { |
377 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
378 | continue; | ||
375 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | 379 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) |
376 | continue; | 380 | continue; |
377 | lpfc_disc_state_machine(vport, ndlp, NULL, | 381 | lpfc_disc_state_machine(vport, ndlp, NULL, |
@@ -414,7 +418,8 @@ enable_vport(struct fc_vport *fc_vport) | |||
414 | * up and ready to FDISC. | 418 | * up and ready to FDISC. |
415 | */ | 419 | */ |
416 | ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); | 420 | ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); |
417 | if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { | 421 | if (ndlp && NLP_CHK_NODE_ACT(ndlp) |
422 | && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { | ||
418 | if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { | 423 | if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { |
419 | lpfc_set_disctmo(vport); | 424 | lpfc_set_disctmo(vport); |
420 | lpfc_initial_fdisc(vport); | 425 | lpfc_initial_fdisc(vport); |
@@ -498,7 +503,41 @@ lpfc_vport_delete(struct fc_vport *fc_vport) | |||
498 | scsi_remove_host(lpfc_shost_from_vport(vport)); | 503 | scsi_remove_host(lpfc_shost_from_vport(vport)); |
499 | 504 | ||
500 | ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); | 505 | ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); |
501 | if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && | 506 | |
507 | /* In case of driver unload, we shall not perform fabric logo as the | ||
508 | * worker thread already stopped at this stage and, in this case, we | ||
509 | * can safely skip the fabric logo. | ||
510 | */ | ||
511 | if (phba->pport->load_flag & FC_UNLOADING) { | ||
512 | if (ndlp && NLP_CHK_NODE_ACT(ndlp) && | ||
513 | ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && | ||
514 | phba->link_state >= LPFC_LINK_UP) { | ||
515 | /* First look for the Fabric ndlp */ | ||
516 | ndlp = lpfc_findnode_did(vport, Fabric_DID); | ||
517 | if (!ndlp) | ||
518 | goto skip_logo; | ||
519 | else if (!NLP_CHK_NODE_ACT(ndlp)) { | ||
520 | ndlp = lpfc_enable_node(vport, ndlp, | ||
521 | NLP_STE_UNUSED_NODE); | ||
522 | if (!ndlp) | ||
523 | goto skip_logo; | ||
524 | } | ||
525 | /* Remove ndlp from vport npld list */ | ||
526 | lpfc_dequeue_node(vport, ndlp); | ||
527 | |||
528 | /* Indicate free memory when release */ | ||
529 | spin_lock_irq(&phba->ndlp_lock); | ||
530 | NLP_SET_FREE_REQ(ndlp); | ||
531 | spin_unlock_irq(&phba->ndlp_lock); | ||
532 | /* Kick off release ndlp when it can be safely done */ | ||
533 | lpfc_nlp_put(ndlp); | ||
534 | } | ||
535 | goto skip_logo; | ||
536 | } | ||
537 | |||
538 | /* Otherwise, we will perform fabric logo as needed */ | ||
539 | if (ndlp && NLP_CHK_NODE_ACT(ndlp) && | ||
540 | ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && | ||
502 | phba->link_state >= LPFC_LINK_UP) { | 541 | phba->link_state >= LPFC_LINK_UP) { |
503 | if (vport->cfg_enable_da_id) { | 542 | if (vport->cfg_enable_da_id) { |
504 | timeout = msecs_to_jiffies(phba->fc_ratov * 2000); | 543 | timeout = msecs_to_jiffies(phba->fc_ratov * 2000); |
@@ -519,8 +558,27 @@ lpfc_vport_delete(struct fc_vport *fc_vport) | |||
519 | if (!ndlp) | 558 | if (!ndlp) |
520 | goto skip_logo; | 559 | goto skip_logo; |
521 | lpfc_nlp_init(vport, ndlp, Fabric_DID); | 560 | lpfc_nlp_init(vport, ndlp, Fabric_DID); |
561 | /* Indicate free memory when release */ | ||
562 | NLP_SET_FREE_REQ(ndlp); | ||
522 | } else { | 563 | } else { |
564 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
565 | ndlp = lpfc_enable_node(vport, ndlp, | ||
566 | NLP_STE_UNUSED_NODE); | ||
567 | if (!ndlp) | ||
568 | goto skip_logo; | ||
569 | |||
570 | /* Remove ndlp from vport npld list */ | ||
523 | lpfc_dequeue_node(vport, ndlp); | 571 | lpfc_dequeue_node(vport, ndlp); |
572 | spin_lock_irq(&phba->ndlp_lock); | ||
573 | if (!NLP_CHK_FREE_REQ(ndlp)) | ||
574 | /* Indicate free memory when release */ | ||
575 | NLP_SET_FREE_REQ(ndlp); | ||
576 | else { | ||
577 | /* Skip this if ndlp is already in free mode */ | ||
578 | spin_unlock_irq(&phba->ndlp_lock); | ||
579 | goto skip_logo; | ||
580 | } | ||
581 | spin_unlock_irq(&phba->ndlp_lock); | ||
524 | } | 582 | } |
525 | vport->unreg_vpi_cmpl = VPORT_INVAL; | 583 | vport->unreg_vpi_cmpl = VPORT_INVAL; |
526 | timeout = msecs_to_jiffies(phba->fc_ratov * 2000); | 584 | timeout = msecs_to_jiffies(phba->fc_ratov * 2000); |
@@ -534,9 +592,9 @@ skip_logo: | |||
534 | lpfc_sli_host_down(vport); | 592 | lpfc_sli_host_down(vport); |
535 | 593 | ||
536 | lpfc_stop_vport_timers(vport); | 594 | lpfc_stop_vport_timers(vport); |
537 | lpfc_unreg_all_rpis(vport); | ||
538 | 595 | ||
539 | if (!(phba->pport->load_flag & FC_UNLOADING)) { | 596 | if (!(phba->pport->load_flag & FC_UNLOADING)) { |
597 | lpfc_unreg_all_rpis(vport); | ||
540 | lpfc_unreg_default_rpis(vport); | 598 | lpfc_unreg_default_rpis(vport); |
541 | /* | 599 | /* |
542 | * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) | 600 | * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) |