[PATCH v2 10/13] scsi: fnic: Abort timed-out NVMe LS requests

From: Karan Tilak Kumar

Date: Wed May 27 2026 - 15:57:44 EST


Add an FDLS helper that sends ABTS frames for outstanding NVMe LS
requests.

Use the active LS request OXID when building the ABTS frame, send it
through the FCoE transmit path, and call it from LS timeout and abort
handling.

Reviewed-by: Sesidhar Baddela <sebaddel@xxxxxxxxx>
Reviewed-by: Arulprabhu Ponnusamy <arulponn@xxxxxxxxx>
Reviewed-by: Gian Carlo Boffa <gcboffa@xxxxxxxxx>
Reviewed-by: Arun Easi <aeasi@xxxxxxxxx>
Reviewed-by: Hannes Reinecke <hare@xxxxxxxxxx>
Reviewed-by: Lee Duncan <lduncan@xxxxxxxx>
Signed-off-by: Karan Tilak Kumar <kartilak@xxxxxxxxx>
Co-developed-by: Hannes Reinecke <hare@xxxxxxxxxx>
---
drivers/scsi/fnic/fdls_disc.c | 38 +++++++++++++++++++++++++++++++++++
drivers/scsi/fnic/fnic_fdls.h | 2 ++
drivers/scsi/fnic/fnic_nvme.c | 16 +++++++++++++++
3 files changed, 56 insertions(+)

diff --git a/drivers/scsi/fnic/fdls_disc.c b/drivers/scsi/fnic/fdls_disc.c
index 0fcdfdea8fb4..5d010b38102c 100644
--- a/drivers/scsi/fnic/fdls_disc.c
+++ b/drivers/scsi/fnic/fdls_disc.c
@@ -654,6 +654,44 @@ fdls_send_logo_resp(struct fnic_iport_s *iport,
fnic_send_fcoe_frame(iport, frame, frame_size);
}

+int fdls_send_ls_req_abts(struct fnic_iport_s *iport,
+ struct fnic_tport_s *tport, unsigned int oxid)
+{
+ uint8_t *frame;
+ uint8_t s_id[3];
+ uint8_t d_id[3];
+ struct fnic *fnic = iport->fnic;
+ struct fc_frame_header *pls_req_abts;
+ uint16_t frame_size = FNIC_ETH_FCOE_HDRS_OFFSET +
+ sizeof(struct fc_frame_header);
+
+ frame = fdls_alloc_frame(iport);
+ if (frame == NULL) {
+ FNIC_FCS_DBG(KERN_ERR, fnic,
+ "Failed to allocate frame to send ls req ABTS");
+ return -ENOMEM;
+ }
+
+ pls_req_abts = (struct fc_frame_header *) (frame +
+ FNIC_ETH_FCOE_HDRS_OFFSET);
+ fdls_init_fabric_abts_frame(frame, iport);
+
+ hton24(s_id, iport->fcid);
+ hton24(d_id, tport->fcid);
+ FNIC_STD_SET_S_ID(*pls_req_abts, s_id);
+ FNIC_STD_SET_D_ID(*pls_req_abts, d_id);
+
+ FNIC_STD_SET_OX_ID(*pls_req_abts, oxid);
+
+ FNIC_FCS_DBG(KERN_INFO, fnic,
+ "iport 0x%x: tport: 0x%x FDLS sending ls req abts with oxid: 0x%x",
+ iport->fcid, tport->fcid, oxid);
+
+ fnic_send_fcoe_frame(iport, frame, frame_size);
+ return 0;
+}
+
+
void
fdls_send_tport_abts(struct fnic_iport_s *iport,
struct fnic_tport_s *tport)
diff --git a/drivers/scsi/fnic/fnic_fdls.h b/drivers/scsi/fnic/fnic_fdls.h
index 0a68d0fb11b1..ce4b3aae77e3 100644
--- a/drivers/scsi/fnic/fnic_fdls.h
+++ b/drivers/scsi/fnic/fnic_fdls.h
@@ -407,6 +407,8 @@ uint16_t fdls_alloc_oxid(struct fnic_iport_s *iport, int oxid_frame_type,
uint16_t *active_oxid);
void fdls_free_oxid(struct fnic_iport_s *iport,
uint16_t oxid, uint16_t *active_oxid);
+int fdls_send_ls_req_abts(struct fnic_iport_s *iport,
+ struct fnic_tport_s *tport, unsigned int oxid);
void fdls_tgt_logout(struct fnic_iport_s *iport,
struct fnic_tport_s *tport);
void fnic_del_fabric_timer_sync(struct fnic *fnic);
diff --git a/drivers/scsi/fnic/fnic_nvme.c b/drivers/scsi/fnic/fnic_nvme.c
index 83a43df28956..dc202f0ae4d8 100644
--- a/drivers/scsi/fnic/fnic_nvme.c
+++ b/drivers/scsi/fnic/fnic_nvme.c
@@ -1195,6 +1195,7 @@ void nvfnic_ls_req_timeout(struct timer_list *t)
struct fnic_iport_s *iport = &fnic->iport;
struct fnic_tport_s *tport = (struct fnic_tport_s *) nvfnic_ls_req->tport;
uint16_t oxid = nvfnic_ls_req->oxid;
+ int timeout;

FNIC_NVME_DBG(KERN_INFO, fnic,
"tport: 0x%x lsreq: 0x%x state: %d timeout\n",
@@ -1228,6 +1229,19 @@ void nvfnic_ls_req_timeout(struct timer_list *t)
FNIC_NVME_DBG(KERN_ERR, fnic,
"tport: 0x%x lsreq: 0x%x sending abort\n",
tport->fcid, nvfnic_ls_req->oxid);
+ nvfnic_ls_req->state = FNIC_LS_REQ_CMD_ABTS_PENDING;
+ spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
+
+ if (fdls_send_ls_req_abts(iport, tport, nvfnic_ls_req->oxid) == 0) {
+ timeout = FNIC_LS_REQ_TMO_MSECS(ls_req->timeout);
+ mod_timer(&nvfnic_ls_req->ls_req_timer,
+ round_jiffies(jiffies + msecs_to_jiffies(timeout)));
+ return;
+ }
+ FNIC_NVME_DBG(KERN_ERR, fnic,
+ "tport: 0x%x lsreq: 0x%x cannot send abort\n",
+ tport->fcid, oxid);
+ spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
}

if (ls_req->private == NULL) {
@@ -1519,6 +1533,8 @@ void nvfnic_ls_req_abort(struct nvme_fc_local_port *lport,
mod_timer(&nvfnic_ls_req->ls_req_timer,
round_jiffies(jiffies + msecs_to_jiffies(timeout)));
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
+
+ fdls_send_ls_req_abts(iport, tport, nvfnic_ls_req->oxid);
}

bool nvfnic_queue_abort_io_req(struct fnic *fnic, int tag,
--
2.47.1