aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_init.c
diff options
context:
space:
mode:
authorJames Smart <james.smart@broadcom.com>2020-11-15 11:26:33 -0800
committerMartin K. Petersen <martin.petersen@oracle.com>2020-11-17 00:43:54 -0500
commite9b1108316b9b5beee03f731c7c9c7c874e537fa (patch)
treed9dc36e090289ad3a05fc1f45121b68f7ee4bcc7 /drivers/scsi/lpfc/lpfc_init.c
parentscsi: lpfc: Fix removal of SCSI transport device get and put on dev structure (diff)
downloadlinux-dev-e9b1108316b9b5beee03f731c7c9c7c874e537fa.tar.xz
linux-dev-e9b1108316b9b5beee03f731c7c9c7c874e537fa.zip
scsi: lpfc: Fix refcounting around SCSI and NVMe transport APIs
Due to bug history and code review, the node reference counting approach in the driver isn't implemented consistently with how the scsi and nvme transport perform registrations and unregistrations and their callbacks. This resulted in many bad/stale node pointers. Reword the driver so that reference handling is performed as follows: - The initial node reference is taken on structure allocation - Take a reference on any add/register call to the transport - Remove a reference on any delete/unregister call to the transport - After the node has fully removed from both the SCSI and NVMEe transports (dev_loss_callbacks have called back) call the discovery engine DEVICE_RM event which will remove the final reference and release the node structure. - Alter dev_loss handling when a vport or base port is unloading. - Remove the put_node handling - no longer needed. - Rewrite the vport_delete handling on reference counts. Part of this effort was driven from the FDISC not registering with the transport and disrupting the model for node reference counting. - Deleted lpfc_nlp_remove. Pushed it's remaining ops into lpfc_nlp_release. - Several other small code cleanups. Link: https://lore.kernel.org/r/20201115192646.12977-5-james.smart@broadcom.com Co-developed-by: Dick Kennedy <dick.kennedy@broadcom.com> Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com> Signed-off-by: James Smart <james.smart@broadcom.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_init.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c49
1 files changed, 31 insertions, 18 deletions
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 72448287a3d1..65b9e4e06b9f 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -2859,12 +2859,17 @@ lpfc_cleanup(struct lpfc_vport *vport)
continue;
}
- if (ndlp->nlp_type & NLP_FABRIC)
+ /* Fabric Ports not in UNMAPPED state are cleaned up in the
+ * DEVICE_RM event.
+ */
+ if (ndlp->nlp_type & NLP_FABRIC &&
+ ndlp->nlp_state == NLP_STE_UNMAPPED_NODE)
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY);
- lpfc_disc_state_machine(vport, ndlp, NULL,
- NLP_EVT_DEVICE_RM);
+ if (!(ndlp->fc4_xpt_flags & (NVME_XPT_REGD|SCSI_XPT_REGD)))
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+ NLP_EVT_DEVICE_RM);
}
/* At this point, ALL ndlp's should be gone
@@ -2879,11 +2884,13 @@ lpfc_cleanup(struct lpfc_vport *vport)
list_for_each_entry_safe(ndlp, next_ndlp,
&vport->fc_nodes, nlp_listp) {
lpfc_printf_vlog(ndlp->vport, KERN_ERR,
- LOG_TRACE_EVENT,
- "0282 did:x%x ndlp:x%px "
- "refcnt:%d\n",
- ndlp->nlp_DID, (void *)ndlp,
- kref_read(&ndlp->kref));
+ LOG_TRACE_EVENT,
+ "0282 did:x%x ndlp:x%px "
+ "refcnt:%d xflags x%x nflag x%x\n",
+ ndlp->nlp_DID, (void *)ndlp,
+ kref_read(&ndlp->kref),
+ ndlp->fc4_xpt_flags,
+ ndlp->nlp_flag);
}
break;
}
@@ -3499,10 +3506,10 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action)
* comes back online.
*/
if (phba->sli_rev == LPFC_SLI_REV4) {
- lpfc_printf_vlog(ndlp->vport, KERN_INFO,
+ lpfc_printf_vlog(vports[i], KERN_INFO,
LOG_NODE | LOG_DISCOVERY,
"0011 Free RPI x%x on "
- "ndlp:x%px did x%x\n",
+ "ndlp: %p did x%x\n",
ndlp->nlp_rpi, ndlp,
ndlp->nlp_DID);
lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi);
@@ -3513,8 +3520,18 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action)
if (ndlp->nlp_type & NLP_FABRIC) {
lpfc_disc_state_machine(vports[i], ndlp,
NULL, NLP_EVT_DEVICE_RECOVERY);
- lpfc_disc_state_machine(vports[i], ndlp,
- NULL, NLP_EVT_DEVICE_RM);
+
+ /* Don't remove the node unless the
+ * has been unregistered with the
+ * transport. If so, let dev_loss
+ * take care of the node.
+ */
+ if (!(ndlp->fc4_xpt_flags &
+ (NVME_XPT_REGD | SCSI_XPT_REGD)))
+ lpfc_disc_state_machine
+ (vports[i], ndlp,
+ NULL,
+ NLP_EVT_DEVICE_RM);
}
}
}
@@ -12501,13 +12518,11 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
/* Remove FC host with the physical port */
fc_remove_host(shost);
+ scsi_remove_host(shost);
/* Clean up all nodes, mailboxes and IOs. */
lpfc_cleanup(vport);
- /* Remove the shost now that the devices connections are lost. */
- scsi_remove_host(shost);
-
/*
* Bring down the SLI Layer. This step disable all interrupts,
* clears the rings, discards all mailbox commands, and resets
@@ -13359,6 +13374,7 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
/* Remove FC host with the physical port */
fc_remove_host(shost);
+ scsi_remove_host(shost);
/* Perform ndlp cleanup on the physical port. The nvme and nvmet
* localports are destroyed after to cleanup all transport memory.
@@ -13371,9 +13387,6 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
if (phba->cfg_xri_rebalancing)
lpfc_destroy_multixri_pools(phba);
- /* Remove the shost now that the devices connections are lost. */
- scsi_remove_host(shost);
-
/*
* Bring down the SLI Layer. This step disables all interrupts,
* clears the rings, discards all mailbox commands, and resets