[PATCH 07/13] scsi: fnic: Route completions and resets by initiator role

From: Karan Tilak Kumar

Date: Thu May 21 2026 - 14:14:36 EST


Dispatch FCPIO command, response, and ITMF completions to the FCP or NVMe
handlers based on the configured role.

Read the NVMe queue-depth and timeout retry fields from firmware config,
clean up NVMe I/O on firmware reset, and skip SCSI-only cleanup for
initiator roles that already reset firmware-owned requests.

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: Lee Duncan <lduncan@xxxxxxxx>
Signed-off-by: Karan Tilak Kumar <kartilak@xxxxxxxxx>
Co-developed-by: Hannes Reinecke <hare@xxxxxxxxxx>
---
drivers/scsi/fnic/fnic_res.c | 2 ++
drivers/scsi/fnic/fnic_scsi.c | 30 ++++++++++++++++++++++++++----
2 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/fnic/fnic_res.c b/drivers/scsi/fnic/fnic_res.c
index 18353fbb5f98..d75d7046c7f6 100644
--- a/drivers/scsi/fnic/fnic_res.c
+++ b/drivers/scsi/fnic/fnic_res.c
@@ -57,6 +57,8 @@ int fnic_get_vnic_config(struct fnic *fnic)
GET_CONFIG(port_down_io_retries);
GET_CONFIG(luns_per_tgt);
GET_CONFIG(intr_mode);
+ GET_CONFIG(lun_queue_depth);
+ GET_CONFIG(io_timeout_retry);
GET_CONFIG(wq_copy_count);

role = c->flags & FNIC_ROLE_CONFIG_MASK;
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index 04ab384033b1..5ad4bb714428 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -145,8 +145,9 @@ unsigned int fnic_count_ioreqs(struct fnic *fnic, u32 portid)
{
unsigned int count = 0;

- fnic_scsi_io_iter(fnic, fnic_count_portid_ioreqs_iter,
- &portid, &count);
+ if (IS_FNIC_FCP_INITIATOR(fnic))
+ fnic_scsi_io_iter(fnic, fnic_count_portid_ioreqs_iter,
+ &portid, &count);

FNIC_SCSI_DBG(KERN_DEBUG, fnic,
"portid = 0x%x count = %u\n", portid, count);
@@ -734,6 +735,8 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic,
/* Clean up all outstanding io requests */
if (IS_FNIC_FCP_INITIATOR(fnic))
fnic_cleanup_io(fnic, SCSI_NO_TAG);
+ else if (IS_FNIC_NVME_INITIATOR(fnic))
+ nvfnic_cleanup_all_nvme_ios(fnic);

atomic64_set(&fnic->fnic_stats.fw_stats.active_fw_reqs, 0);
atomic64_set(&fnic->fnic_stats.io_stats.active_ios, 0);
@@ -1457,11 +1460,21 @@ static int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev,
break;

case FCPIO_ICMND_CMPL: /* fw completed a command */
- fnic_fcpio_icmnd_cmpl_handler(fnic, cq_index, desc);
+ if (IS_FNIC_FCP_INITIATOR(fnic))
+ fnic_fcpio_icmnd_cmpl_handler(fnic, cq_index, desc);
+ else if (IS_FNIC_NVME_INITIATOR(fnic))
+ nvfnic_fcpio_nvme_fast_cmpl_handler(fnic, desc);
+ break;
+
+ case FCPIO_NVME_ERSP_HW_CMPL: /* fw completed NVMe ERSP */
+ nvfnic_fcpio_ersp_cmpl_handler(fnic, desc, 1);
break;

case FCPIO_ITMF_CMPL: /* fw completed itmf (abort cmd, lun reset)*/
- fnic_fcpio_itmf_cmpl_handler(fnic, cq_index, desc);
+ if (IS_FNIC_FCP_INITIATOR(fnic))
+ fnic_fcpio_itmf_cmpl_handler(fnic, cq_index, desc);
+ else if (IS_FNIC_NVME_INITIATOR(fnic))
+ nvfnic_fcpio_nvme_itmf_cmpl_handler(fnic, desc);
break;

case FCPIO_FLOGI_REG_CMPL: /* fw completed flogi_reg */
@@ -1650,6 +1663,15 @@ void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq,
unsigned long start_time = 0;
uint16_t hwq;

+ /*
+ * Clean up all outstanding io requests. For FC initiator or NVME
+ * initiator we issue firmware reset before this and all I/Os are
+ * already freed
+ */
+ if (IS_FNIC_FCP_INITIATOR(fnic) ||
+ IS_FNIC_NVME_INITIATOR(fnic))
+ return;
+
/* get the tag reference */
fcpio_tag_id_dec(&desc->hdr.tag, &id);
id &= FNIC_TAG_MASK;
--
2.47.1