Commit e47c9093 authored by James Smart's avatar James Smart Committed by James Bottomley

[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: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 4660c8ed
...@@ -595,6 +595,8 @@ struct lpfc_hba { ...@@ -595,6 +595,8 @@ struct lpfc_hba {
unsigned long last_completion_time; unsigned long last_completion_time;
struct timer_list hb_tmofunc; struct timer_list hb_tmofunc;
uint8_t hb_outstanding; uint8_t hb_outstanding;
/* ndlp reference management */
spinlock_t ndlp_lock;
/* /*
* Following bit will be set for all buffer tags which are not * Following bit will be set for all buffer tags which are not
* associated with any HBQ. * associated with any HBQ.
......
...@@ -1191,7 +1191,7 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) ...@@ -1191,7 +1191,7 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport)
shost = lpfc_shost_from_vport(vport); shost = lpfc_shost_from_vport(vport);
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
if (ndlp->rport) if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport)
ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo; ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo;
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
} }
...@@ -2384,7 +2384,8 @@ lpfc_get_node_by_target(struct scsi_target *starget) ...@@ -2384,7 +2384,8 @@ lpfc_get_node_by_target(struct scsi_target *starget)
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
/* Search for this, mapped, target ID */ /* Search for this, mapped, target ID */
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && if (NLP_CHK_NODE_ACT(ndlp) &&
ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
starget->id == ndlp->nlp_sid) { starget->id == ndlp->nlp_sid) {
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
return ndlp; return ndlp;
......
/******************************************************************* /*******************************************************************
* This file is part of the Emulex Linux Device Driver for * * This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. * * Fibre Channel Host Bus Adapters. *
* Copyright (C) 2004-2007 Emulex. All rights reserved. * * Copyright (C) 2004-2008 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. * * EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com * * www.emulex.com *
* * * *
...@@ -53,7 +53,11 @@ void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *); ...@@ -53,7 +53,11 @@ void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *);
void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *);
void lpfc_disable_node(struct lpfc_vport *, struct lpfc_nodelist *);
struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *,
struct lpfc_nodelist *, int);
void lpfc_nlp_set_state(struct lpfc_vport *, struct lpfc_nodelist *, int); void lpfc_nlp_set_state(struct lpfc_vport *, struct lpfc_nodelist *, int);
void lpfc_drop_node(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_drop_node(struct lpfc_vport *, struct lpfc_nodelist *);
void lpfc_set_disctmo(struct lpfc_vport *); void lpfc_set_disctmo(struct lpfc_vport *);
......
/******************************************************************* /*******************************************************************
* This file is part of the Emulex Linux Device Driver for * * This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. * * Fibre Channel Host Bus Adapters. *
* Copyright (C) 2004-2007 Emulex. All rights reserved. * * Copyright (C) 2004-2008 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. * * EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com * * www.emulex.com *
* * * *
...@@ -294,7 +294,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, ...@@ -294,7 +294,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
/* Save for completion so we can release these resources */ /* Save for completion so we can release these resources */
geniocb->context1 = (uint8_t *) inp; geniocb->context1 = (uint8_t *) inp;
geniocb->context2 = (uint8_t *) outp; geniocb->context2 = (uint8_t *) outp;
geniocb->context_un.ndlp = ndlp; geniocb->context_un.ndlp = lpfc_nlp_get(ndlp);
/* Fill in payload, bp points to frame payload */ /* Fill in payload, bp points to frame payload */
icmd->ulpCommand = CMD_GEN_REQUEST64_CR; 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,8 +489,10 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
*/ */
ndlp = lpfc_findnode_did(vport, ndlp = lpfc_findnode_did(vport,
Did); Did);
if (ndlp && (ndlp->nlp_type & if (ndlp &&
NLP_FCP_TARGET)) NLP_CHK_NODE_ACT(ndlp)
&& (ndlp->nlp_type &
NLP_FCP_TARGET))
lpfc_setup_disc_node lpfc_setup_disc_node
(vport, Did); (vport, Did);
else if (lpfc_ns_cmd(vport, else if (lpfc_ns_cmd(vport,
...@@ -1064,7 +1066,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, ...@@ -1064,7 +1066,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
int rc = 0; int rc = 0;
ndlp = lpfc_findnode_did(vport, NameServer_DID); ndlp = lpfc_findnode_did(vport, NameServer_DID);
if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) { if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)
|| ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) {
rc=1; rc=1;
goto ns_cmd_exit; goto ns_cmd_exit;
} }
...@@ -1213,8 +1216,9 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, ...@@ -1213,8 +1216,9 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
cmpl = lpfc_cmpl_ct_cmd_rff_id; cmpl = lpfc_cmpl_ct_cmd_rff_id;
break; break;
} }
lpfc_nlp_get(ndlp); /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count
* to hold ndlp reference for the corresponding callback function.
*/
if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) { if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) {
/* On success, The cmpl function will free the buffers */ /* On success, The cmpl function will free the buffers */
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
...@@ -1222,9 +1226,13 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, ...@@ -1222,9 +1226,13 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
cmdcode, ndlp->nlp_DID, 0); cmdcode, ndlp->nlp_DID, 0);
return 0; return 0;
} }
rc=6; rc=6;
/* Decrement ndlp reference count to release ndlp reference held
* for the failed command's callback function.
*/
lpfc_nlp_put(ndlp); lpfc_nlp_put(ndlp);
lpfc_mbuf_free(phba, bmp->virt, bmp->phys); lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
ns_cmd_free_bmp: ns_cmd_free_bmp:
kfree(bmp); kfree(bmp);
...@@ -1271,6 +1279,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ...@@ -1271,6 +1279,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
} }
ndlp = lpfc_findnode_did(vport, FDMI_DID); ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
goto fail_out;
if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
/* FDMI rsp failed */ /* FDMI rsp failed */
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, 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,6 +1305,8 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA); lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
break; break;
} }
fail_out:
lpfc_ct_free_iocb(phba, cmdiocb); lpfc_ct_free_iocb(phba, cmdiocb);
return; return;
} }
...@@ -1650,12 +1663,18 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) ...@@ -1650,12 +1663,18 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
bpl->tus.w = le32_to_cpu(bpl->tus.w); bpl->tus.w = le32_to_cpu(bpl->tus.w);
cmpl = lpfc_cmpl_ct_cmd_fdmi; cmpl = lpfc_cmpl_ct_cmd_fdmi;
lpfc_nlp_get(ndlp);
/* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count
* to hold ndlp reference for the corresponding callback function.
*/
if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0)) if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0))
return 0; return 0;
/* Decrement ndlp reference count to release ndlp reference held
* for the failed command's callback function.
*/
lpfc_nlp_put(ndlp); lpfc_nlp_put(ndlp);
lpfc_mbuf_free(phba, bmp->virt, bmp->phys); lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
fdmi_cmd_free_bmp: fdmi_cmd_free_bmp:
kfree(bmp); kfree(bmp);
...@@ -1698,7 +1717,7 @@ lpfc_fdmi_timeout_handler(struct lpfc_vport *vport) ...@@ -1698,7 +1717,7 @@ lpfc_fdmi_timeout_handler(struct lpfc_vport *vport)
struct lpfc_nodelist *ndlp; struct lpfc_nodelist *ndlp;
ndlp = lpfc_findnode_did(vport, FDMI_DID); ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (ndlp) { if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
if (init_utsname()->nodename[0] != '\0') if (init_utsname()->nodename[0] != '\0')
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA); lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
else else
......
/******************************************************************* /*******************************************************************
* This file is part of the Emulex Linux Device Driver for * * This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. * * Fibre Channel Host Bus Adapters. *
* Copyright (C) 2004-2007 Emulex. All rights reserved. * * Copyright (C) 2004-2008 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. * * EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com * * www.emulex.com *
* * * *
...@@ -73,6 +73,12 @@ struct lpfc_nodelist { ...@@ -73,6 +73,12 @@ struct lpfc_nodelist {
uint8_t nlp_fcp_info; /* class info, bits 0-3 */ uint8_t nlp_fcp_info; /* class info, bits 0-3 */
#define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */ #define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */
uint16_t nlp_usg_map; /* ndlp management usage bitmap */
#define NLP_USG_NODE_ACT_BIT 0x1 /* Indicate ndlp is actively used */
#define NLP_USG_IACT_REQ_BIT 0x2 /* Request to inactivate ndlp */
#define NLP_USG_FREE_REQ_BIT 0x4 /* Request to invoke ndlp memory free */
#define NLP_USG_FREE_ACK_BIT 0x8 /* Indicate ndlp memory free invoked */
struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */
struct fc_rport *rport; /* Corresponding FC transport struct fc_rport *rport; /* Corresponding FC transport
port structure */ port structure */
...@@ -105,6 +111,31 @@ struct lpfc_nodelist { ...@@ -105,6 +111,31 @@ struct lpfc_nodelist {
#define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */ #define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */
#define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */ #define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */
/* ndlp usage management macros */
#define NLP_CHK_NODE_ACT(ndlp) (((ndlp)->nlp_usg_map \
& NLP_USG_NODE_ACT_BIT) \
&& \
!((ndlp)->nlp_usg_map \
& NLP_USG_FREE_ACK_BIT))
#define NLP_SET_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \
|= NLP_USG_NODE_ACT_BIT)
#define NLP_INT_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \
= NLP_USG_NODE_ACT_BIT)
#define NLP_CLR_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \
&= ~NLP_USG_NODE_ACT_BIT)
#define NLP_CHK_IACT_REQ(ndlp) ((ndlp)->nlp_usg_map \
& NLP_USG_IACT_REQ_BIT)
#define NLP_SET_IACT_REQ(ndlp) ((ndlp)->nlp_usg_map \
|= NLP_USG_IACT_REQ_BIT)
#define NLP_CHK_FREE_REQ(ndlp) ((ndlp)->nlp_usg_map \
& NLP_USG_FREE_REQ_BIT)
#define NLP_SET_FREE_REQ(ndlp) ((ndlp)->nlp_usg_map \
|= NLP_USG_FREE_REQ_BIT)
#define NLP_CHK_FREE_ACK(ndlp) ((ndlp)->nlp_usg_map \
& NLP_USG_FREE_ACK_BIT)
#define NLP_SET_FREE_ACK(ndlp) ((ndlp)->nlp_usg_map \
|= NLP_USG_FREE_ACK_BIT)
/* There are 4 different double linked lists nodelist entries can reside on. /* There are 4 different double linked lists nodelist entries can reside on.
* The Port Login (PLOGI) list and Address Discovery (ADISC) list are used * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used
* when Link Up discovery or Registered State Change Notification (RSCN) * when Link Up discovery or Registered State Change Notification (RSCN)
......
This diff is collapsed.
This diff is collapsed.
/******************************************************************* /*******************************************************************
* This file is part of the Emulex Linux Device Driver for * * This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. * * Fibre Channel Host Bus Adapters. *
* Copyright (C) 2004-2007 Emulex. All rights reserved. * * Copyright (C) 2004-2008 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. * * EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com * * www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig * * Portions Copyright (C) 2004-2005 Christoph Hellwig *
...@@ -1422,9 +1422,32 @@ lpfc_cleanup(struct lpfc_vport *vport) ...@@ -1422,9 +1422,32 @@ lpfc_cleanup(struct lpfc_vport *vport)
lpfc_port_link_failure(vport); lpfc_port_link_failure(vport);
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (!NLP_CHK_NODE_ACT(ndlp)) {
ndlp = lpfc_enable_node(vport, ndlp,
NLP_STE_UNUSED_NODE);
if (!ndlp)
continue;
spin_lock_irq(&phba->ndlp_lock);
NLP_SET_FREE_REQ(ndlp);
spin_unlock_irq(&phba->ndlp_lock);
/* Trigger the release of the ndlp memory */
lpfc_nlp_put(ndlp);
continue;
}
spin_lock_irq(&phba->ndlp_lock);
if (NLP_CHK_FREE_REQ(ndlp)) {
/* The ndlp should not be in memory free mode already */
spin_unlock_irq(&phba->ndlp_lock);
continue;
} else
/* Indicate request for freeing ndlp memory */
NLP_SET_FREE_REQ(ndlp);
spin_unlock_irq(&phba->ndlp_lock);
if (ndlp->nlp_type & NLP_FABRIC) if (ndlp->nlp_type & NLP_FABRIC)
lpfc_disc_state_machine(vport, ndlp, NULL, lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY); NLP_EVT_DEVICE_RECOVERY);
lpfc_disc_state_machine(vport, ndlp, NULL, lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RM); NLP_EVT_DEVICE_RM);
} }
...@@ -1438,6 +1461,17 @@ lpfc_cleanup(struct lpfc_vport *vport) ...@@ -1438,6 +1461,17 @@ lpfc_cleanup(struct lpfc_vport *vport)
if (i++ > 3000) { if (i++ > 3000) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
"0233 Nodelist not empty\n"); "0233 Nodelist not empty\n");
list_for_each_entry_safe(ndlp, next_ndlp,
&vport->fc_nodes, nlp_listp) {
lpfc_printf_vlog(ndlp->vport, KERN_ERR,
LOG_NODE,
"0282: did:x%x ndlp:x%p "
"usgmap:x%x refcnt:%d\n",
ndlp->nlp_DID, (void *)ndlp,
ndlp->nlp_usg_map,
atomic_read(
&ndlp->kref.refcount));
}
break; break;
} }
...@@ -1586,6 +1620,8 @@ lpfc_offline_prep(struct lpfc_hba * phba) ...@@ -1586,6 +1620,8 @@ lpfc_offline_prep(struct lpfc_hba * phba)
list_for_each_entry_safe(ndlp, next_ndlp, list_for_each_entry_safe(ndlp, next_ndlp,
&vports[i]->fc_nodes, &vports[i]->fc_nodes,
nlp_listp) { nlp_listp) {
if (!NLP_CHK_NODE_ACT(ndlp))
continue;
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
continue; continue;
if (ndlp->nlp_type & NLP_FABRIC) { 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,6 +1941,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
spin_lock_init(&phba->hbalock); spin_lock_init(&phba->hbalock);
/* Initialize ndlp management spinlock */
spin_lock_init(&phba->ndlp_lock);
phba->pcidev = pdev; phba->pcidev = pdev;
/* Assign an unused board number */ /* Assign an unused board number */
......
/******************************************************************* /*******************************************************************
* This file is part of the Emulex Linux Device Driver for * * This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. * * Fibre Channel Host Bus Adapters. *
* Copyright (C) 2004-2007 Emulex. All rights reserved. * * Copyright (C) 2004-2008 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. * * EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com * * www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig * * Portions Copyright (C) 2004-2005 Christoph Hellwig *
...@@ -249,6 +249,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -249,6 +249,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_hba *phba = vport->phba; struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd; struct lpfc_dmabuf *pcmd;
struct lpfc_work_evt *evtp;
uint32_t *lp; uint32_t *lp;
IOCB_t *icmd; IOCB_t *icmd;
struct serv_parm *sp; struct serv_parm *sp;
...@@ -435,8 +436,14 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -435,8 +436,14 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
del_timer_sync(&ndlp->nlp_delayfunc); del_timer_sync(&ndlp->nlp_delayfunc);
ndlp->nlp_last_elscmd = 0; ndlp->nlp_last_elscmd = 0;
if (!list_empty(&ndlp->els_retry_evt.evt_listp)) if (!list_empty(&ndlp->els_retry_evt.evt_listp)) {
list_del_init(&ndlp->els_retry_evt.evt_listp); list_del_init(&ndlp->els_retry_evt.evt_listp);
/* Decrement ndlp reference count held for the
* delayed retry
*/
evtp = &ndlp->els_retry_evt;
lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1);
}
if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
...@@ -656,7 +663,7 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -656,7 +663,7 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
void *arg, uint32_t evt) void *arg, uint32_t evt)
{ {
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
"0253 Illegal State Transition: node x%x " "0271 Illegal State Transition: node x%x "
"event x%x, state x%x Data: x%x x%x\n", "event x%x, state x%x Data: x%x x%x\n",
ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
ndlp->nlp_flag); ndlp->nlp_flag);
...@@ -674,7 +681,7 @@ lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -674,7 +681,7 @@ lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
*/ */
if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
"0253 Illegal State Transition: node x%x " "0272 Illegal State Transition: node x%x "
"event x%x, state x%x Data: x%x x%x\n", "event x%x, state x%x Data: x%x x%x\n",
ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
ndlp->nlp_flag); ndlp->nlp_flag);
...@@ -2144,8 +2151,11 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -2144,8 +2151,11 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint32_t cur_state, rc; uint32_t cur_state, rc;
uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *, uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *,
uint32_t); uint32_t);
uint32_t got_ndlp = 0;
if (lpfc_nlp_get(ndlp))
got_ndlp = 1;
lpfc_nlp_get(ndlp);
cur_state = ndlp->nlp_state; cur_state = ndlp->nlp_state;
/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */ /* 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,15 +2172,24 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
rc = (func) (vport, ndlp, arg, evt); rc = (func) (vport, ndlp, arg, evt);
/* DSM out state <rc> on NPort <nlp_DID> */ /* DSM out state <rc> on NPort <nlp_DID> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, if (got_ndlp) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
"0212 DSM out state %d on NPort x%x Data: x%x\n", "0212 DSM out state %d on NPort x%x Data: x%x\n",
rc, ndlp->nlp_DID, ndlp->nlp_flag); rc, ndlp->nlp_DID, ndlp->nlp_flag);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
"DSM out: ste:%d did:x%x flg:x%x", "DSM out: ste:%d did:x%x flg:x%x",
rc, ndlp->nlp_DID, ndlp->nlp_flag); rc, ndlp->nlp_DID, ndlp->nlp_flag);
/* Decrement the ndlp reference count held for this function */
lpfc_nlp_put(ndlp);
} else {
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
"0212 DSM out state %d on NPort free\n", rc);
lpfc_nlp_put(ndlp); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
"DSM out: ste:%d did:x%x flg:x%x",
rc, 0, 0);
}
return rc; return rc;
} }
/******************************************************************* /*******************************************************************
* This file is part of the Emulex Linux Device Driver for * * This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. * * Fibre Channel Host Bus Adapters. *
* Copyright (C) 2004-2007 Emulex. All rights reserved. * * Copyright (C) 2004-2008 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. * * EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com * * www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig * * Portions Copyright (C) 2004-2005 Christoph Hellwig *
...@@ -1283,6 +1283,8 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) ...@@ -1283,6 +1283,8 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
match = 0; match = 0;
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (!NLP_CHK_NODE_ACT(ndlp))
continue;
if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
i == ndlp->nlp_sid && i == ndlp->nlp_sid &&
ndlp->rport) { ndlp->rport) {
......
/******************************************************************* /*******************************************************************
* This file is part of the Emulex Linux Device Driver for * * This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. * * Fibre Channel Host Bus Adapters. *
* Copyright (C) 2004-2006 Emulex. All rights reserved. * * Copyright (C) 2004-2008 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. * * EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com * * www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig * * Portions Copyright (C) 2004-2005 Christoph Hellwig *
...@@ -327,7 +327,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) ...@@ -327,7 +327,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
* up and ready to FDISC. * up and ready to FDISC.
*/ */
ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) {
lpfc_set_disctmo(vport); lpfc_set_disctmo(vport);
lpfc_initial_fdisc(vport); lpfc_initial_fdisc(vport);
...@@ -358,7 +359,8 @@ disable_vport(struct fc_vport *fc_vport) ...@@ -358,7 +359,8 @@ disable_vport(struct fc_vport *fc_vport)
long timeout; long timeout;
ndlp = lpfc_findnode_did(vport, Fabric_DID); ndlp = lpfc_findnode_did(vport, Fabric_DID);
if (ndlp && phba->link_state >= LPFC_LINK_UP) { if (ndlp && NLP_CHK_NODE_ACT(ndlp)
&& phba->link_state >= LPFC_LINK_UP) {
vport->unreg_vpi_cmpl = VPORT_INVAL; vport->unreg_vpi_cmpl = VPORT_INVAL;
timeout = msecs_to_jiffies(phba->fc_ratov * 2000); timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
if (!lpfc_issue_els_npiv_logo(vport, ndlp)) if (!lpfc_issue_els_npiv_logo(vport, ndlp))
...@@ -372,6 +374,8 @@ disable_vport(struct fc_vport *fc_vport) ...@@ -372,6 +374,8 @@ disable_vport(struct fc_vport *fc_vport)
* calling lpfc_cleanup_rpis(vport, 1) * calling lpfc_cleanup_rpis(vport, 1)
*/ */
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (!NLP_CHK_NODE_ACT(ndlp))
continue;
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
continue; continue;
lpfc_disc_state_machine(vport, ndlp, NULL, lpfc_disc_state_machine(vport, ndlp, NULL,
...@@ -414,7 +418,8 @@ enable_vport(struct fc_vport *fc_vport) ...@@ -414,7 +418,8 @@ enable_vport(struct fc_vport *fc_vport)
* up and ready to FDISC. * up and ready to FDISC.
*/ */
ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (ndlp && NLP_CHK_NODE_ACT(ndlp)
&& ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) {
lpfc_set_disctmo(vport); lpfc_set_disctmo(vport);
lpfc_initial_fdisc(vport); lpfc_initial_fdisc(vport);
...@@ -498,7 +503,41 @@ lpfc_vport_delete(struct fc_vport *fc_vport) ...@@ -498,7 +503,41 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
scsi_remove_host(lpfc_shost_from_vport(vport)); scsi_remove_host(lpfc_shost_from_vport(vport));
ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
/* In case of driver unload, we shall not perform fabric logo as the
* worker thread already stopped at this stage and, in this case, we
* can safely skip the fabric logo.
*/
if (phba->pport->load_flag & FC_UNLOADING) {
if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
phba->link_state >= LPFC_LINK_UP) {
/* First look for the Fabric ndlp */
ndlp = lpfc_findnode_did(vport, Fabric_DID);
if (!ndlp)
goto skip_logo;
else if (!NLP_CHK_NODE_ACT(ndlp)) {
ndlp = lpfc_enable_node(vport, ndlp,
NLP_STE_UNUSED_NODE);
if (!ndlp)
goto skip_logo;
}
/* Remove ndlp from vport npld list */
lpfc_dequeue_node(vport, ndlp);
/* Indicate free memory when release */
spin_lock_irq(&phba->ndlp_lock);
NLP_SET_FREE_REQ(ndlp);
spin_unlock_irq(&phba->ndlp_lock);
/* Kick off release ndlp when it can be safely done */
lpfc_nlp_put(ndlp);
}
goto skip_logo;
}
/* Otherwise, we will perform fabric logo as needed */
if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
phba->link_state >= LPFC_LINK_UP) { phba->link_state >= LPFC_LINK_UP) {
if (vport->cfg_enable_da_id) { if (vport->cfg_enable_da_id) {
timeout = msecs_to_jiffies(phba->fc_ratov * 2000); timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
...@@ -519,8 +558,27 @@ lpfc_vport_delete(struct fc_vport *fc_vport) ...@@ -519,8 +558,27 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
if (!ndlp) if (!ndlp)
goto skip_logo; goto skip_logo;
lpfc_nlp_init(vport, ndlp, Fabric_DID); lpfc_nlp_init(vport, ndlp, Fabric_DID);
/* Indicate free memory when release */
NLP_SET_FREE_REQ(ndlp);
} else { } else {
if (!NLP_CHK_NODE_ACT(ndlp))
ndlp = lpfc_enable_node(vport, ndlp,
NLP_STE_UNUSED_NODE);
if (!ndlp)
goto skip_logo;
/* Remove ndlp from vport npld list */
lpfc_dequeue_node(vport, ndlp); lpfc_dequeue_node(vport, ndlp);
spin_lock_irq(&phba->ndlp_lock);
if (!NLP_CHK_FREE_REQ(ndlp))
/* Indicate free memory when release */
NLP_SET_FREE_REQ(ndlp);
else {
/* Skip this if ndlp is already in free mode */
spin_unlock_irq(&phba->ndlp_lock);
goto skip_logo;
}
spin_unlock_irq(&phba->ndlp_lock);
} }
vport->unreg_vpi_cmpl = VPORT_INVAL; vport->unreg_vpi_cmpl = VPORT_INVAL;
timeout = msecs_to_jiffies(phba->fc_ratov * 2000); timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
...@@ -534,9 +592,9 @@ lpfc_vport_delete(struct fc_vport *fc_vport) ...@@ -534,9 +592,9 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
lpfc_sli_host_down(vport); lpfc_sli_host_down(vport);
lpfc_stop_vport_timers(vport); lpfc_stop_vport_timers(vport);
lpfc_unreg_all_rpis(vport);
if (!(phba->pport->load_flag & FC_UNLOADING)) { if (!(phba->pport->load_flag & FC_UNLOADING)) {
lpfc_unreg_all_rpis(vport);
lpfc_unreg_default_rpis(vport); lpfc_unreg_default_rpis(vport);
/* /*
* Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment