[PATCH 1/1] scsi: lpfc: Clear rport association before unregistering it

Dai Ngo <[email protected]> Wed, 29 Jul 2026 08:18:33 -0700
Newsgroups org.kernel.vger.linux-scsi
Message-ID <[email protected]>
System crashed when a Fibre Channel cable is removed from an
Emulex/Broadcom lpfc HBA.

The crash occurs after the lpfc Link Down event, after dm-multipath
fails paths, and when the FC remote ports time out and are removed.

[ 3214.903257] lpfc 0000:c1:00.0: 0:1305 Link Down Event x2 received Data: x2 x20 x200110 x0
[ 3225.070299] sd 19:0:5:254: rejecting I/O to offline device
[ 3225.070330] I/O error, dev sdm, sector 532480 op 0x0:(READ) flags 0x4200 phys_seg 16 prio class 2
[ 3225.070355] device-mapper: multipath: 252:10: Failing path 8:192.
...
[ 3245.037613]  rport-19:0-1: blocked FC remote port time out: removing rport
[ 3245.037651]  rport-19:0-0: blocked FC remote port time out: removing rport
[ 3245.549614]  rport-19:0-3: blocked FC remote port time out: removing rport
[ 3245.549632]  rport-19:0-2: blocked FC remote port time out: removing rport
[ 3245.550290] Oops: general protection fault, probably for non-canonical address 0x400d7115d1923c7a: 0000 [#1] PREEMPT SMP NOPTI
[ 3245.550309] CPU: 6 UID: 0 PID: 355 Comm: kworker/6:1 Kdump: loaded Not tainted 6.12.0-203.76.7.5.el9uek.x86_64 #2
[ 3245.550338] Workqueue: fc_wq_19 fc_rport_final_delete [scsi_transport_fc]
[ 3245.550360] RIP: 0010:lpfc_dev_loss_tmo_callbk+0x58/0x48d [lpfc]

Call trace:

lpfc_dev_loss_tmo_callbk+0x58/0x48d [lpfc]
fc_rport_final_delete+0xeb/0x1b0 [scsi_transport_fc]
process_one_work+0x174/0x31a
worker_thread+0x191/0x300
kthread+0xcf/0x100
ret_from_fork+0x31/0x50
ret_from_fork_asm+0x1a/0x30

The crash happened at this statement in lpfc_dev_loss_tmo_callbk():

phba  = vport->phba;

and vport has an invalid address, 0x400d7115d1923c7a.

The crash happened because rport->dd_data->pnode still pointed to an
ndlp, but that ndlp was no longer valid. If ndlp->vport is
0x400d7115d1923c7a, that is much more consistent with a stale/reused
ndlp object than with a valid node whose vport was separately freed. The
node pointer itself can still be canonical because it points into memory
that used to be an lpfc_nodelist; its contents are what became invalid.

This patch fixes the problem by detaching the node from the SCSI
remote port before calling fc_remote_port_delete(). Clear rdata->pnode,
ndlp->rport, and the SCSI transport registration flag while holding
ndlp->lock.

This prevents stale rport-to-node references and keeps the node’s
transport state consistent during remote-port teardown.

Assisted-by: Codex:gpt-5
Signed-off-by: Dai Ngo <[email protected]>
---
 drivers/scsi/lpfc/lpfc_hbadisc.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index ecc9d6bcda32..f0329bb89e9a 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -4564,6 +4564,8 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp)
 {
 	struct fc_rport *rport = ndlp->rport;
 	struct lpfc_vport *vport = ndlp->vport;
+	struct lpfc_rport_data *rdata;
+	unsigned long iflags;
 
 	if (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)
 		return;
@@ -4578,6 +4580,14 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp)
 			 ndlp->nlp_DID, rport, ndlp->fc4_xpt_flags,
 			 kref_read(&ndlp->kref));
 
+	rdata = rport->dd_data;
+	spin_lock_irqsave(&ndlp->lock, iflags);
+	if (rdata && rdata->pnode == ndlp)
+		rdata->pnode = NULL;
+	ndlp->rport = NULL;
+	ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD;
+	spin_unlock_irqrestore(&ndlp->lock, iflags);
+
 	fc_remote_port_delete(rport);
 	lpfc_nlp_put(ndlp);
 }
-- 
2.47.3