mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
scsi: lpfc: Modify kref handling for Fabric Controller ndlps
Currently, there is a kref put in the lpfc_cleanup() routine that takes care of outstanding references on fabric controller ndlps in UNUSED state. While typically there is a state change from UNUSED -> REGLOGIN when the ndlp successfully logs into the fabric, there may be cases when FLOGI is unsuccessful and the ndlp will remain in UNUSED state without a registered rpi, yet the ndlp incorrectly has a kref count of one. To address this, handling of Fabric Controller ndlps are moved into the routines: lpfc_issue_els_scr(), lpfc_issue_els_rdf(), lpfc_cmpl_els_disc_cmd(). In both lpfc_issue_els_scr() and lpfc_issue_els_rdf(), if there does not exist a previously created fabric controller ndlp, an ndlp will be created. Otherwise, we can reuse the pre-existing ndlp object. In lpfc_cmpl_els_disc_cmd(), if the SCR or RDF are not successfully issued, the initial reference on the ndlp that is not registered with upper layers will be decremented with a kref_put(). Signed-off-by: Justin Tee <justin.tee@broadcom.com> Link: https://patch.msgid.link/20251106224639.139176-7-justintee8345@gmail.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
committed by
Martin K. Petersen
parent
23f4906729
commit
0b8b15a0b7
@@ -3390,11 +3390,21 @@ lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
lpfc_cmpl_els_edc(phba, cmdiocb, rspiocb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ulp_status) {
|
||||
/* ELS discovery cmd completes with error */
|
||||
lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS | LOG_CGN_MGMT,
|
||||
"4203 ELS cmd x%x error: x%x x%X\n", cmd,
|
||||
ulp_status, ulp_word4);
|
||||
|
||||
/* In the case where the ELS cmd completes with an error and
|
||||
* the node does not have RPI registered, the node is
|
||||
* outstanding and should put its initial reference.
|
||||
*/
|
||||
if ((cmd == ELS_CMD_SCR || cmd == ELS_CMD_RDF) &&
|
||||
!(ndlp->fc4_xpt_flags & SCSI_XPT_REGD) &&
|
||||
!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag))
|
||||
lpfc_nlp_put(ndlp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -3463,6 +3473,7 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry)
|
||||
uint8_t *pcmd;
|
||||
uint16_t cmdsize;
|
||||
struct lpfc_nodelist *ndlp;
|
||||
bool node_created = false;
|
||||
|
||||
cmdsize = (sizeof(uint32_t) + sizeof(SCR));
|
||||
|
||||
@@ -3472,21 +3483,21 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry)
|
||||
if (!ndlp)
|
||||
return 1;
|
||||
lpfc_enqueue_node(vport, ndlp);
|
||||
node_created = true;
|
||||
}
|
||||
|
||||
elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
|
||||
ndlp->nlp_DID, ELS_CMD_SCR);
|
||||
if (!elsiocb)
|
||||
return 1;
|
||||
goto out_node_created;
|
||||
|
||||
if (phba->sli_rev == LPFC_SLI_REV4) {
|
||||
rc = lpfc_reg_fab_ctrl_node(vport, ndlp);
|
||||
if (rc) {
|
||||
lpfc_els_free_iocb(phba, elsiocb);
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
|
||||
"0937 %s: Failed to reg fc node, rc %d\n",
|
||||
__func__, rc);
|
||||
return 1;
|
||||
goto out_free_iocb;
|
||||
}
|
||||
}
|
||||
pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
|
||||
@@ -3505,23 +3516,27 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry)
|
||||
phba->fc_stat.elsXmitSCR++;
|
||||
elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd;
|
||||
elsiocb->ndlp = lpfc_nlp_get(ndlp);
|
||||
if (!elsiocb->ndlp) {
|
||||
lpfc_els_free_iocb(phba, elsiocb);
|
||||
return 1;
|
||||
}
|
||||
if (!elsiocb->ndlp)
|
||||
goto out_free_iocb;
|
||||
|
||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
|
||||
"Issue SCR: did:x%x refcnt %d",
|
||||
ndlp->nlp_DID, kref_read(&ndlp->kref), 0);
|
||||
|
||||
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
|
||||
if (rc == IOCB_ERROR) {
|
||||
lpfc_els_free_iocb(phba, elsiocb);
|
||||
lpfc_nlp_put(ndlp);
|
||||
return 1;
|
||||
}
|
||||
if (rc == IOCB_ERROR)
|
||||
goto out_iocb_error;
|
||||
|
||||
return 0;
|
||||
|
||||
out_iocb_error:
|
||||
lpfc_nlp_put(ndlp);
|
||||
out_free_iocb:
|
||||
lpfc_els_free_iocb(phba, elsiocb);
|
||||
out_node_created:
|
||||
if (node_created)
|
||||
lpfc_nlp_put(ndlp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3734,7 +3749,12 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
|
||||
*
|
||||
* Return code
|
||||
* 0 - Successfully issued rdf command
|
||||
* 1 - Failed to issue rdf command
|
||||
* < 0 - Failed to issue rdf command
|
||||
* -EACCES - RDF not required for NPIV_PORT
|
||||
* -ENODEV - No fabric controller device available
|
||||
* -ENOMEM - No available memory
|
||||
* -EIO - The mailbox failed to complete successfully.
|
||||
*
|
||||
**/
|
||||
int
|
||||
lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
|
||||
@@ -3745,25 +3765,30 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
|
||||
struct lpfc_nodelist *ndlp;
|
||||
uint16_t cmdsize;
|
||||
int rc;
|
||||
bool node_created = false;
|
||||
int err;
|
||||
|
||||
cmdsize = sizeof(*prdf);
|
||||
|
||||
/* RDF ELS is not required on an NPIV VN_Port. */
|
||||
if (vport->port_type == LPFC_NPIV_PORT)
|
||||
return -EACCES;
|
||||
|
||||
ndlp = lpfc_findnode_did(vport, Fabric_Cntl_DID);
|
||||
if (!ndlp) {
|
||||
ndlp = lpfc_nlp_init(vport, Fabric_Cntl_DID);
|
||||
if (!ndlp)
|
||||
return -ENODEV;
|
||||
lpfc_enqueue_node(vport, ndlp);
|
||||
node_created = true;
|
||||
}
|
||||
|
||||
/* RDF ELS is not required on an NPIV VN_Port. */
|
||||
if (vport->port_type == LPFC_NPIV_PORT)
|
||||
return -EACCES;
|
||||
|
||||
elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
|
||||
ndlp->nlp_DID, ELS_CMD_RDF);
|
||||
if (!elsiocb)
|
||||
return -ENOMEM;
|
||||
if (!elsiocb) {
|
||||
err = -ENOMEM;
|
||||
goto out_node_created;
|
||||
}
|
||||
|
||||
/* Configure the payload for the supported FPIN events. */
|
||||
prdf = (struct lpfc_els_rdf_req *)elsiocb->cmd_dmabuf->virt;
|
||||
@@ -3789,8 +3814,8 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
|
||||
elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd;
|
||||
elsiocb->ndlp = lpfc_nlp_get(ndlp);
|
||||
if (!elsiocb->ndlp) {
|
||||
lpfc_els_free_iocb(phba, elsiocb);
|
||||
return -EIO;
|
||||
err = -EIO;
|
||||
goto out_free_iocb;
|
||||
}
|
||||
|
||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
|
||||
@@ -3799,11 +3824,19 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
|
||||
|
||||
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
|
||||
if (rc == IOCB_ERROR) {
|
||||
lpfc_els_free_iocb(phba, elsiocb);
|
||||
lpfc_nlp_put(ndlp);
|
||||
return -EIO;
|
||||
err = -EIO;
|
||||
goto out_iocb_error;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out_iocb_error:
|
||||
lpfc_nlp_put(ndlp);
|
||||
out_free_iocb:
|
||||
lpfc_els_free_iocb(phba, elsiocb);
|
||||
out_node_created:
|
||||
if (node_created)
|
||||
lpfc_nlp_put(ndlp);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3824,19 +3857,23 @@ static int
|
||||
lpfc_els_rcv_rdf(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
|
||||
struct lpfc_nodelist *ndlp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = lpfc_els_rsp_acc(vport, ELS_CMD_RDF, cmdiocb, ndlp, NULL);
|
||||
/* Send LS_ACC */
|
||||
if (lpfc_els_rsp_acc(vport, ELS_CMD_RDF, cmdiocb, ndlp, NULL)) {
|
||||
if (rc) {
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT,
|
||||
"1623 Failed to RDF_ACC from x%x for x%x\n",
|
||||
ndlp->nlp_DID, vport->fc_myDID);
|
||||
"1623 Failed to RDF_ACC from x%x for x%x Data: %d\n",
|
||||
ndlp->nlp_DID, vport->fc_myDID, rc);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rc = lpfc_issue_els_rdf(vport, 0);
|
||||
/* Issue new RDF for reregistering */
|
||||
if (lpfc_issue_els_rdf(vport, 0)) {
|
||||
if (rc) {
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT,
|
||||
"2623 Failed to re register RDF for x%x\n",
|
||||
vport->fc_myDID);
|
||||
"2623 Failed to re register RDF for x%x Data: %d\n",
|
||||
vport->fc_myDID, rc);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
@@ -3057,12 +3057,6 @@ lpfc_cleanup(struct lpfc_vport *vport)
|
||||
lpfc_vmid_vport_cleanup(vport);
|
||||
|
||||
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
|
||||
if (ndlp->nlp_DID == Fabric_Cntl_DID &&
|
||||
ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
|
||||
lpfc_nlp_put(ndlp);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Fabric Ports not in UNMAPPED state are cleaned up in the
|
||||
* DEVICE_RM event.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user