From 051d4b65e839c1b5dd43469b291cd1199d16bc68 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Thu, 6 Nov 2025 14:46:30 -0800 Subject: [PATCH 01/10] scsi: lpfc: Update various NPIV diagnostic log messaging Update PRLI status log message to automatically warn when CQE status is non-zero. When issuing an RSCN, log ndlp's kref count to the debugfs trace buffer. Add the NPIV virtual port index to the FDMI registration log message with the fabric. Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251106224639.139176-2-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 6 +++--- drivers/scsi/lpfc/lpfc_init.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index b71db7d7d747..f7c6758557c8 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2367,7 +2367,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, mode = KERN_INFO; /* Warn PRLI status */ - lpfc_printf_vlog(vport, mode, LOG_ELS, + lpfc_vlog_msg(vport, mode, LOG_ELS, "2754 PRLI DID:%06X Status:x%x/x%x, " "data: x%x x%x x%lx\n", ndlp->nlp_DID, ulp_status, @@ -3597,8 +3597,8 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue RSCN: did:x%x", - ndlp->nlp_DID, 0, 0); + "Issue RSCN: 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) { diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index f206267d9ecd..34386b7c0b48 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -9082,9 +9082,9 @@ lpfc_setup_fdmi_mask(struct lpfc_vport *vport) vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR; } - lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "6077 Setup FDMI mask: hba x%x port x%x\n", - vport->fdmi_hba_mask, vport->fdmi_port_mask); + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6077 Setup FDMI mask: hba x%x port x%x\n", + vport->fdmi_hba_mask, vport->fdmi_port_mask); } /** From f7a302e4759c521fe57c7319e40549697424393d Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Thu, 6 Nov 2025 14:46:31 -0800 Subject: [PATCH 02/10] scsi: lpfc: Revise discovery related function headers and comments Correcting discovery related function headers, return status information, and comment descriptions. There are no functional changes. Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251106224639.139176-3-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 17 ++++++++--------- drivers/scsi/lpfc/lpfc_sli.c | 9 +++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index f7c6758557c8..5456d2ab2d36 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -3024,6 +3024,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp->nlp_DID, ulp_status, ulp_word4); + /* Call NLP_EVT_DEVICE_RM if link is down or LOGO is aborted */ if (lpfc_error_lost_link(vport, ulp_status, ulp_word4)) skip_recovery = 1; } @@ -3306,7 +3307,8 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp) * * This routine is a generic completion callback function for Discovery ELS cmd. * Currently used by the ELS command issuing routines for the ELS State Change - * Request (SCR), lpfc_issue_els_scr() and the ELS RDF, lpfc_issue_els_rdf(). + * Request (SCR), lpfc_issue_els_scr(), Exchange Diagnostic Capabilities (EDC), + * lpfc_issue_els_edc() and the ELS RDF, lpfc_issue_els_rdf(). * These commands will be retried once only for ELS timeout errors. **/ static void @@ -3705,10 +3707,7 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) lpfc_nlp_put(ndlp); return 1; } - /* This will cause the callback-function lpfc_cmpl_els_cmd to - * trigger the release of the node. - */ - /* Don't release reference count as RDF is likely outstanding */ + return 0; } @@ -4299,7 +4298,7 @@ lpfc_issue_els_edc(struct lpfc_vport *vport, uint8_t retry) rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { /* The additional lpfc_nlp_put will cause the following - * lpfc_els_free_iocb routine to trigger the rlease of + * lpfc_els_free_iocb routine to trigger the release of * the node. */ lpfc_els_free_iocb(phba, elsiocb); @@ -5127,7 +5126,7 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) { struct lpfc_dmabuf *buf_ptr, *buf_ptr1; - /* The I/O iocb is complete. Clear the node and first dmbuf */ + /* The I/O iocb is complete. Clear the node and first dmabuf */ elsiocb->ndlp = NULL; /* cmd_dmabuf = cmd, cmd_dmabuf->next = rsp, bpl_dmabuf = bpl */ @@ -8734,7 +8733,7 @@ reject_out: * @cmdiocb: pointer to lpfc command iocb data structure. * @ndlp: pointer to a node-list data structure. * - * This routine processes Read Timout Value (RTV) IOCB received as an + * This routine processes Read Timeout Value (RTV) IOCB received as an * ELS unsolicited event. It first checks the remote port state. If the * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE * state, it invokes the lpfc_els_rsl_reject() routine to send the reject @@ -10843,7 +10842,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_els_unsol_buffer(phba, pring, vport, elsiocb); /* * The different unsolicited event handlers would tell us - * if they are done with "mp" by setting cmd_dmabuf to NULL. + * if they are done with "mp" by setting cmd_dmabuf/bpl_dmabuf to NULL. */ if (elsiocb->cmd_dmabuf) { lpfc_in_buf_free(phba, elsiocb->cmd_dmabuf); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 7ea7c4245c69..41eb558dd139 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -19858,13 +19858,15 @@ lpfc_sli4_remove_rpis(struct lpfc_hba *phba) } /** - * lpfc_sli4_resume_rpi - Remove the rpi bitmask region + * lpfc_sli4_resume_rpi - Resume traffic relative to an RPI * @ndlp: pointer to lpfc nodelist data structure. * @cmpl: completion call-back. * @iocbq: data to load as mbox ctx_u information * - * This routine is invoked to remove the memory region that - * provided rpi via a bitmask. + * Return codes + * 0 - successful + * -ENOMEM - No available memory + * -EIO - The mailbox failed to complete successfully. **/ int lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp, @@ -19894,7 +19896,6 @@ lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp, return -EIO; } - /* Post all rpi memory regions to the port. */ lpfc_resume_rpi(mboxq, ndlp); if (cmpl) { mboxq->mbox_cmpl = cmpl; From 3c228061c80df4ea63c2d5ca2c781323885bac7a Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Thu, 6 Nov 2025 14:46:32 -0800 Subject: [PATCH 03/10] scsi: lpfc: Remove redundant NULL ptr assignment in lpfc_els_free_iocb() Remove redundant cmd_dmabuf and bpl_dmabuf NULL ptr assignment as they are already initialized to NULL when handling a new unsolicited event. Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251106224639.139176-4-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 5456d2ab2d36..b4aba68afb66 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -5159,14 +5159,12 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) } else { buf_ptr1 = elsiocb->cmd_dmabuf; lpfc_els_free_data(phba, buf_ptr1); - elsiocb->cmd_dmabuf = NULL; } } if (elsiocb->bpl_dmabuf) { buf_ptr = elsiocb->bpl_dmabuf; lpfc_els_free_bpl(phba, buf_ptr); - elsiocb->bpl_dmabuf = NULL; } lpfc_sli_release_iocbq(phba, elsiocb); return 0; From 6f81582b7a9deb3ab10354e801b3ea5cec92b06c Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Thu, 6 Nov 2025 14:46:33 -0800 Subject: [PATCH 04/10] scsi: lpfc: Ensure unregistration of rpis for received PLOGIs Unregistration of an rpi object should be done when a PLOGI is received as PLOGI receipt implies an implicit LOGO. Previously, the driver would continue using the same, already registered, rpi and ACC the received PLOGI. Replace the ACC and early return statement with break to execute the rest of the lpfc_rcv_plogi logic outside the switch case statement. This ensures unregistration and reregistration of an rpi after PLOGI_ACC completion. Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251106224639.139176-5-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 2 +- drivers/scsi/lpfc/lpfc_nportdisc.c | 17 ++++------------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index b4aba68afb66..8552b24b45a1 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -3263,7 +3263,7 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp) return -ENOMEM; } rc = lpfc_reg_rpi(phba, vport->vpi, fc_ndlp->nlp_DID, - (u8 *)&vport->fc_sparam, mbox, fc_ndlp->nlp_rpi); + (u8 *)&ns_ndlp->fc_sparam, mbox, fc_ndlp->nlp_rpi); if (rc) { rc = -EACCES; goto out; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 1e5ef93e67e3..a6da7c392405 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -452,18 +452,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ if (!(ndlp->nlp_type & NLP_FABRIC) && !(phba->nvmet_support)) { - /* Clear ndlp info, since follow up PRLI may have - * updated ndlp information - */ - ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); - ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); - ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER; - clear_bit(NLP_FIRSTBURST, &ndlp->nlp_flag); - - lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, - ndlp, NULL); - return 1; + break; } if (nlp_portwwn != 0 && nlp_portwwn != wwn_to_u64(sp->portName.u.wwn)) @@ -485,7 +474,9 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); break; } - + /* Clear ndlp info, since follow up processes may have + * updated ndlp information + */ ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; From 23f4906729a0064e734fb9da2ed02e8fbbf8db00 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Thu, 6 Nov 2025 14:46:34 -0800 Subject: [PATCH 05/10] scsi: lpfc: Fix leaked ndlp krefs when in point-to-point topology In point-to-point topology, the driver sometimes defers the unsolicited FLOGI LS_ACC until it sends its FLOGI to the remote port. When this happens, lpfc neglects to release the ndlp allocated for the unsolicited FLOGI. This patch adds code to release the ndlp for the deferred unsolicited FLOGI LS_ACC. An NLP_FLOGI_DFR_ACC flag is introduced to facilitate identifying an ndlp with an expected deferred FLOGI LS_ACC completion. When lpfc_cmpl_els_rsp() detects the correct qualifiers, it releases the initial reference on the ndlp object. And when lpfc_cmpl_els_rsp() exits, the remaining put for the deferred action is executed and the ndlp is released. Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251106224639.139176-6-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 - drivers/scsi/lpfc/lpfc_disc.h | 3 +- drivers/scsi/lpfc/lpfc_els.c | 65 +++++++++++++++++++++++++---------- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 224edacf2d8e..8459cf568c12 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -311,7 +311,6 @@ struct lpfc_defer_flogi_acc { u16 rx_id; u16 ox_id; struct lpfc_nodelist *ndlp; - }; #define LPFC_VMID_TIMER 300 /* timer interval in seconds */ diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 3d47dc7458d1..51cb8571c049 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2013 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -208,6 +208,7 @@ enum lpfc_nlp_flag { NPR list */ NLP_RM_DFLT_RPI = 26, /* need to remove leftover dflt RPI */ NLP_NODEV_REMOVE = 27, /* Defer removal till discovery ends */ + NLP_FLOGI_DFR_ACC = 28, /* FLOGI LS_ACC was Deferred */ NLP_SC_REQ = 29, /* Target requires authentication */ NLP_FIRSTBURST = 30, /* Target supports FirstBurst */ NLP_RPI_REGISTERED = 31 /* nlp_rpi is valid */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 8552b24b45a1..b6ce7e0f8a9b 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1413,11 +1413,12 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->defer_flogi_acc.ox_id; } - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "3354 Xmit deferred FLOGI ACC: rx_id: x%x," - " ox_id: x%x, hba_flag x%lx\n", - phba->defer_flogi_acc.rx_id, - phba->defer_flogi_acc.ox_id, phba->hba_flag); + /* The LS_ACC completion needs to drop the initial reference. + * This is a special case for Pt2Pt because both FLOGIs need + * to complete and lpfc defers the LS_ACC when the remote + * FLOGI arrives before the driver's FLOGI. + */ + set_bit(NLP_FLOGI_DFR_ACC, &ndlp->nlp_flag); /* Send deferred FLOGI ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, &defer_flogi_acc, @@ -1433,6 +1434,14 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->defer_flogi_acc.ndlp = NULL; } + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3354 Xmit deferred FLOGI ACC: rx_id: x%x," + " ox_id: x%x, ndlp x%px hba_flag x%lx\n", + phba->defer_flogi_acc.rx_id, + phba->defer_flogi_acc.ox_id, + phba->defer_flogi_acc.ndlp, + phba->hba_flag); + vport->fc_myDID = did; } @@ -5302,11 +5311,12 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOCB_t *irsp; LPFC_MBOXQ_t *mbox = NULL; u32 ulp_status, ulp_word4, tmo, did, iotag; + u32 cmd; if (!vport) { lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, "3177 null vport in ELS rsp\n"); - goto out; + goto release; } if (cmdiocb->context_un.mbox) mbox = cmdiocb->context_un.mbox; @@ -5416,7 +5426,7 @@ out: * these conditions because it doesn't need the login. */ if (phba->sli_rev == LPFC_SLI_REV4 && - vport && vport->port_type == LPFC_NPIV_PORT && + vport->port_type == LPFC_NPIV_PORT && !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE && ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE && @@ -5432,6 +5442,27 @@ out: } } + /* The driver's unsolicited deferred FLOGI ACC in Pt2Pt needs to + * release the initial reference because the put after the free_iocb + * call removes only the reference from the defer logic. This FLOGI + * is never registered with the SCSI transport. + */ + if (test_bit(FC_PT2PT, &vport->fc_flag) && + test_and_clear_bit(NLP_FLOGI_DFR_ACC, &ndlp->nlp_flag)) { + lpfc_printf_vlog(vport, KERN_INFO, + LOG_ELS | LOG_NODE | LOG_DISCOVERY, + "3357 Pt2Pt Defer FLOGI ACC ndlp x%px, " + "nflags x%lx, fc_flag x%lx\n", + ndlp, ndlp->nlp_flag, + vport->fc_flag); + cmd = *((u32 *)cmdiocb->cmd_dmabuf->virt); + if (cmd == ELS_CMD_ACC) { + if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) + lpfc_nlp_put(ndlp); + } + } + +release: /* Release the originating I/O reference. */ lpfc_els_free_iocb(phba, cmdiocb); lpfc_nlp_put(ndlp); @@ -8399,13 +8430,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, &wqe->xmit_els_rsp.wqe_com); vport->fc_myDID = did; - - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "3344 Deferring FLOGI ACC: rx_id: x%x," - " ox_id: x%x, hba_flag x%lx\n", - phba->defer_flogi_acc.rx_id, - phba->defer_flogi_acc.ox_id, phba->hba_flag); - phba->defer_flogi_acc.flag = true; /* This nlp_get is paired with nlp_puts that reset the @@ -8414,6 +8438,14 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, * processed or cancelled. */ phba->defer_flogi_acc.ndlp = lpfc_nlp_get(ndlp); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3344 Deferring FLOGI ACC: rx_id: x%x," + " ox_id: x%x, ndlp x%px, hba_flag x%lx\n", + phba->defer_flogi_acc.rx_id, + phba->defer_flogi_acc.ox_id, + phba->defer_flogi_acc.ndlp, + phba->hba_flag); return 0; } @@ -10354,11 +10386,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * Do not process any unsolicited ELS commands * if the ndlp is in DEV_LOSS */ - if (test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) { - if (newnode) - lpfc_nlp_put(ndlp); + if (test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) goto dropit; - } elsiocb->ndlp = lpfc_nlp_get(ndlp); if (!elsiocb->ndlp) From 0b8b15a0b74dafe4b184dfae120d715172960ae5 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Thu, 6 Nov 2025 14:46:35 -0800 Subject: [PATCH 06/10] 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 Link: https://patch.msgid.link/20251106224639.139176-7-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 97 ++++++++++++++++++++++++----------- drivers/scsi/lpfc/lpfc_init.c | 6 --- 2 files changed, 67 insertions(+), 36 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index b6ce7e0f8a9b..00cfd4ac4ccd 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -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; } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 34386b7c0b48..a9c6dbe3b465 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -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. */ From 07caedc6a3887938813727beafea40f07c497705 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Thu, 6 Nov 2025 14:46:36 -0800 Subject: [PATCH 07/10] scsi: lpfc: Fix reusing an ndlp that is marked NLP_DROPPED during FLOGI It's possible for an unstable link to repeatedly bounce allowing a FLOGI retry, but then bounce again forcing an abort of the FLOGI. Ensure that the initial reference count on the FLOGI ndlp is restored in this faulty link scenario. Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251106224639.139176-8-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 36 +++++++++++++++++++++++++------- drivers/scsi/lpfc/lpfc_hbadisc.c | 4 +++- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 00cfd4ac4ccd..0045c1e29619 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -934,10 +934,15 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { /* One additional decrement on node reference count to - * trigger the release of the node + * trigger the release of the node. Make sure the ndlp + * is marked NLP_DROPPED. */ - if (!(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) + if (!test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag) && + !test_bit(NLP_DROPPED, &ndlp->nlp_flag) && + !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { + set_bit(NLP_DROPPED, &ndlp->nlp_flag); lpfc_nlp_put(ndlp); + } goto out; } @@ -995,9 +1000,10 @@ stop_rr_fcf_flogi: IOERR_LOOP_OPEN_FAILURE))) lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS, "2858 FLOGI Status:x%x/x%x TMO" - ":x%x Data x%lx x%x\n", + ":x%x Data x%lx x%x x%lx x%x\n", ulp_status, ulp_word4, tmo, - phba->hba_flag, phba->fcf.fcf_flag); + phba->hba_flag, phba->fcf.fcf_flag, + ndlp->nlp_flag, ndlp->fc4_xpt_flags); /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { @@ -1015,14 +1021,17 @@ stop_rr_fcf_flogi: * reference to trigger node release. */ if (!test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag) && - !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) + !test_bit(NLP_DROPPED, &ndlp->nlp_flag) && + !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { + set_bit(NLP_DROPPED, &ndlp->nlp_flag); lpfc_nlp_put(ndlp); + } lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, "0150 FLOGI Status:x%x/x%x " - "xri x%x TMO:x%x refcnt %d\n", + "xri x%x iotag x%x TMO:x%x refcnt %d\n", ulp_status, ulp_word4, cmdiocb->sli4_xritag, - tmo, kref_read(&ndlp->kref)); + cmdiocb->iotag, tmo, kref_read(&ndlp->kref)); /* If this is not a loop open failure, bail out */ if (!(ulp_status == IOSTAT_LOCAL_REJECT && @@ -1279,6 +1288,19 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint32_t tmo, did; int rc; + /* It's possible for lpfc to reissue a FLOGI on an ndlp that is marked + * NLP_DROPPED. This happens when the FLOGI completed with the XB bit + * set causing lpfc to reference the ndlp until the XRI_ABORTED CQE is + * issued. The time window for the XRI_ABORTED CQE can be as much as + * 2*2*RA_TOV allowing for ndlp reuse of this type when the link is + * cycling quickly. When true, restore the initial reference and remove + * the NLP_DROPPED flag as lpfc is retrying. + */ + if (test_and_clear_bit(NLP_DROPPED, &ndlp->nlp_flag)) { + if (!lpfc_nlp_get(ndlp)) + return 1; + } + cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_FLOGI); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 43d246c5c049..717ae56c8e4b 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -424,6 +424,7 @@ lpfc_check_nlp_post_devloss(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { if (test_and_clear_bit(NLP_IN_RECOV_POST_DEV_LOSS, &ndlp->save_flags)) { + clear_bit(NLP_DROPPED, &ndlp->nlp_flag); lpfc_nlp_get(ndlp); lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_NODE, "8438 Devloss timeout reversed on DID x%x " @@ -566,7 +567,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) return fcf_inuse; } - lpfc_nlp_put(ndlp); + if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) + lpfc_nlp_put(ndlp); return fcf_inuse; } From 683df5fc3ec5b9bd2596f84d120c4fda8151fd09 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Thu, 6 Nov 2025 14:46:37 -0800 Subject: [PATCH 08/10] scsi: lpfc: Allow support for BB credit recovery in point-to-point topology Currently, BB credit recovery is excluded to fabric topology mode. This patch allows setting of BB_SC_N in PLOGIs and PLOGI_ACCs when in point-to-point mode so that BB credit recovery can operate in point-to-point topology as well. Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251106224639.139176-9-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 0045c1e29619..b066ba83ce87 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2279,7 +2279,8 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) sp->cmn.valid_vendor_ver_level = 0; memset(sp->un.vendorVersion, 0, sizeof(sp->un.vendorVersion)); - sp->cmn.bbRcvSizeMsb &= 0xF; + if (!test_bit(FC_PT2PT, &vport->fc_flag)) + sp->cmn.bbRcvSizeMsb &= 0xF; /* Check if the destination port supports VMID */ ndlp->vmid_support = 0; @@ -5670,7 +5671,8 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, sp->cmn.valid_vendor_ver_level = 0; memset(sp->un.vendorVersion, 0, sizeof(sp->un.vendorVersion)); - sp->cmn.bbRcvSizeMsb &= 0xF; + if (!test_bit(FC_PT2PT, &vport->fc_flag)) + sp->cmn.bbRcvSizeMsb &= 0xF; /* If our firmware supports this feature, convey that * info to the target using the vendor specific field. From 191da2c71b13b1975d8759f852b0ce9bbc913545 Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Thu, 6 Nov 2025 14:46:38 -0800 Subject: [PATCH 09/10] scsi: lpfc: Add capability to register Platform Name ID to fabric FC-LS and FC-GS specifications outline fields for registering a platform name identifier (PNI) to the fabric. The PNI assists fabrics with identifying the physical server source of frames in the fabric. lpfc generates a PNI based partially on the uuid specific for the system. Initial attempts to extract a uuid are made from SMBIOS's System Information 08h uuid entry. If SMBIOS DMI does not exist, a PNI is not generated and PNI registration with the fabric is skipped. The PNI is submitted in FLOGI and FDISC frames. After successful fabric login, the RSPNI_PNI CT frame is submitted to the fabric to register the OS host name tying it to the PNI. Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251106224639.139176-10-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 3 ++ drivers/scsi/lpfc/lpfc_ct.c | 36 +++++++++++++++ drivers/scsi/lpfc/lpfc_els.c | 18 ++++++-- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 + drivers/scsi/lpfc/lpfc_hw.h | 25 ++++++++++- drivers/scsi/lpfc/lpfc_nportdisc.c | 4 -- drivers/scsi/lpfc/lpfc_sli.c | 70 ++++++++++++++++++++++++++++++ 7 files changed, 150 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 8459cf568c12..689793d03c20 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -633,6 +633,7 @@ struct lpfc_vport { #define FC_CT_RSPN_ID 0x8 /* RSPN_ID accepted by switch */ #define FC_CT_RFT_ID 0x10 /* RFT_ID accepted by switch */ #define FC_CT_RPRT_DEFER 0x20 /* Defer issuing FDMI RPRT */ +#define FC_CT_RSPNI_PNI 0x40 /* RSPNI_PNI accepted by switch */ struct list_head fc_nodes; spinlock_t fc_nodes_list_lock; /* spinlock for fc_nodes list */ @@ -1077,6 +1078,8 @@ struct lpfc_hba { uint32_t nport_event_cnt; /* timestamp for nlplist entry */ + unsigned long pni; /* 64-bit Platform Name Identifier */ + uint8_t wwnn[8]; uint8_t wwpn[8]; uint32_t RandomData[7]; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index f93f8dca65bd..d3caac394291 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1742,6 +1742,28 @@ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, return; } +static void +lpfc_cmpl_ct_cmd_rspni_pni(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport; + struct lpfc_dmabuf *outp; + struct lpfc_sli_ct_request *ctrsp; + u32 ulp_status; + + vport = cmdiocb->vport; + ulp_status = get_job_ulpstatus(phba, rspiocb); + + if (ulp_status == IOSTAT_SUCCESS) { + outp = cmdiocb->rsp_dmabuf; + ctrsp = (struct lpfc_sli_ct_request *)outp->virt; + if (be16_to_cpu(ctrsp->CommandResponse.bits.CmdRsp) == + SLI_CT_RESPONSE_FS_ACC) + vport->ct_flags |= FC_CT_RSPNI_PNI; + } + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); +} + static void lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) @@ -1956,6 +1978,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, bpl->tus.f.bdeSize = RSPN_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RSNN_NN) bpl->tus.f.bdeSize = RSNN_REQUEST_SZ; + else if (cmdcode == SLI_CTNS_RSPNI_PNI) + bpl->tus.f.bdeSize = RSPNI_REQUEST_SZ; else if (cmdcode == SLI_CTNS_DA_ID) bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RFF_ID) @@ -2077,6 +2101,18 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, CtReq->un.rsnn.symbname, size); cmpl = lpfc_cmpl_ct_cmd_rsnn_nn; break; + case SLI_CTNS_RSPNI_PNI: + vport->ct_flags &= ~FC_CT_RSPNI_PNI; + CtReq->CommandResponse.bits.CmdRsp = + cpu_to_be16(SLI_CTNS_RSPNI_PNI); + CtReq->un.rspni.pni = cpu_to_be64(phba->pni); + scnprintf(CtReq->un.rspni.symbname, + sizeof(CtReq->un.rspni.symbname), "OS Host Name::%s", + phba->os_host_name); + CtReq->un.rspni.len = strnlen(CtReq->un.rspni.symbname, + sizeof(CtReq->un.rspni.symbname)); + cmpl = lpfc_cmpl_ct_cmd_rspni_pni; + break; case SLI_CTNS_DA_ID: /* Implement DA_ID Nameserver request */ CtReq->CommandResponse.bits.CmdRsp = diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index b066ba83ce87..02b6d31b9ad9 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -650,8 +650,6 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_class_sup |= FC_COS_CLASS2; if (sp->cls3.classValid) ndlp->nlp_class_sup |= FC_COS_CLASS3; - if (sp->cls4.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS4; ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; @@ -1356,6 +1354,14 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Can't do SLI4 class2 without support sequence coalescing */ sp->cls2.classValid = 0; sp->cls2.seqDelivery = 0; + + /* Fill out Auxiliary Parameter Data */ + if (phba->pni) { + sp->aux.flags = + AUX_PARM_DATA_VALID | AUX_PARM_PNI_VALID; + sp->aux.pni = cpu_to_be64(phba->pni); + sp->aux.npiv_cnt = cpu_to_be16(phba->max_vpi - 1); + } } else { /* Historical, setting sequential-delivery bit for SLI3 */ sp->cls2.seqDelivery = (sp->cls2.classValid) ? 1 : 0; @@ -5657,7 +5663,6 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, sp->cls1.classValid = 0; sp->cls2.classValid = 0; sp->cls3.classValid = 0; - sp->cls4.classValid = 0; /* Copy our worldwide names */ memcpy(&sp->portName, &vport->fc_sparam.portName, @@ -11510,6 +11515,13 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, sp->cls2.seqDelivery = 1; sp->cls3.seqDelivery = 1; + /* Fill out Auxiliary Parameter Data */ + if (phba->pni) { + sp->aux.flags = + AUX_PARM_DATA_VALID | AUX_PARM_PNI_VALID; + sp->aux.pni = cpu_to_be64(phba->pni); + } + pcmd += sizeof(uint32_t); /* CSP Word 2 */ pcmd += sizeof(uint32_t); /* CSP Word 3 */ pcmd += sizeof(uint32_t); /* CSP Word 4 */ diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 717ae56c8e4b..bb803f32bc1b 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -4373,6 +4373,8 @@ out: lpfc_ns_cmd(vport, SLI_CTNS_RNN_ID, 0, 0); lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0); lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0); + if (phba->pni) + lpfc_ns_cmd(vport, SLI_CTNS_RSPNI_PNI, 0, 0); lpfc_ns_cmd(vport, SLI_CTNS_RFT_ID, 0, 0); if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 3bc0efa7453e..b2e353590ebb 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -168,6 +168,11 @@ struct lpfc_sli_ct_request { uint8_t len; uint8_t symbname[255]; } rspn; + struct rspni { /* For RSPNI_PNI requests */ + __be64 pni; + u8 len; + u8 symbname[255]; + } rspni; struct gff { uint32_t PortId; } gff; @@ -213,6 +218,8 @@ struct lpfc_sli_ct_request { sizeof(struct da_id)) #define RSPN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ sizeof(struct rspn)) +#define RSPNI_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ + sizeof(struct rspni)) /* * FsType Definitions @@ -309,6 +316,7 @@ struct lpfc_sli_ct_request { #define SLI_CTNS_RIP_NN 0x0235 #define SLI_CTNS_RIPA_NN 0x0236 #define SLI_CTNS_RSNN_NN 0x0239 +#define SLI_CTNS_RSPNI_PNI 0x0240 #define SLI_CTNS_DA_ID 0x0300 /* @@ -512,6 +520,21 @@ struct class_parms { uint8_t word3Reserved2; /* Fc Word 3, bit 0: 7 */ }; +enum aux_parm_flags { + AUX_PARM_PNI_VALID = 0x20, /* FC Word 0, bit 29 */ + AUX_PARM_DATA_VALID = 0x40, /* FC Word 0, bit 30 */ +}; + +struct aux_parm { + u8 flags; /* FC Word 0, bit 31:24 */ + u8 ext_feat[3]; /* FC Word 0, bit 23:0 */ + + __be64 pni; /* FC Word 1 and 2, platform name identifier */ + + __be16 rsvd; /* FC Word 3, bit 31:16 */ + __be16 npiv_cnt; /* FC Word 3, bit 15:0 */ +} __packed; + struct serv_parm { /* Structure is in Big Endian format */ struct csp cmn; struct lpfc_name portName; @@ -519,7 +542,7 @@ struct serv_parm { /* Structure is in Big Endian format */ struct class_parms cls1; struct class_parms cls2; struct class_parms cls3; - struct class_parms cls4; + struct aux_parm aux; union { uint8_t vendorVersion[16]; struct { diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index a6da7c392405..8240d59f4120 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -432,8 +432,6 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_class_sup |= FC_COS_CLASS2; if (sp->cls3.classValid) ndlp->nlp_class_sup |= FC_COS_CLASS3; - if (sp->cls4.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS4; ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; /* if already logged in, do implicit logout */ @@ -1417,8 +1415,6 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ndlp->nlp_class_sup |= FC_COS_CLASS2; if (sp->cls3.classValid) ndlp->nlp_class_sup |= FC_COS_CLASS3; - if (sp->cls4.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS4; ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 41eb558dd139..73d77cfab5f8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -8446,6 +8448,70 @@ lpfc_set_host_tm(struct lpfc_hba *phba) return rc; } +/** + * lpfc_get_platform_uuid - Attempts to extract a platform uuid + * @phba: pointer to lpfc hba data structure. + * + * This routine attempts to first read SMBIOS DMI data for the System + * Information structure offset 08h called System UUID. Else, no platform + * UUID will be advertised. + **/ +static void +lpfc_get_platform_uuid(struct lpfc_hba *phba) +{ + int rc; + const char *uuid; + char pni[17] = {0}; /* 16 characters + '\0' */ + bool is_ff = true, is_00 = true; + u8 i; + + /* First attempt SMBIOS DMI */ + uuid = dmi_get_system_info(DMI_PRODUCT_UUID); + if (uuid) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2088 SMBIOS UUID %s\n", + uuid); + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2099 Could not extract UUID\n"); + } + + if (uuid && uuid_is_valid(uuid)) { + /* Generate PNI from UUID format. + * + * 1.) Extract lower 64 bits from UUID format. + * 2.) Set 3h for NAA Locally Assigned Name Identifier format. + * + * e.g. xxxxxxxx-xxxx-xxxx-yyyy-yyyyyyyyyyyy + * + * extract the yyyy-yyyyyyyyyyyy portion + * final PNI 3yyyyyyyyyyyyyyy + */ + scnprintf(pni, sizeof(pni), "3%c%c%c%s", + uuid[20], uuid[21], uuid[22], &uuid[24]); + + /* Sanitize the converted PNI */ + for (i = 1; i < 16 && (is_ff || is_00); i++) { + if (pni[i] != '0') + is_00 = false; + if (pni[i] != 'f' && pni[i] != 'F') + is_ff = false; + } + + /* Convert from char* to unsigned long */ + rc = kstrtoul(pni, 16, &phba->pni); + if (!rc && !is_ff && !is_00) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2100 PNI 0x%016lx\n", phba->pni); + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2101 PNI %s generation status %d\n", + pni, rc); + phba->pni = 0; + } + } +} + /** * lpfc_sli4_hba_setup - SLI4 device initialization PCI function * @phba: Pointer to HBA context object. @@ -8529,6 +8595,10 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) clear_bit(HBA_FCOE_MODE, &phba->hba_flag); } + /* Obtain platform UUID, only for SLI4 FC adapters */ + if (!test_bit(HBA_FCOE_MODE, &phba->hba_flag)) + lpfc_get_platform_uuid(phba); + if (bf_get(lpfc_mbx_rd_rev_cee_ver, &mqe->un.read_rev) == LPFC_DCBX_CEE_MODE) set_bit(HBA_FIP_SUPPORT, &phba->hba_flag); From d45fdc6cdd7370ce2c8eb55b65af34594cdd9d7e Mon Sep 17 00:00:00 2001 From: Justin Tee Date: Thu, 6 Nov 2025 14:46:39 -0800 Subject: [PATCH 10/10] scsi: lpfc: Update lpfc version to 14.4.0.12 Update lpfc version to 14.4.0.12 Signed-off-by: Justin Tee Link: https://patch.msgid.link/20251106224639.139176-11-justintee8345@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 31c3c5abdca6..f3dada5bf7c1 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.4.0.11" +#define LPFC_DRIVER_VERSION "14.4.0.12" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */