All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support
@ 2026-06-12  9:52 Nilesh Javali
  2026-06-12  9:52 ` [PATCH v2 01/60] scsi: qla2xxx: Add 29xx series PCI device ID support Nilesh Javali
                   ` (59 more replies)
  0 siblings, 60 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Add support for the QLA29xx generation of Marvell QLogic
Fibre Channel HBAs (ISP2091/ISP2291/ISP2099/ISP2299).
The 29xx family shares much of its architecture with the
existing 27xx/28xx adapters but introduces 128-byte request
and response ring entries (up from 64 bytes), requiring
extended IOCB definitions and updated ring management
throughout the driver.

The key hardware change is the wider IOCB format: every
request and response queue entry is now 128 bytes.
This propagates into every code path that builds, submits,
or processes IOCBs -- command submission, status completion,
marker, CT pass-through, ELS, logio, task management,
abort, ABTS, VP control, and NVMe.

The series is organised as follows:

Patches 01-08: Foundation and flash/firmware infrastructure
  PCI device ID registration, ISP-flags wiring, flash read/write
  interface, NVRAM configuration, queue initialisation, FC operational
  firmware load, and BSG passthrough (flash block I/O, MPI firmware
  load/dump).

Patches 09-13: 128-byte IOCB infrastructure
  New qla_fw29.h header with extended structure definitions, status
  continuation and marker IOCBs, removal of duplicate flash memo
  block defines, IO-path updates to select the correct IOCB size, and
  introduction of entry-size helper functions that centralise the
  IS_QLA29XX() dispatch pattern.

Patches 14-26: Sysfs, mailbox commands, and core enablement
  Sysfs attribute gating for unsupported 29xx features, mailbox command
  enablement (get_fw_version, execute_fw, get_adapter_id,
  init_firmware, get_firmware_state, serdes, ELS, echo_test,
  data rate), shutdown path, ring-slot helpers, and memory allocation
  updates.

Patches 27-44: Response-path IOCB handling and final wiring
  Marker, status continuation, status entry, CT pass-through, PUREX,
  ELS, logio, task management, abort, ABTS, VP control/config/report-ID,
  NVMe IOCB unification, LS4 pass-through, NVMe ring advance
  conversion, and BSG feature gating adjustments.

Patches 45-60: the tail of the series carries bug fixes uncovered
  during review of v1 patchset (64G/128G speed reporting,
  VP index bounds, Name Server logout detection, NVMe
  abort/LS-reject locking, a BSG job leak, an info leak,
  and an edif NULL deref).

The series applies on top of the scsi tree's 7.1/scsi-queue branch.

Changes in v2:
  - Folded the standalone fix-ups posted in v1 into the feature commits
    they corrected, so the 29xx enablement commits are now individually
    correct and bisectable (no "fix the previous patch" commits in the
    middle of the series).
  - Corrected several Fixes: tags to reference the actual introducing
    commits after the above reorganisation.
  - Widened the ELS vp_index path to 16 bits to match the 29xx 9-bit
    hardware field, folded into the ELS enablement commit.

Thanks,
Nilesh

Anil Gurumurthy (5):
  scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx
  scsi: qla2xxx: Add extended status continuation and marker IOCBs
  scsi: qla2xxx: Remove duplicate flash memo block definitions
  scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx
  scsi: qla2xxx: Replace IS_QLA29XX() size checks with entry-size
    helpers

Manish Rangankar (10):
  scsi: qla2xxx: Add 29xx series PCI device ID support
  scsi: qla2xxx: Add flash read/write interface for 29xx
  scsi: qla2xxx: Add NVRAM config support for 29xx adapters
  scsi: qla2xxx: Add get_flash_version support for 29xx adapters
  scsi: qla2xxx: Add 29xx support in queue initialisation path
  scsi: qla2xxx: Add FC operational firmware load for 29xx
  scsi: qla2xxx: Add flash block read/write BSG support for 29xx
  scsi: qla2xxx: Add BSG MPI firmware load/dump for 29xx
  scsi: qla2xxx: Add LS4 pass-through IOCB handling for 29xx series
  scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support

Nilesh Javali (45):
  scsi: qla2xxx: Skip image-set-valid attribute for 29xx
  scsi: qla2xxx: Skip unsupported sysfs attributes for 29xx
  scsi: qla2xxx: Enable get_fw_version mailbox for 29xx
  scsi: qla2xxx: Extend execute_fw mailbox to include 29xx
  scsi: qla2xxx: Enable get_adapter_id mailbox for 29xx
  scsi: qla2xxx: Enable init_firmware mailbox for 29xx
  scsi: qla2xxx: Enable get_firmware_state for 29xx
  scsi: qla2xxx: Enable serdes, resource count and FCE trace for 29xx
  scsi: qla2xxx: Enable set_els_cmds and echo_test for 29xx
  scsi: qla2xxx: Add support for QLA29XX in data rate functions
  scsi: qla2xxx: Enable qla2x00_shutdown for 29xx
  scsi: qla2xxx: Use ring-slot helpers in __qla2x00_alloc_iocbs
  scsi: qla2xxx: Add support for QLA29XX in memory allocation
  scsi: qla2xxx: Refactor marker IOCB handling for 29xx series
  scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters
  scsi: qla2xxx: Update handling of status entries for 29xx series
  scsi: qla2xxx: Enhance ct_entry_24xx_ext iocb handling for 29xx series
  scsi: qla2xxx: Enhance purex_entry handling for 29xx series
  scsi: qla2xxx: Update handling of ELS IOCBs for 29xx series
  scsi: qla2xxx: Add size check for ELS status entry layout on 29xx
  scsi: qla2xxx: Add 29xx extended logio IOCB support
  scsi: qla2xxx: Enhance task management IOCB handling for 29xx series
  scsi: qla2xxx: Add abort command handling for 29xx series
  scsi: qla2xxx: Enhance ABTS processing for 29xx series
  scsi: qla2xxx: Update VP control IOCB handling for 29xx series
  scsi: qla2xxx: Add build-time size check for VP config IOCB layout
  scsi: qla2xxx: Add size check for extended VP report ID entry
  scsi: qla2xxx: Unify NVMe IOCB build path for 29xx and legacy adapters
  scsi: qla2xxx: Convert NVMe ring advance to use qla_req_ring_advance()
  scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking
  scsi: qla2xxx: Replace __le16 bitfields with scalar and accessors
  scsi: qla2xxx: Fix endianness annotations in vp_rpt_id_entry
    structures
  scsi: qla2xxx: Use 64-bit FPM word counters for 29xx host stats
  scsi: qla2xxx: Add 64G/128G port speed setting support
  scsi: qla2xxx: Fix 64G link speed reporting in get_data_rate
  scsi: qla2xxx: edif: Fix NULL pointer deref in RX SA delete check
  scsi: qla2xxx: Fix Name Server logout detection on FWI2 adapters
  scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size
  scsi: qla2xxx: Check entry_status in qla24xx_modify_vp_config()
  scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition()
  scsi: qla2xxx: Initialize NVMe abort_work once at submission
  scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject
  scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak
  scsi: qla2xxx: Fix BSG job leak on validate flash image error path
  scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions()

 drivers/scsi/qla2xxx/qla_attr.c   |   55 +-
 drivers/scsi/qla2xxx/qla_bsg.c    |  475 +++++++++--
 drivers/scsi/qla2xxx/qla_bsg.h    |   34 +
 drivers/scsi/qla2xxx/qla_dbg.c    |   31 +-
 drivers/scsi/qla2xxx/qla_def.h    |  140 +++-
 drivers/scsi/qla2xxx/qla_dfs.c    |    4 +-
 drivers/scsi/qla2xxx/qla_edif.c   |  104 ++-
 drivers/scsi/qla2xxx/qla_fw.h     |  140 +++-
 drivers/scsi/qla2xxx/qla_fw29.h   |  830 ++++++++++++++++++
 drivers/scsi/qla2xxx/qla_gbl.h    |   40 +-
 drivers/scsi/qla2xxx/qla_gs.c     |  174 +++-
 drivers/scsi/qla2xxx/qla_init.c   |  692 ++++++++++++++-
 drivers/scsi/qla2xxx/qla_inline.h |  247 +++++-
 drivers/scsi/qla2xxx/qla_iocb.c   | 1304 +++++++++++++++++++++++------
 drivers/scsi/qla2xxx/qla_isr.c    |  756 +++++++++++------
 drivers/scsi/qla2xxx/qla_mbx.c    |  482 ++++++++---
 drivers/scsi/qla2xxx/qla_mid.c    |   74 +-
 drivers/scsi/qla2xxx/qla_nvme.c   |  288 +++++--
 drivers/scsi/qla2xxx/qla_nvme.h   |    4 +-
 drivers/scsi/qla2xxx/qla_nx.c     |    2 +-
 drivers/scsi/qla2xxx/qla_os.c     |  273 +++++-
 drivers/scsi/qla2xxx/qla_sup.c    |  761 ++++++++++++++++-
 drivers/scsi/qla2xxx/qla_target.c |   17 +-
 23 files changed, 5920 insertions(+), 1007 deletions(-)
 create mode 100644 drivers/scsi/qla2xxx/qla_fw29.h


base-commit: f9a7112b50efe8e115ca335ff57ed7504646a734
-- 
2.47.3


^ permalink raw reply	[flat|nested] 154+ messages in thread

* [PATCH v2 01/60] scsi: qla2xxx: Add 29xx series PCI device ID support
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:30   ` sashiko-bot
  2026-06-12 10:40   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 02/60] scsi: qla2xxx: Add flash read/write interface for 29xx Nilesh Javali
                   ` (58 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Manish Rangankar <mrangankar@marvell.com>

The QLA29xx is a new generation FC HBA that shares much of its
architecture with the 27xx/28xx family.  Register the new PCI
device IDs, wire up IS_QLA29XX() capability checks in the probe
and ISP-flags paths, and extend speed-capability logic so the
driver correctly recognises and initialises 29xx adapters.

Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_def.h  | 33 +++++++++++----
 drivers/scsi/qla2xxx/qla_init.c |  2 +-
 drivers/scsi/qla2xxx/qla_isr.c  |  5 ++-
 drivers/scsi/qla2xxx/qla_os.c   | 74 ++++++++++++++++++++++++++-------
 4 files changed, 88 insertions(+), 26 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 5593ad7fad27..6337a056b149 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3528,7 +3528,6 @@ struct isp_operations {
 #define QLA_MIDX_DEFAULT	0
 #define QLA_MIDX_RSP_Q		1
 #define QLA_PCI_MSIX_CONTROL	0xa2
-#define QLA_83XX_PCI_MSIX_CONTROL	0x92
 
 struct scsi_qla_host;
 
@@ -4287,6 +4286,10 @@ struct qla_hw_data {
 #define PCI_DEVICE_ID_QLOGIC_ISP2089	0x2089
 #define PCI_DEVICE_ID_QLOGIC_ISP2281	0x2281
 #define PCI_DEVICE_ID_QLOGIC_ISP2289	0x2289
+#define PCI_DEVICE_ID_QLOGIC_ISP2099	0x2099
+#define PCI_DEVICE_ID_QLOGIC_ISP2299	0x2299
+#define PCI_DEVICE_ID_QLOGIC_ISP2091	0x2091
+#define PCI_DEVICE_ID_QLOGIC_ISP2291	0x2291
 
 	uint32_t	isp_type;
 #define DT_ISP2100                      BIT_0
@@ -4316,7 +4319,11 @@ struct qla_hw_data {
 #define DT_ISP2089			BIT_24
 #define DT_ISP2281			BIT_25
 #define DT_ISP2289			BIT_26
-#define DT_ISP_LAST			(DT_ISP2289 << 1)
+#define DT_ISP2299			BIT_27
+#define DT_ISP2099			BIT_28
+#define DT_ISP2091			BIT_29
+#define DT_ISP2291			BIT_30
+#define DT_ISP_LAST			((uint32_t)DT_ISP2291 << 1)
 
 	uint32_t	device_type;
 #define DT_T10_PI                       BIT_25
@@ -4353,6 +4360,10 @@ struct qla_hw_data {
 #define IS_QLA2261(ha)	(DT_MASK(ha) & DT_ISP2261)
 #define IS_QLA2081(ha)	(DT_MASK(ha) & DT_ISP2081)
 #define IS_QLA2281(ha)	(DT_MASK(ha) & DT_ISP2281)
+#define IS_QLA2299(ha)	(DT_MASK(ha) & DT_ISP2299)
+#define IS_QLA2099(ha)	(DT_MASK(ha) & DT_ISP2099)
+#define IS_QLA2091(ha)	(DT_MASK(ha) & DT_ISP2091)
+#define IS_QLA2291(ha)	(DT_MASK(ha) & DT_ISP2291)
 
 #define IS_QLA23XX(ha)  (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
 			IS_QLA6312(ha) || IS_QLA6322(ha))
@@ -4363,6 +4374,9 @@ struct qla_hw_data {
 #define IS_QLA84XX(ha)  (IS_QLA8432(ha))
 #define IS_QLA27XX(ha)  (IS_QLA2071(ha) || IS_QLA2271(ha) || IS_QLA2261(ha))
 #define IS_QLA28XX(ha)	(IS_QLA2081(ha) || IS_QLA2281(ha))
+#define IS_QLA29XX(ha)	(IS_QLA2099(ha) || IS_QLA2299(ha) || \
+			 IS_QLA2091(ha) || IS_QLA2291(ha))
+
 #define IS_QLA24XX_TYPE(ha)     (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
 				IS_QLA84XX(ha))
 #define IS_CNA_CAPABLE(ha)	(IS_QLA81XX(ha) || IS_QLA82XX(ha) || \
@@ -4372,9 +4386,10 @@ struct qla_hw_data {
 				IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
 				IS_QLA82XX(ha) || IS_QLA83XX(ha) || \
 				IS_QLA8044(ha) || IS_QLA27XX(ha) || \
-				IS_QLA28XX(ha))
+				IS_QLA28XX(ha) || IS_QLA29XX(ha))
 #define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
-				IS_QLA27XX(ha) || IS_QLA28XX(ha))
+				IS_QLA27XX(ha) || IS_QLA28XX(ha) || \
+				IS_QLA29XX(ha))
 #define IS_NOPOLLING_TYPE(ha)	(IS_QLA81XX(ha) && (ha)->flags.msix_enabled)
 #define IS_FAC_REQUIRED(ha)	(IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
 				IS_QLA27XX(ha) || IS_QLA28XX(ha))
@@ -4390,9 +4405,9 @@ struct qla_hw_data {
 #define HAS_EXTENDED_IDS(ha)    ((ha)->device_type & DT_EXTENDED_IDS)
 #define IS_CT6_SUPPORTED(ha)	((ha)->device_type & DT_CT6_SUPPORTED)
 #define IS_MQUE_CAPABLE(ha)	(IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
-				 IS_QLA28XX(ha))
+				 IS_QLA28XX(ha) || IS_QLA29XX(ha))
 #define IS_BIDI_CAPABLE(ha) \
-    (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
+    (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
 /* Bit 21 of fw_attributes decides the MCTP capabilities */
 #define IS_MCTP_CAPABLE(ha)	(IS_QLA2031(ha) && \
 				((ha)->fw_attributes_ext[0] & BIT_0))
@@ -4408,12 +4423,12 @@ struct qla_hw_data {
 	(QLA_NVME_IOS(_sp) && QLA_ABTS_FW_ENABLED(_sp->fcport->vha->hw))
 
 #define IS_PI_UNINIT_CAPABLE(ha)	(IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
-					 IS_QLA28XX(ha))
+					 IS_QLA28XX(ha) || IS_QLA29XX(ha))
 #define IS_PI_IPGUARD_CAPABLE(ha)	(IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
-					 IS_QLA28XX(ha))
+					 IS_QLA28XX(ha) || IS_QLA29XX(ha))
 #define IS_PI_DIFB_DIX0_CAPABLE(ha)	(0)
 #define IS_PI_SPLIT_DET_CAPABLE_HBA(ha)	(IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
-					IS_QLA28XX(ha))
+					IS_QLA28XX(ha) || IS_QLA29XX(ha))
 #define IS_PI_SPLIT_DET_CAPABLE(ha)	(IS_PI_SPLIT_DET_CAPABLE_HBA(ha) && \
     (((ha)->fw_attributes_h << 16 | (ha)->fw_attributes) & BIT_22))
 #define IS_ATIO_MSIX_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index e746c9274cde..e23e7ac48ae2 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -2773,7 +2773,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
 	ha->isp_ops->reset_chip(vha);
 
 	/* Check for secure flash support */
-	if (IS_QLA28XX(ha)) {
+	if (IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 		if (rd_reg_word(&reg->mailbox12) & BIT_0)
 			ha->flags.secure_adapter = 1;
 		ql_log(ql_log_info, vha, 0xffff, "Secure Adapter: %s\n",
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 33776330956c..c47c38e099ff 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -4663,7 +4663,8 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
 	/* If possible, enable MSI-X. */
 	if (ql2xenablemsix == 0 || (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
 	    !IS_QLA8432(ha) && !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) &&
-	    !IS_QLAFX00(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)))
+	    !IS_QLAFX00(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha) &&
+	    !IS_QLA29XX(ha)))
 		goto skip_msi;
 
 	if (ql2xenablemsix == 2)
@@ -4702,7 +4703,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
 
 	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
 	    !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) &&
-	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
 		goto skip_msi;
 
 	ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 72b1c28e4dae..c91d2b8bd08e 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -429,7 +429,8 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req,
 	qla_cpu_update(rsp->qpair, raw_smp_processor_id());
 	ha->base_qpair->pdev = ha->pdev;
 
-	if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha))
+	if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha) ||
+	    IS_QLA29XX(ha))
 		ha->base_qpair->reqq_start_iocbs = qla_83xx_start_iocbs;
 }
 
@@ -2153,8 +2154,6 @@ qla2x00_iospace_config(struct qla_hw_data *ha)
 static int
 qla83xx_iospace_config(struct qla_hw_data *ha)
 {
-	uint16_t msix;
-
 	if (pci_request_selected_regions(ha->pdev, ha->bars,
 	    QLA2XXX_DRIVER_NAME)) {
 		ql_log_pci(ql_log_fatal, ha->pdev, 0x0117,
@@ -2203,10 +2202,18 @@ qla83xx_iospace_config(struct qla_hw_data *ha)
 	ha->msixbase = ioremap(pci_resource_start(ha->pdev, 2),
 			pci_resource_len(ha->pdev, 2));
 	if (ha->msixbase) {
+		int msix_cnt;
+
 		/* Read MSIX vector size of the board */
-		pci_read_config_word(ha->pdev,
-		    QLA_83XX_PCI_MSIX_CONTROL, &msix);
-		ha->msix_count = (msix & PCI_MSIX_FLAGS_QSIZE)  + 1;
+		msix_cnt = pci_msix_vec_count(ha->pdev);
+		if (msix_cnt <= 0) {
+			ql_log_pci(ql_log_warn, ha->pdev, 0x0120,
+				   "Failed to read MSI-X count (%d), falling back to base vectors.\n",
+				   msix_cnt);
+			goto mqiobase_exit;
+		}
+		ha->msix_count = msix_cnt;
+
 		/*
 		 * By default, driver uses at least two msix vectors
 		 * (default & rspq)
@@ -2796,6 +2803,20 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
 		ha->device_type |= DT_T10_PI;
 		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
 		break;
+	case PCI_DEVICE_ID_QLOGIC_ISP2099:
+	case PCI_DEVICE_ID_QLOGIC_ISP2299:
+	case PCI_DEVICE_ID_QLOGIC_ISP2091:
+	case PCI_DEVICE_ID_QLOGIC_ISP2291:
+		ha->isp_type |= DT_ISP2299;
+		ha->isp_type |= DT_ISP2099;
+		ha->isp_type |= DT_ISP2091;
+		ha->isp_type |= DT_ISP2291;
+		ha->device_type |= DT_ZIO_SUPPORTED;
+		ha->device_type |= DT_FWI2;
+		ha->device_type |= DT_IIDMA;
+		ha->device_type |= DT_T10_PI;
+		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+		break;
 	}
 
 	if (IS_QLA82XX(ha))
@@ -2803,8 +2824,8 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
 	else {
 		/* Get adapter physical port no from interrupt pin register. */
 		pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no);
-		if (IS_QLA25XX(ha) || IS_QLA2031(ha) ||
-		    IS_QLA27XX(ha) || IS_QLA28XX(ha))
+		if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
+		    IS_QLA28XX(ha) || IS_QLA29XX(ha))
 			ha->port_no--;
 		else
 			ha->port_no = !(ha->port_no & 1);
@@ -2936,7 +2957,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2081 ||
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2281 ||
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2089 ||
-	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2289) {
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2289 ||
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2099 ||
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2299 ||
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2091 ||
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2291) {
 		bars = pci_select_bars(pdev, IORESOURCE_MEM);
 		mem_only = 1;
 		ql_dbg_pci(ql_dbg_init, pdev, 0x0007,
@@ -2998,7 +3023,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	/* Set EEH reset type to fundamental if required by hba */
 	if (IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha) ||
-	    IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
+	    IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
+	    IS_QLA29XX(ha))
 		pdev->needs_freset = 1;
 
 	ha->prev_topology = 0;
@@ -3195,6 +3221,22 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 		ha->flash_data_off = FARX_ACCESS_FLASH_DATA_28XX;
 		ha->nvram_conf_off = ~0;
 		ha->nvram_data_off = ~0;
+	} else if (IS_QLA29XX(ha)) {
+		ha->portnum = PCI_FUNC(ha->pdev->devfn);
+		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
+		ha->mbx_count = MAILBOX_REGISTER_COUNT;
+		req_length = REQUEST_ENTRY_CNT_83XX;
+		rsp_length = RESPONSE_ENTRY_CNT_83XX;
+		ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
+		ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
+		ha->gid_list_info_size = 8;
+		ha->optrom_size = OPTROM_SIZE_28XX;
+		ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
+		ha->isp_ops = &qla27xx_isp_ops;
+		ha->flash_conf_off = ~0;
+		ha->flash_data_off = ~0;
+		ha->nvram_conf_off = ~0;
+		ha->nvram_data_off = ~0;
 	}
 
 	ql_dbg_pci(ql_dbg_init, pdev, 0x001e,
@@ -3373,7 +3415,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	rsp->rsp_q_in = &ha->iobase->isp24.rsp_q_in;
 	rsp->rsp_q_out = &ha->iobase->isp24.rsp_q_out;
 	if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
-	    IS_QLA28XX(ha)) {
+	    IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 		req->req_q_in = &ha->mqiobase->isp25mq.req_q_in;
 		req->req_q_out = &ha->mqiobase->isp25mq.req_q_out;
 		rsp->rsp_q_in = &ha->mqiobase->isp25mq.rsp_q_in;
@@ -3898,7 +3940,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
 		return;
 
 	if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
-	    IS_QLA28XX(ha)) {
+	    IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 		if (ha->flags.fw_started)
 			qla2x00_abort_isp_cleanup(base_vha);
 	} else if (!IS_QLAFX00(ha)) {
@@ -4387,7 +4429,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 
 	/* Get consistent memory allocated for EX-INIT-CB. */
 	if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
-	    IS_QLA28XX(ha)) {
+	    IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 		ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
 		    &ha->ex_init_cb_dma);
 		if (!ha->ex_init_cb)
@@ -4397,7 +4439,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	}
 
 	/* Get consistent memory allocated for Special Features-CB. */
-	if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+	if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 		ha->sf_init_cb = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL,
 						&ha->sf_init_cb_dma);
 		if (!ha->sf_init_cb)
@@ -8155,6 +8197,10 @@ static const struct pci_device_id qla2xxx_pci_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2281) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2089) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2289) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2099) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2299) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2091) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2291) },
 	{ 0 },
 };
 MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 02/60] scsi: qla2xxx: Add flash read/write interface for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
  2026-06-12  9:52 ` [PATCH v2 01/60] scsi: qla2xxx: Add 29xx series PCI device ID support Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:16   ` sashiko-bot
  2026-06-12 10:43   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 03/60] scsi: qla2xxx: Add NVRAM config support for 29xx adapters Nilesh Javali
                   ` (57 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Manish Rangankar <mrangankar@marvell.com>

The 29xx series uses a different flash access mechanism than
earlier adapters.  Add the mailbox wrappers and qla_sup helpers
needed for flash read and write operations, including the
necessary hooks in isp_ops so that the existing flash
infrastructure can drive the new hardware.

Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_def.h |  20 +
 drivers/scsi/qla2xxx/qla_fw.h  |  54 +++
 drivers/scsi/qla2xxx/qla_gbl.h |  15 +-
 drivers/scsi/qla2xxx/qla_mbx.c | 144 +++++++
 drivers/scsi/qla2xxx/qla_os.c  |  18 +-
 drivers/scsi/qla2xxx/qla_sup.c | 661 ++++++++++++++++++++++++++++++++-
 6 files changed, 905 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 6337a056b149..b5ad6ed3d5d1 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1278,6 +1278,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs)
 #define MBC_LOAD_RISC_RAM		9	/* Load RAM command. */
 #define MBC_DUMP_RISC_RAM		0xa	/* Dump RAM command. */
 #define MBC_SECURE_FLASH_UPDATE		0xa	/* Secure Flash Update(28xx) */
+#define MBC_RD_WR_FLASH			0xa	/* Read/write Dword/block Flash(29xx) */
 #define MBC_LOAD_RISC_RAM_EXTENDED	0xb	/* Load RAM extended. */
 #define MBC_DUMP_RISC_RAM_EXTENDED	0xc	/* Dump RAM extended. */
 #define MBC_WRITE_RAM_WORD_EXTENDED	0xd	/* Write RAM word extended */
@@ -4170,6 +4171,7 @@ struct qla_hw_data {
 #define EEH_FLUSH_RDY  1
 #define EEH_FLUSH_DONE 2
 		uint32_t	secure_mcu:1;
+		uint32_t	valid_flt:1;
 	} flags;
 
 	uint16_t max_exchg;
@@ -4498,6 +4500,8 @@ struct qla_hw_data {
 
 	struct qla_flt_header *flt;
 	dma_addr_t	flt_dma;
+	struct qla_flash_layout *flt_data;
+	uint32_t	fw_dump_tmplt_len;
 
 #define XGMAC_DATA_SIZE	4096
 	void		*xgmac_data;
@@ -4722,6 +4726,9 @@ struct qla_hw_data {
 	uint32_t	fdt_protect_sec_cmd;
 	uint32_t	fdt_wrt_sts_reg_cmd;
 
+#define QLA_SEGMENT_LENGTH      0x25000
+	uint32_t        flt_segment_length;
+
 	struct {
 		uint32_t	flt_region_flt;
 		uint32_t	flt_region_fdt;
@@ -5348,6 +5355,14 @@ static inline bool qla_vha_mark_busy(scsi_qla_host_t *vha)
 /*
  * Flash support definitions
  */
+#define check_and_set_mbc_bits(bopt, dopt, bit_to_check, bit_to_set) {	\
+	if (bopt & bit_to_check)			\
+		dopt |= bit_to_set;			\
+}
+
+#define SET_FW_BIT(__opts, bit) ((__opts) |= (bit))
+#define CLEAR_FW_BIT(__opts, bit) ((__opts) &= ~(bit))
+
 #define OPTROM_SIZE_2300	0x20000
 #define OPTROM_SIZE_2322	0x100000
 #define OPTROM_SIZE_24XX	0x100000
@@ -5612,4 +5627,9 @@ struct ql_vnd_tgt_stats_resp {
 	(!_fcport || IS_SESSION_DELETED(_fcport) || atomic_read(&_fcport->state) != FCS_ONLINE || \
 	!_fcport->vha->hw->flags.fw_started)
 
+#define is_flash_read(_opt)	\
+	(!(_opt & BIT_9) && !(_opt & BIT_6))
+
+#define is_flash_write(_opt)	\
+	(!(_opt & BIT_9) && (_opt & BIT_6))
 #endif
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index f307beed9d29..d27d09964a24 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1695,6 +1695,10 @@ struct qla_flt_location {
 #define FLT_REG_NVME_PARAMS_PRI_28XX	0x14E
 #define FLT_REG_NVME_PARAMS_SEC_28XX	0x179
 
+/* 29xx */
+#define FLT_REG_MINI_FLT		0x201
+#define FLT_REG_FW_DUMP_TMPLT		0x1A0
+
 struct qla_flt_region {
 	__le16	code;
 	uint8_t attribute;
@@ -1716,6 +1720,56 @@ struct qla_flt_header {
 #define FLT_MAX_REGIONS		0xFF
 #define FLT_REGIONS_SIZE	(FLT_REGION_SIZE * FLT_MAX_REGIONS)
 
+/* 29xx */
+#define FLT_HDR_VERSION		0x2
+
+struct qla_flt_region_header {
+	__le32	signature;
+	__le32	version;
+	__le32	length;
+	__le32	checksum;
+	__le16	region_count;
+	__le16	region_size;
+	__le32	segment_size;
+	__le32	res3;
+	__le32	res4;
+	__le32	res5;
+	__le32	res6;
+	__le32	res7;
+	__le32	res8;
+	__le32	res9;
+	__le32	res10;
+	__le32	res11;
+	__le32	res12;
+};
+
+struct qla_flt_region_data {
+	__le16	region_code;
+	__le16	reserved;
+	__le32	attribute;
+	__le32	image_length;
+	__le32	mbi_offset;
+	__le32	version;
+	__le32	card_type;
+	__le32	chip_revision;
+	__le32	res4;
+	__le32	res5;
+	__le32	res6;
+	__le32	res7;
+	__le32	res8;
+	__le32	res9;
+	__le32	res10;
+	__le32	res11;
+	__le32	res12;
+};
+
+struct qla_flash_layout {
+	struct qla_flt_region_header flt_header;
+	struct qla_flt_region_data region[];
+};
+
+#define FLT_DATA_MAX_REGIONS	0xFF
+
 /* Flash NPIV Configuration Table ********************************************/
 
 struct qla_npiv_header {
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 9e328c235e39..a032dd047a8f 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -580,6 +580,12 @@ extern int qla2xxx_read_remote_register(scsi_qla_host_t *, uint32_t,
 extern int qla2xxx_write_remote_register(scsi_qla_host_t *, uint32_t,
     uint32_t);
 void qla_no_op_mb(struct scsi_qla_host *vha);
+extern int qla29xx_flash_block_read(scsi_qla_host_t *vha, dma_addr_t req_dma,
+				    uint32_t flash_addr, uint32_t flash_size,
+				    uint16_t reg_code, uint16_t opt);
+extern int qla29xx_flash_block_write(scsi_qla_host_t *vha, dma_addr_t req_dma,
+				     uint32_t flash_addr, uint32_t flash_size,
+				     uint16_t reg_code, uint16_t opt);
 
 /*
  * Global Function Prototypes in qla_isr.c source file.
@@ -682,7 +688,14 @@ struct purex_item *qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha,
 	void **pkt, struct rsp_que **rsp, bool is_purls, bool byte_order);
 int qla_mailbox_passthru(scsi_qla_host_t *vha, uint16_t *mbx_in,
 			 uint16_t *mbx_out);
-
+void *qla29xx_read_optrom_data(struct scsi_qla_host *vha,
+				       uint16_t reg_code, uint16_t opts,
+				       void *buf, uint32_t offset,
+				       uint32_t length);
+extern int qla29xx_write_optrom_data(struct scsi_qla_host *vha,
+				     uint16_t reg_code, uint16_t opts,
+				     void *buf, uint32_t offset,
+				     uint32_t length);
 /*
  * Global Function Prototypes in qla_dbg.c source file.
  */
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 44e310f1a370..2d052f870b2b 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -7254,3 +7254,147 @@ int qla_mpipt_validate_fw(scsi_qla_host_t *vha, u16 img_idx, uint16_t *state)
 
 	return rval;
 }
+
+int qla29xx_flash_block_read(scsi_qla_host_t *vha, dma_addr_t req_dma,
+			     uint32_t flash_addr, uint32_t flash_size,
+			     uint16_t reg_code, uint16_t opt)
+{
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	int rval = 0;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1067,
+			"Entered %s options 0x%x.\n", __func__, opt);
+
+	memset(mcp->mb, 0, sizeof(mcp->mb));
+
+	if (!is_flash_read(opt)) {
+		ql_log(ql_log_info, vha, 0x1068,
+				"%s: Invalid flash option 0x%x.\n", __func__, opt);
+		return -EINVAL;
+	}
+
+	mcp->mb[0] = MBC_RD_WR_FLASH;
+
+	/* mailbox option field :
+	 *      TIM img or Img  : BIT_15 (1/0)
+	 *       Last seg img   : BIT_11 (1)
+	 *      First seg img   : BIT_10  (1)
+	 *      dword or block  : BIT_9  (1/0)
+	 *     flash MBR update : BIT_8  (1/0)
+	 * Secure or non-secure : BIT_7  (1/0)
+	 *        Write or Read : BIT_6  (1/0)
+	 *       Last block img : BIT_5  (1)
+	 *      First block img : BIT_4  (1)
+	 *         Request type : (BIT3 - BIT_0)
+	 *                        - Normal
+	 *                        - Normal, Force Sema
+	 *                        - Initialize
+	 *                        - Initialize, Force sema
+	 *                        - Abort secured update
+	 */
+	mcp->mb[1] = opt;
+	mcp->mb[2] = reg_code;
+
+	mcp->mb[3] = MSW(flash_size);
+	mcp->mb[4] = LSW(flash_size);
+
+	mcp->mb[5] = MSW(req_dma);
+	mcp->mb[6] = LSW(req_dma);
+	mcp->mb[7] = MSW(MSD(req_dma));
+	mcp->mb[8] = LSW(MSD(req_dma));
+
+	mcp->mb[9] = MSW(flash_addr);
+	mcp->mb[10] = LSW(flash_addr);
+
+	mcp->out_mb =
+		MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		ql_dbg(ql_dbg_mbx, vha, 0x103f,
+				"Failed=%x mb=(0x%x,0x%x,0x%x,0x%x).\n",
+				rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]);
+	} else {
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1043,
+				"Done %s mb=(0x%x,0x%x,0x%x).\n", __func__,
+				mcp->mb[0], mcp->mb[1],  mcp->mb[2]);
+	}
+
+	return rval;
+}
+
+int qla29xx_flash_block_write(scsi_qla_host_t *vha, dma_addr_t req_dma,
+			      uint32_t flash_addr, uint32_t flash_size,
+			      uint16_t reg_code, uint16_t opt)
+{
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	int rval = 0;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1069,
+			"Entered %s options 0x%x.\n", __func__, opt);
+
+	memset(mcp->mb, 0, sizeof(mcp->mb));
+
+	if (!is_flash_write(opt)) {
+		ql_log(ql_log_info, vha, 0x106a,
+				"%s: Invalid flash option 0x%x.\n", __func__, opt);
+		return -EINVAL;
+	}
+
+	mcp->mb[0] = MBC_RD_WR_FLASH;
+
+	/* mailbox option field :
+	 *      TIM img or Img  : BIT_15 (1/0)
+	 *       Last seg img   : BIT_11 (1)
+	 *      First seg img   : BIT_10  (1)
+	 *      dword or block  : BIT_9  (1/0)
+	 *     flash MBR update : BIT_8  (1/0)
+	 * Secure or non-secure : BIT_7  (1/0)
+	 *        Write or Read : BIT_6  (1/0)
+	 *       Last block img : BIT_5  (1)
+	 *      First block img : BIT_4  (1)
+	 *         Request type : (BIT3 - BIT_0)
+	 *                        - Normal
+	 *                        - Normal, Force Sema
+	 *                        - Initialize
+	 *                        - Initialize, Force sema
+	 *                        - Abort secured update
+	 */
+	mcp->mb[1] = opt;
+	mcp->mb[2] = reg_code;
+
+	mcp->mb[3] = MSW(flash_size);
+	mcp->mb[4] = LSW(flash_size);
+
+	mcp->mb[5] = MSW(req_dma);
+	mcp->mb[6] = LSW(req_dma);
+	mcp->mb[7] = MSW(MSD(req_dma));
+	mcp->mb[8] = LSW(MSD(req_dma));
+
+	mcp->mb[9] = MSW(flash_addr);
+	mcp->mb[10] = LSW(flash_addr);
+
+	mcp->out_mb =
+		MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		ql_dbg(ql_dbg_mbx, vha, 0x110a,
+				"Failed=%x mb=(0x%x,0x%x,0x%x,0x%x).\n",
+				rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]);
+	} else {
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x110b,
+				"Done %s mb=(0x%x,0x%x,0x%x).\n", __func__,
+				mcp->mb[0], mcp->mb[1],  mcp->mb[2]);
+	}
+
+	return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index c91d2b8bd08e..ebb97329e6ea 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -3237,6 +3237,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 		ha->flash_data_off = ~0;
 		ha->nvram_conf_off = ~0;
 		ha->nvram_data_off = ~0;
+		ha->flt_segment_length = QLA_SEGMENT_LENGTH;
 	}
 
 	ql_dbg_pci(ql_dbg_init, pdev, 0x001e,
@@ -4488,6 +4489,14 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 		goto fail_flt_buffer;
 	}
 
+	ha->flt_data = vzalloc(sizeof(struct qla_flash_layout) +
+			(sizeof(struct qla_flt_region_data) * FLT_MAX_REGIONS));
+	if (!ha->flt_data) {
+		ql_dbg_pci(ql_dbg_init, ha->pdev, 0x001a,
+			   "Unable to allocate memory for mini FLT data.\n");
+		goto fail_flt;
+	}
+
 	/* allocate the purex dma pool */
 	ha->purex_dma_pool = dma_pool_create(name, &ha->pdev->dev,
 	    ELS_MAX_PAYLOAD, 8, 0);
@@ -4495,7 +4504,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	if (!ha->purex_dma_pool) {
 		ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b,
 		    "Unable to allocate purex_dma_pool.\n");
-		goto fail_flt;
+		goto fail_flt_data;
 	}
 
 	ha->elsrej.size = sizeof(struct fc_els_ls_rjt) + 16;
@@ -4528,6 +4537,9 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 			  ha->elsrej.c, ha->elsrej.cdma);
 fail_elsrej:
 	dma_pool_destroy(ha->purex_dma_pool);
+fail_flt_data:
+	vfree(ha->flt_data);
+	ha->flt_data = NULL;
 fail_flt:
 	dma_free_coherent(&ha->pdev->dev, sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE,
 	    ha->flt, ha->flt_dma);
@@ -4963,6 +4975,10 @@ qla2x00_mem_free(struct qla_hw_data *ha)
 	ha->flt = NULL;
 	ha->flt_dma = 0;
 
+	if (ha->flt_data)
+		vfree(ha->flt_data);
+	ha->flt_data = NULL;
+
 	if (ha->ms_iocb)
 		dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
 	ha->ms_iocb = NULL;
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index b6c36a8a2d60..eb10904f14ca 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -10,6 +10,651 @@
 #include <linux/vmalloc.h>
 #include <linux/uaccess.h>
 
+/**
+ * qla29xx_get_flt_layout - Retrieve the flash layout table (FLT) for QLA29xx.
+ * @vha: Pointer to SCSI QLogic host structure.
+ *
+ * This function reads and validates the FLT structure from the flash memory.
+ * It extracts region information and updates the hardware data structure.
+ */
+static void
+qla29xx_get_flt_layout(scsi_qla_host_t *vha)
+{
+	struct qla_hw_data *ha = vha->hw;
+	struct qla_flash_layout *flt_layout = ha->flt_data;
+	struct qla_flt_region_header *flt_header = &flt_layout->flt_header;
+	struct qla_flt_region_data *region = &flt_layout->region[0];
+	uint32_t flt_options = 0;
+	uint32_t flt_size;
+	uint32_t cnt, chksum;
+	uint16_t reg_cnt, i;
+	__le32 *wptr;
+	void *buf = NULL;
+
+	flt_size = sizeof(struct qla_flt_region_header);
+	wptr = (__force __le32 *)ha->flt_data;
+
+	buf = qla29xx_read_optrom_data(vha, FLT_REG_MINI_FLT, flt_options,
+				       ha->flt_data, 0, flt_size);
+	if (!buf) {
+		ql_log(ql_log_warn, vha, 0x007b,
+		    "Failed to read FLT information.\n");
+		goto exit_flt;
+	}
+
+	ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0111,
+	       "Contents of Flash Layout (0x%x):\n", flt_size);
+	ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0112,
+		       ha->flt_data, flt_size);
+
+	/* check flt version checksum and other info */
+	if ((le32_to_cpu(*wptr) == 0xffff) &&
+	    flt_header->version != cpu_to_le32(FLT_HDR_VERSION)) {
+		ql_log(ql_log_warn, vha, 0x007c,
+		    "Unsupported FLT detected: version=0x%x length=0x%x signature=0x%x region_count=0x%x checksum=0x%x.\n",
+		    le32_to_cpu(flt_header->version),
+		    le32_to_cpu(flt_header->length),
+		    le32_to_cpu(flt_header->signature),
+		    le16_to_cpu(flt_header->region_count),
+		    le32_to_cpu(flt_header->checksum));
+		goto exit_flt;
+	}
+
+	reg_cnt = le16_to_cpu(flt_header->region_count);
+	if (reg_cnt > FLT_MAX_REGIONS)
+		goto exit_flt;
+
+	flt_size = sizeof(struct qla_flash_layout) +
+		   (reg_cnt * le16_to_cpu(flt_header->region_size));
+	if (flt_size > sizeof(struct qla_flash_layout) +
+	    sizeof(struct qla_flt_region_data) * FLT_DATA_MAX_REGIONS) {
+		ql_log(ql_log_warn, vha, 0x007d,
+		    "FLT size 0x%x exceeds buffer, region_size=0x%x.\n",
+		    flt_size, le16_to_cpu(flt_header->region_size));
+		goto exit_flt;
+	}
+
+	buf = qla29xx_read_optrom_data(vha, FLT_REG_MINI_FLT, flt_options,
+				       ha->flt_data, 0, flt_size);
+	if (!buf) {
+		ql_log(ql_log_warn, vha, 0x007b,
+		    "Failed to read FLT information.\n");
+		goto exit_flt;
+	}
+
+	cnt = le32_to_cpu(flt_header->length) / sizeof(*wptr);
+	if (cnt > flt_size / sizeof(*wptr)) {
+		ql_log(ql_log_warn, vha, 0x007e,
+		    "FLT length 0x%x exceeds read size 0x%x, rejecting.\n",
+		    le32_to_cpu(flt_header->length), flt_size);
+		goto exit_flt;
+	}
+	for (chksum = 0; cnt--; wptr++)
+		chksum += le32_to_cpu(*wptr);
+	if (chksum) {
+		ql_log(ql_log_fatal, vha, 0x007f,
+		    "Inconsistent FLT detected: version=0x%x length=0x%x signature=0x%x checksum=0x%x.\n",
+		    le32_to_cpu(flt_header->version),
+		    le32_to_cpu(flt_header->length),
+		    le32_to_cpu(flt_header->signature),
+		    le32_to_cpu(flt_header->checksum));
+		goto exit_flt;
+	}
+
+	ql_dbg(ql_dbg_init, vha, 0x007f,
+		"FLT detected: version=0x%08x length=0x%08x signature=0x%08x region_count=0x%04x region_len=0x%04x segment_len=0x%08x checksum=0x%08x.\n",
+		le32_to_cpu(flt_header->version),
+		le32_to_cpu(flt_header->length),
+		le32_to_cpu(flt_header->signature),
+		le16_to_cpu(flt_header->region_count),
+		le16_to_cpu(flt_header->region_size),
+		le32_to_cpu(flt_header->segment_size),
+		le32_to_cpu(flt_header->checksum));
+
+	for (i = 0; reg_cnt; i++, reg_cnt--) {
+		region = &flt_layout->region[i];
+		ql_dbg(ql_dbg_init, vha, 0x0080,
+		    "FLT[%03x]: len=0x%08x version=0x%08x attr=0x%02x.\n",
+		    le16_to_cpu(region->region_code),
+		    le32_to_cpu(region->image_length),
+		    le32_to_cpu(region->version),
+		    le32_to_cpu(region->attribute));
+		if (le16_to_cpu(region->region_code) == FLT_REG_FW_DUMP_TMPLT) {
+			ql_dbg(ql_dbg_init, vha, 0x0080,
+				"%s: %d: Found FW dump template", __func__, __LINE__);
+			ha->fw_dump_tmplt_len = le32_to_cpu(region->image_length);
+		}
+	}
+
+	if (le32_to_cpu(flt_header->segment_size) >= sizeof(uint32_t)) {
+		ha->flt_segment_length = le32_to_cpu(flt_header->segment_size);
+	} else {
+		ql_log(ql_log_warn, vha, 0x0081,
+		    "FLT segment size 0x%x too small, using default 0x%x.\n",
+		    le32_to_cpu(flt_header->segment_size), QLA_SEGMENT_LENGTH);
+		ha->flt_segment_length = QLA_SEGMENT_LENGTH;
+	}
+	ha->flags.valid_flt = true;
+	return;
+
+exit_flt:
+	ha->flt_segment_length = QLA_SEGMENT_LENGTH;
+}
+
+/**
+ * qla29xx_get_fdt_info - Retrieve flash descriptor table (FDT) information.
+ * @vha: Pointer to SCSI QLogic host structure.
+ *
+ * This function reads and validates the FDT structure from the flash memory.
+ * It extracts manufacturer and device-specific information and updates
+ * the hardware data structure.
+ */
+static void
+qla29xx_get_fdt_info(scsi_qla_host_t *vha)
+{
+#define FLASH_BLK_SIZE_4K	0x1000
+#define FLASH_BLK_SIZE_32K	0x8000
+#define FLASH_BLK_SIZE_64K	0x10000
+	struct qla_hw_data *ha = vha->hw;
+	struct req_que *req = ha->req_q_map[0];
+	uint16_t cnt, chksum;
+	__le16 *wptr = (__force __le16 *)req->ring;
+	struct qla_fdt_layout *fdt = (struct qla_fdt_layout *)req->ring;
+	uint32_t fdt_options = 0;
+	void *buf = NULL;
+
+	buf = qla29xx_read_optrom_data(vha, FLT_REG_FDT, fdt_options,
+					fdt, 0, sizeof(*fdt));
+	if (!buf) {
+		ql_log(ql_log_warn, vha, 0x0047,
+		    "Failed to read FLT information.\n");
+		return;
+	}
+
+	if (le16_to_cpu(*wptr) == 0xffff)
+		return;
+	if (memcmp(fdt->sig, "QLID", 4))
+		return;
+
+	for (cnt = 0, chksum = 0; cnt < sizeof(*fdt) >> 1; cnt++, wptr++)
+		chksum += le16_to_cpu(*wptr);
+	if (chksum) {
+		ql_dbg(ql_dbg_init, vha, 0x004c,
+			"Inconsistent FDT detected: checksum=0x%x id=%c version0x%x.\n",
+			chksum, fdt->sig[0], le16_to_cpu(fdt->version));
+		ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0113,
+		    fdt, sizeof(*fdt));
+		return;
+	}
+}
+
+/**
+ * qla29xx_get_flash_region - Retrieve flash region information for QLA29xx adapters.
+ * @vha: Pointer to SCSI QLogic host structure.
+ * @code: Region code to identify the flash region.
+ * @region: Pointer to store the retrieved flash region information.
+ *
+ * This function retrieves the flash region information for QLA29xx adapters
+ * based on the specified region code.
+ *
+ * Returns QLA_SUCCESS on success or QLA_FUNCTION_FAILED on failure.
+ */
+static int
+qla29xx_get_flash_region(struct scsi_qla_host *vha, uint32_t code,
+			 struct qla_flt_region_data *region)
+{
+	struct qla_hw_data *ha = vha->hw;
+	struct qla_flash_layout *flt = ha->flt_data;
+	struct qla_flt_region_header *flt_hdr = &flt->flt_header;
+	struct qla_flt_region_data *flt_reg = &flt->region[0];
+	uint16_t cnt;
+	int rval = QLA_FUNCTION_FAILED;
+
+	if (!ha->flt_data || !ha->flags.valid_flt)
+		return QLA_FUNCTION_FAILED;
+
+	cnt = le16_to_cpu(flt_hdr->region_count);
+	for (; cnt; cnt--, flt_reg++) {
+		if (le16_to_cpu(flt_reg->region_code) == code) {
+			memcpy((uint8_t *)region, flt_reg,
+			    sizeof(struct qla_flt_region_data));
+			rval = QLA_SUCCESS;
+			break;
+		}
+	}
+
+	return rval;
+}
+
+/**
+ * set_segment_bits - Set segment-related bits in the options field.
+ * @options: Pointer to the options field.
+ * @segment_index: Index of the current segment.
+ * @total: Total number of segments.
+ *
+ * This function sets the appropriate bits in the options field to indicate
+ * whether the current segment is the first, last, or a single segment.
+ */
+static void set_segment_bits(uint16_t *options, int segment_index, int total)
+{
+	/* - Single segment complete image.
+	 * - 1st Segment of an image.
+	 * - Last segment of an image.
+	 */
+	if (total == 1)
+		*options |= (1 << 10) | (1 << 11);
+	else if (segment_index == 0)
+		*options |= (1 << 10);
+	else if (segment_index == total - 1)
+		*options |= (1 << 11);
+}
+
+/**
+ * set_chunk_bits - Set chunk-related bits in the options field.
+ * @options: Pointer to the options field.
+ * @count: Index of the current chunk.
+ * @total: Total number of chunks.
+ *
+ * This function sets the appropriate bits in the options field to indicate
+ * whether the current chunk is the first, last, or a single chunk.
+ */
+static void set_chunk_bits(uint16_t *options, int count, int total)
+{
+	/* - Single chunk complete segment
+	 * - 1st chunk of a segment
+	 * - Last chunk of a segment
+	 */
+	if (total == 1)
+		*options |= (1 << 4) | (1 << 5);
+	else if (count == 0)
+		*options |= (1 << 4);
+	else if (count == total - 1)
+		*options |= (1 << 5);
+}
+
+/**
+ * qla29xx_write_optrom_data - Write data to the optrom for QLA29xx adapters.
+ * @vha: Pointer to SCSI QLogic host structure.
+ * @reg_code: Region code to write to.
+ * @opts: Options for the write operation.
+ * @buf: Buffer containing the data to write.
+ * @offset: Offset within the region to start writing.
+ * @length: Length of data to write.
+ *
+ * This function writes data to the specified optrom region for QLA29xx adapters.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int
+qla29xx_write_optrom_data(struct scsi_qla_host *vha, uint16_t reg_code,
+			 uint16_t opts, void *buf, uint32_t offset,
+			 uint32_t length)
+{
+	struct qla_hw_data *ha = vha->hw;
+	struct qla_flt_region_data region;
+	dma_addr_t optrom_dma;
+	uint32_t faddr, left, burst;
+	uint32_t img_len, seg_dlen;
+	uint32_t region_len, region_dlen;
+	void *optrom;
+	uint8_t *pbuf;
+	int rval = -EINVAL;
+	uint16_t total_segments, segment_index = 0;
+	uint16_t chunk_index = 0, chunk_count = 0;
+
+	memset(&region, 0, sizeof(region));
+
+	optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+				    &optrom_dma, GFP_KERNEL);
+	if (!optrom) {
+		ql_log(ql_log_warn, vha, 0x0090,
+		    "Unable to allocate memory for optrom burst read (%x KB).\n",
+		    OPTROM_BURST_SIZE / 1024);
+		return -ENOMEM;
+	}
+
+	if (ha->flags.valid_flt && length == 0) {
+		/* Get image length and segment length from FLT */
+		rval = qla29xx_get_flash_region(vha, reg_code, &region);
+		if (rval != QLA_SUCCESS) {
+			ql_log(ql_log_warn, vha, 0x0092,
+				"Invalid address %x - not a region start address\n",
+				reg_code);
+			goto free_buf;
+		}
+		img_len = le32_to_cpu(region.image_length);
+	} else {
+		img_len = length;
+	}
+
+	seg_dlen = ha->flt_segment_length >> 2;
+	region_len = (length > 0) ? length : img_len;
+	region_dlen = (region_len >> 2);
+	total_segments = (region_dlen + seg_dlen - 1) / seg_dlen;
+
+	faddr = offset >> 2;
+	left = region_dlen;
+	burst = OPTROM_BURST_DWORDS;
+	pbuf = buf;
+
+	while (region_dlen > 0) {
+		uint32_t segment_size, total_chunks;
+		uint16_t options = 0;
+
+		segment_size = (region_dlen > seg_dlen) ? seg_dlen : region_dlen;
+		total_chunks = (segment_size + OPTROM_BURST_DWORDS - 1) /
+				OPTROM_BURST_DWORDS;
+
+		burst = OPTROM_BURST_DWORDS;
+		if (burst > left)
+			burst = left;
+		if (burst > segment_size - chunk_index * OPTROM_BURST_DWORDS)
+			burst = segment_size - chunk_index * OPTROM_BURST_DWORDS;
+
+		set_segment_bits(&options, segment_index, total_segments);
+		set_chunk_bits(&options, chunk_index, total_chunks);
+
+		/* flash block write operations */
+		SET_FW_BIT(options, BIT_6);
+		CLEAR_FW_BIT(options, BIT_9);
+
+		check_and_set_mbc_bits(opts, options, BIT_15, BIT_15);
+		check_and_set_mbc_bits(opts, options, BIT_7, BIT_7);
+
+		if (segment_index == total_segments - 1 &&
+		    chunk_index == total_chunks - 1)
+			check_and_set_mbc_bits(opts, options, BIT_8, BIT_8);
+
+		memcpy(optrom, pbuf, burst * 4);
+
+		/* faddr is offset relative to region code */
+		rval = qla29xx_flash_block_write(vha, optrom_dma,
+				faddr, burst, reg_code, options);
+		if (rval) {
+			ql_log(ql_log_warn, vha, 0x0095,
+			    "Unable to burst-write optrom segment (%x/%x/%llx).\n",
+			    rval, faddr, (unsigned long long)optrom_dma);
+
+			dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+			    optrom, optrom_dma);
+			goto exit_write;
+		}
+
+		left -= burst;
+		faddr += burst;
+		pbuf += burst * 4;
+		chunk_index++;
+		chunk_count++;
+		if (chunk_index >= total_chunks) {
+			chunk_index = 0;
+			segment_index++;
+			region_dlen -= segment_size;
+		}
+	}
+
+free_buf:
+	dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
+	    optrom_dma);
+	return rval;
+
+exit_write:
+	return rval;
+}
+
+/**
+ * qla29xx_read_optrom_data - Read data from the optrom for QLA29xx adapters.
+ * @vha: Pointer to SCSI QLogic host structure.
+ * @reg_code: Region code to read from.
+ * @opts: Options for the read operation.
+ * @buf: Buffer to store the read data.
+ * @offset: Offset within the region to start reading.
+ * @length: Length of data to read.
+ *
+ * This function reads data from the specified optrom region for QLA29xx adapters.
+ *
+ * Returns a pointer to the buffer on success or NULL on failure.
+ */
+void *
+qla29xx_read_optrom_data(struct scsi_qla_host *vha, uint16_t reg_code,
+			 uint16_t opts, void *buf, uint32_t offset,
+			 uint32_t length)
+{
+	struct qla_hw_data *ha = vha->hw;
+	struct qla_flt_region_data region;
+	dma_addr_t optrom_dma;
+	uint32_t faddr, left, burst;
+	uint32_t img_len, seg_dlen;
+	uint32_t region_len, region_dlen;
+	void *optrom;
+	uint8_t *pbuf;
+	uint16_t total_segments, segment_index = 0;
+	uint16_t chunk_index = 0, chunk_count = 0;
+	int rval;
+
+	memset(&region, 0, sizeof(region));
+
+	optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+				    &optrom_dma, GFP_KERNEL);
+	if (!optrom) {
+		ql_log(ql_log_warn, vha, 0x0093,
+		    "Unable to allocate memory for optrom burst read (%x KB).\n",
+		    OPTROM_BURST_SIZE / 1024);
+		return NULL;
+	}
+
+	if (ha->flags.valid_flt && length == 0) {
+		/* Get image length and segment length from FLT */
+		rval = qla29xx_get_flash_region(vha, reg_code, &region);
+		if (rval != QLA_SUCCESS) {
+			ql_log(ql_log_warn, vha, 0x7033,
+				"Invalid address %x - not a region start address\n",
+				reg_code);
+			goto free_buf;
+		}
+		img_len = le32_to_cpu(region.image_length);
+	} else {
+		img_len = length;
+	}
+
+	seg_dlen = ha->flt_segment_length >> 2;
+	region_len = (length > 0) ? length : img_len;
+	region_dlen = (region_len >> 2);
+	total_segments = (region_dlen + seg_dlen - 1) / seg_dlen;
+
+	faddr = offset >> 2;
+	left = region_dlen;
+	burst = OPTROM_BURST_DWORDS;
+	pbuf = buf;
+
+	ql_log(ql_log_info, vha, 0x0096,
+	       "Reg[0x%x]: options=0x%x length=0x%x offset=0x%x segments=%u\n",
+		reg_code, opts, region_len, offset, total_segments);
+
+	while (region_dlen > 0) {
+		uint32_t segment_size, total_chunks;
+		uint16_t options = 0;
+
+		segment_size = (region_dlen > seg_dlen) ? seg_dlen : region_dlen;
+		total_chunks = (segment_size + OPTROM_BURST_DWORDS - 1) /
+				OPTROM_BURST_DWORDS;
+
+		burst = OPTROM_BURST_DWORDS;
+		if (burst > left)
+			burst = left;
+		if (burst > segment_size - chunk_index * OPTROM_BURST_DWORDS)
+			burst = segment_size - chunk_index * OPTROM_BURST_DWORDS;
+
+		set_segment_bits(&options, segment_index, total_segments);
+		set_chunk_bits(&options, chunk_index, total_chunks);
+
+		/* flash block read operations */
+		CLEAR_FW_BIT(options, BIT_9);
+		CLEAR_FW_BIT(options, BIT_6);
+
+		options |= opts;
+
+		/* faddr is offset relative to region code */
+		rval = qla29xx_flash_block_read(vha, optrom_dma,
+				faddr, burst, reg_code, options);
+		if (rval) {
+			ql_log(ql_log_warn, vha, 0x0097,
+			    "Unable to burst-read optrom segment (%x/%x/%llx).\n",
+			    rval, faddr, (unsigned long long)optrom_dma);
+			goto free_buf;
+		}
+
+		memcpy(pbuf, optrom, burst * 4);
+
+		left -= burst;
+		faddr += burst;
+		pbuf += burst * 4;
+		chunk_index++;
+		chunk_count++;
+		if (chunk_index >= total_chunks) {
+			chunk_index = 0;
+			segment_index++;
+			region_dlen -= segment_size;
+		}
+	}
+
+	dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
+	    optrom_dma);
+	return buf;
+
+free_buf:
+	dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
+	    optrom_dma);
+	return NULL;
+}
+
+/**
+ * qla29xx_get_flash_version - Retrieve flash version information for QLA29xx adapters.
+ * @vha: Pointer to SCSI QLogic host structure.
+ * @mbuf: Buffer to store the flash version information.
+ *
+ * This function retrieves the flash version information for QLA29xx adapters.
+ * It initializes the version fields and prepares for future flash read logic.
+ *
+ * Returns QLA_SUCCESS on success or QLA_FUNCTION_FAILED on failure.
+ */
+int
+qla29xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
+{
+	struct qla_hw_data *ha = vha->hw;
+	struct qla_flt_region_data region;
+	uint32_t pcihdr = 0, pcids = 0;
+	uint32_t *dcode = mbuf;
+	uint8_t *bcode = mbuf;
+	uint8_t code_type, last_image;
+	void *buf = NULL;
+	int ret = QLA_SUCCESS;
+
+	if (!mbuf)
+		return QLA_FUNCTION_FAILED;
+
+	memset(ha->bios_revision, 0, sizeof(ha->bios_revision));
+	memset(ha->efi_revision, 0, sizeof(ha->efi_revision));
+	memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
+	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
+
+	ret = qla29xx_get_flash_region(vha, FLT_REG_FW, &region);
+	if (ret != QLA_SUCCESS) {
+		ql_log(ql_log_warn, vha, 0x7033,
+			"Invalid region %x\n", FLT_REG_FW);
+		goto exit_boot;
+	}
+
+	ha->fw_revision[0] = (le32_to_cpu(region.version) >> 16) & 0xff;
+	ha->fw_revision[1] = (le32_to_cpu(region.version) >> 8) & 0xff;
+	ha->fw_revision[2] = le32_to_cpu(region.version) & 0xff;
+
+	do {
+		/* Verify PCI expansion ROM header. */
+		buf = qla29xx_read_optrom_data(vha, FLT_REG_BOOT_CODE, 0,
+					       dcode, 0, 0x20);
+		if (!buf) {
+			ret = QLA_FUNCTION_FAILED;
+			ql_log(ql_log_info, vha, 0x017d,
+			    "Unable to read PCI EXP Rom Header(%x).\n", ret);
+			break;
+		}
+
+		bcode = mbuf + (pcihdr % 4);
+		if (memcmp(bcode, "\x55\xaa", 2)) {
+			/* No signature */
+			ql_log(ql_log_fatal, vha, 0x0059,
+			    "No matching ROM signature.\n");
+			ret = QLA_FUNCTION_FAILED;
+			break;
+		}
+
+		/* Locate PCI data structure. */
+		pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
+
+		buf = qla29xx_read_optrom_data(vha, FLT_REG_BOOT_CODE, 0,
+					       dcode, pcids, 0x20);
+		if (!buf) {
+			ret = QLA_FUNCTION_FAILED;
+			ql_log(ql_log_info, vha, 0x018e,
+			    "Unable to read PCI Data Structure (%x).\n", ret);
+			break;
+		}
+
+		bcode = mbuf + (pcihdr % 4);
+		/* Validate signature of PCI data structure. */
+		if (memcmp(bcode, "PCIR", 4)) {
+			/* Incorrect header. */
+			ql_log(ql_log_fatal, vha, 0x005a,
+			    "PCI data struct not found pcir_adr=%x.\n", pcids);
+			ql_dump_buffer(ql_dbg_init, vha, 0x0059, dcode, 32);
+			ret = QLA_FUNCTION_FAILED;
+			break;
+		}
+
+		/* Read version */
+		code_type = bcode[0x14];
+		switch (code_type) {
+		case ROM_CODE_TYPE_BIOS:
+			/* Intel x86, PC-AT compatible. */
+			ha->bios_revision[0] = bcode[0x12];
+			ha->bios_revision[1] = bcode[0x13];
+			ql_dbg(ql_dbg_init, vha, 0x005b,
+			    "Read BIOS %d.%d.\n",
+			    ha->bios_revision[1], ha->bios_revision[0]);
+			break;
+		case ROM_CODE_TYPE_FCODE:
+			/* Open Firmware standard for PCI (FCode). */
+			ha->fcode_revision[0] = bcode[0x12];
+			ha->fcode_revision[1] = bcode[0x13];
+			ql_dbg(ql_dbg_init, vha, 0x005c,
+			    "Read FCODE %d.%d.\n",
+			    ha->fcode_revision[1], ha->fcode_revision[0]);
+			break;
+		case ROM_CODE_TYPE_EFI:
+			/* Extensible Firmware Interface (EFI). */
+			ha->efi_revision[0] = bcode[0x12];
+			ha->efi_revision[1] = bcode[0x13];
+			ql_dbg(ql_dbg_init, vha, 0x005d,
+			    "Read EFI %d.%d.\n",
+			    ha->efi_revision[1], ha->efi_revision[0]);
+			break;
+		default:
+			ql_log(ql_log_warn, vha, 0x005e,
+			    "Unrecognized code type %x at pcids %x.\n",
+			    code_type, pcids);
+			break;
+		}
+
+		last_image = bcode[0x15] & BIT_7;
+
+		/* Locate next PCI expansion ROM. */
+		pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512;
+	} while (!last_image);
+
+exit_boot:
+	return ret;
+}
+
 /*
  * NVRAM support routines
  */
@@ -1117,10 +1762,16 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)
 	uint32_t flt_addr;
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
-	    !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) &&
-	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
-		return QLA_SUCCESS;
+	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_CNA_CAPABLE(ha) &&
+	    !IS_QLA2031(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha) &&
+	    !IS_QLA29XX(ha))
+		goto done;
+
+	if (IS_QLA29XX(ha)) {
+		qla29xx_get_flt_layout(vha);
+		qla29xx_get_fdt_info(vha);
+		goto done;
+	}
 
 	if (IS_QLA28XX(ha) && !qla28xx_validate_mcu_signature(vha))
 		ha->flags.secure_mcu = 1;
@@ -1132,7 +1783,7 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)
 	qla2xxx_get_flt_info(vha, flt_addr);
 	qla2xxx_get_fdt_info(vha);
 	qla2xxx_get_idc_param(vha);
-
+done:
 	return QLA_SUCCESS;
 }
 
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 03/60] scsi: qla2xxx: Add NVRAM config support for 29xx adapters
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
  2026-06-12  9:52 ` [PATCH v2 01/60] scsi: qla2xxx: Add 29xx series PCI device ID support Nilesh Javali
  2026-06-12  9:52 ` [PATCH v2 02/60] scsi: qla2xxx: Add flash read/write interface for 29xx Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:46   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 04/60] scsi: qla2xxx: Add get_flash_version " Nilesh Javali
                   ` (56 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Manish Rangankar <mrangankar@marvell.com>

Extend the NVRAM read and configuration-apply paths to handle the
29xx series.  The 29xx NVRAM layout is similar to the 81xx family,
so reuse the existing nvram_81xx parsing while adding
29xx-specific fields and init-sequence integration.

Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_def.h  |   1 +
 drivers/scsi/qla2xxx/qla_fw.h   |  42 ++++++++++-
 drivers/scsi/qla2xxx/qla_init.c | 123 +++++++++++++++++++++++++-------
 drivers/scsi/qla2xxx/qla_os.c   |   2 +
 4 files changed, 141 insertions(+), 27 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index b5ad6ed3d5d1..89ddf332cdbd 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -4469,6 +4469,7 @@ struct qla_hw_data {
 	uint16_t	vpd_size;
 	uint16_t	vpd_base;
 	void		*vpd;
+	struct qla_flash_memo_block *fiv;
 
 	uint16_t	loop_reset_delay;
 	uint8_t		retry_count;
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index d27d09964a24..6502eff1c0f6 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1676,6 +1676,8 @@ struct qla_flt_location {
 #define FLT_REG_VPD_SEC_27XX_2	0xD8
 #define FLT_REG_VPD_SEC_27XX_3	0xDA
 #define FLT_REG_NVME_PARAMS_27XX	0x21
+#define FLT_REG_FMB_PRI		0xDF
+#define FLT_REG_FMB_SEC		0x124
 
 /* 28xx */
 #define FLT_REG_AUX_IMG_PRI_28XX	0x125
@@ -2110,7 +2112,7 @@ struct nvram_81xx {
 	 * BIT 7    = SCM Disabled if BIT is set (1)
 	 * BIT 8-15 = Unused
 	 */
-	uint16_t enhanced_features;
+	__le16	enhanced_features;
 
 	uint16_t reserved_24[4];
 
@@ -2338,4 +2340,42 @@ struct qla_fcp_prio_cfg {
 
 #define NVRAM_DUAL_FCP_NVME_FLAG_OFFSET	0x196
 
+struct qla_fmb_version {
+	uint8_t major;
+	uint8_t minor;
+	uint8_t sub;
+	uint8_t build;
+};
+
+struct qla_fmb_upd_time {
+	__le16   year;
+	uint8_t  month;
+	uint8_t  day;
+
+	uint8_t  hour;
+	uint8_t  minute;
+	uint8_t  second;
+	uint8_t  reserved;
+};
+
+struct qla_flash_memo_block {
+	__le32   signature;	/* "FMBS" */
+#define QLFC_FMB_SIG	cpu_to_le32(0x464D4253)
+	__le32   length;
+	__le32   version;
+#define QLFC_FMB_VERSION 3
+	__le32   checksum;
+	struct qla_fmb_version ffv_ver;
+	struct qla_fmb_version mbi_ver;
+	struct {
+		__le16   year;
+		uint8_t  month;
+		uint8_t  day;
+		uint8_t  reserve[4];
+	} bld_time;
+	uint8_t tool_id[4];
+	struct qla_fmb_upd_time upd_time;
+	struct qla_fmb_version  tool_version;
+};
+
 #endif
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index e23e7ac48ae2..4acbbe0161df 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -4194,11 +4194,11 @@ qla24xx_detect_sfp(scsi_qla_host_t *vha)
 	used_nvram = 0;
 	ha->flags.lr_detected = 0;
 	if (IS_BPM_RANGE_CAPABLE(ha) &&
-	    (nv->enhanced_features & NEF_LR_DIST_ENABLE)) {
+	    (le16_to_cpu(nv->enhanced_features) & NEF_LR_DIST_ENABLE)) {
 		used_nvram = 1;
 		ha->flags.lr_detected = 1;
 		ha->lr_distance =
-		    (nv->enhanced_features >> LR_DIST_NV_POS)
+		    (le16_to_cpu(nv->enhanced_features) >> LR_DIST_NV_POS)
 		     & LR_DIST_NV_MASK;
 	}
 
@@ -9306,34 +9306,97 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
 	if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
 		ha->vpd_size = FA_VPD_SIZE_82XX;
 
-	if (IS_QLA28XX(ha) || IS_QLA27XX(ha))
-		qla28xx_get_aux_images(vha, &active_regions);
-
 	/* Get VPD data into cache */
 	ha->vpd = ha->nvram + VPD_OFFSET;
 
-	faddr = ha->flt_region_vpd;
-	if (IS_QLA28XX(ha)) {
-		if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
-			faddr = ha->flt_region_vpd_sec;
+	if (IS_QLA29XX(ha)) {
+		uint16_t fw_options = 0, r_code;
+		uint32_t vpd_r[] = {FLT_REG_VPD_0, FLT_REG_VPD_1,
+				    FLT_REG_VPD_2, FLT_REG_VPD_3};
+		uint32_t nvram_r[] = {FLT_REG_NVRAM_0, FLT_REG_NVRAM_1,
+				      FLT_REG_NVRAM_2, FLT_REG_NVRAM_3};
+		void *buf;
+
+		BUILD_BUG_ON((VPD_OFFSET + FA_NVRAM_VPD_SIZE +
+			      sizeof(struct qla_flash_memo_block)) >
+			     MAX_NVRAM_SIZE);
+
+		ha->fiv = (struct qla_flash_memo_block *)
+			((char *)ha->vpd + ha->vpd_size);
+
+		buf = qla29xx_read_optrom_data(vha, FLT_REG_FMB_PRI,
+					       fw_options, ha->fiv, 0,
+					       sizeof(struct qla_flash_memo_block));
+		if (!buf) {
+			ql_log(ql_log_info, vha, 0x01be,
+			    "Unable to read Flash Image Version.\n");
+		} else if (ha->fiv->signature != QLFC_FMB_SIG) {
+			ql_log(ql_log_warn, vha, 0x01bf,
+			    "Invalid FMB signature %#x, expected %#x.\n",
+			    le32_to_cpu(ha->fiv->signature),
+			    le32_to_cpu(QLFC_FMB_SIG));
+			ha->fiv = NULL;
+		} else {
+			ql_log(ql_log_info, vha, 0x0024,
+			    "Flash Image Version %u.%02u.%02u\n",
+			    ha->fiv->mbi_ver.major,
+			    ha->fiv->mbi_ver.minor,
+			    ha->fiv->mbi_ver.sub);
+		}
+
+		if (ha->port_no >= ARRAY_SIZE(vpd_r)) {
+			ql_log(ql_log_warn, vha, 0x002e,
+			    "Invalid port number %u, skipping VPD/NVRAM read.\n",
+			    ha->port_no);
+			goto out_29xx;
+		}
+
+		r_code = vpd_r[ha->port_no];
+		buf = qla29xx_read_optrom_data(vha, r_code, fw_options,
+					       ha->vpd, 0, ha->vpd_size);
+		if (!buf)
+			ql_log(ql_log_info, vha, 0x002d,
+			    "Unable to read VPD info.\n");
+
+		r_code = nvram_r[ha->port_no];
+		buf = qla29xx_read_optrom_data(vha, r_code, fw_options,
+					       ha->nvram, 0, ha->nvram_size);
+		if (!buf)
+			ql_log(ql_log_info, vha, 0x0013,
+			    "Unable to read nvram config info.\n");
+out_29xx:
+	} else {
+		if (IS_QLA28XX(ha) || IS_QLA27XX(ha))
+			qla28xx_get_aux_images(vha, &active_regions);
+
+		faddr = ha->flt_region_vpd;
+		if (IS_QLA28XX(ha)) {
+			if (active_regions.aux.vpd_nvram ==
+			    QLA27XX_SECONDARY_IMAGE)
+				faddr = ha->flt_region_vpd_sec;
+			ql_dbg(ql_dbg_init, vha, 0x0110,
+			    "Loading %s nvram image.\n",
+			    active_regions.aux.vpd_nvram ==
+			    QLA27XX_PRIMARY_IMAGE ?
+			    "primary" : "secondary");
+		}
+		ha->isp_ops->read_optrom(vha, ha->vpd, faddr << 2,
+					 ha->vpd_size);
+
+		/* Get NVRAM data into cache and calculate checksum. */
+		faddr = ha->flt_region_nvram;
+		if (IS_QLA28XX(ha)) {
+			if (active_regions.aux.vpd_nvram ==
+			    QLA27XX_SECONDARY_IMAGE)
+				faddr = ha->flt_region_nvram_sec;
+		}
 		ql_dbg(ql_dbg_init, vha, 0x0110,
 		    "Loading %s nvram image.\n",
 		    active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ?
 		    "primary" : "secondary");
+		ha->isp_ops->read_optrom(vha, ha->nvram, faddr << 2,
+					 ha->nvram_size);
 	}
-	ha->isp_ops->read_optrom(vha, ha->vpd, faddr << 2, ha->vpd_size);
-
-	/* Get NVRAM data into cache and calculate checksum. */
-	faddr = ha->flt_region_nvram;
-	if (IS_QLA28XX(ha)) {
-		if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
-			faddr = ha->flt_region_nvram_sec;
-	}
-	ql_dbg(ql_dbg_init, vha, 0x0110,
-	    "Loading %s nvram image.\n",
-	    active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ?
-	    "primary" : "secondary");
-	ha->isp_ops->read_optrom(vha, ha->nvram, faddr << 2, ha->nvram_size);
 
 	dptr = (__force __le32 *)nv;
 	for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++)
@@ -9386,7 +9449,10 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
 		nv->login_timeout = cpu_to_le16(0);
 		nv->firmware_options_1 =
 		    cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
-		nv->firmware_options_2 = cpu_to_le32(2 << 4);
+		if (IS_QLA29XX(ha))
+			nv->firmware_options_2 = cpu_to_le32(1 << 4);
+		else
+			nv->firmware_options_2 = cpu_to_le32(2 << 4);
 		nv->firmware_options_2 |= cpu_to_le32(BIT_12);
 		nv->firmware_options_3 = cpu_to_le32(2 << 13);
 		nv->host_p = cpu_to_le32(BIT_11|BIT_10);
@@ -9468,9 +9534,13 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
 		icb->node_name[0] &= 0xF0;
 	}
 
-	if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) {
-		if ((nv->enhanced_features & BIT_7) == 0)
+	/* SCM Enabled in NVRAM */
+	if (IS_QLA29XX(ha) || IS_QLA28XX(ha) || IS_QLA27XX(ha)) {
+		if ((le16_to_cpu(nv->enhanced_features) & BIT_7) == 0) {
+			ql_log(ql_log_info, vha, 0x0062,
+			       "USCM enabled in NVRAM\n");
 			ha->flags.scm_supported_a = 1;
+		}
 	}
 
 	/* Set host adapter parameters. */
@@ -9546,7 +9616,8 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
 
 	/* if not running MSI-X we need handshaking on interrupts */
 	if (!vha->hw->flags.msix_enabled &&
-	    (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)))
+	    (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
+	     IS_QLA29XX(ha)))
 		icb->firmware_options_2 |= cpu_to_le32(BIT_22);
 
 	/* Enable ZIO. */
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index ebb97329e6ea..c3eb941f71ad 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -4620,6 +4620,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 fail_free_nvram:
 	kfree(ha->nvram);
 	ha->nvram = NULL;
+	ha->fiv = NULL;
 fail_free_ctx_mempool:
 	mempool_destroy(ha->ctx_mempool);
 	ha->ctx_mempool = NULL;
@@ -5085,6 +5086,7 @@ qla2x00_mem_free(struct qla_hw_data *ha)
 	ha->optrom_buffer = NULL;
 	kfree(ha->nvram);
 	ha->nvram = NULL;
+	ha->fiv = NULL;
 	kfree(ha->npiv_info);
 	ha->npiv_info = NULL;
 	kfree(ha->swl);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 04/60] scsi: qla2xxx: Add get_flash_version support for 29xx adapters
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (2 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 03/60] scsi: qla2xxx: Add NVRAM config support for 29xx adapters Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:18   ` sashiko-bot
  2026-06-12 10:48   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 05/60] scsi: qla2xxx: Add 29xx support in queue initialisation path Nilesh Javali
                   ` (55 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Manish Rangankar <mrangankar@marvell.com>

Remove the standalone qla29xx_get_flash_version() and fold 29xx
support directly into qla24xx_get_flash_version():

  - Firmware version: 29xx reads version metadata from the FLT region
    via qla29xx_get_flash_region(FLT_REG_FW) rather than parsing the
    flash image; an early return skips the legacy firmware-image read.

  - PCI expansion ROM reads (header + data structure): a new
    file-static helper, qla24xx_read_pci_rom_chunk(), abstracts the
    per-generation flash access so both read sites are straight-line
    calls instead of inline if/else twin blocks.  29xx uses
    qla29xx_read_optrom_data(FLT_REG_BOOT_CODE, byte-offset); 24xx
    uses qla24xx_read_flash_data(dword-address).

Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_sup.c | 235 +++++++++++++++------------------
 1 file changed, 103 insertions(+), 132 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index eb10904f14ca..2229c2b084cf 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -527,134 +527,6 @@ qla29xx_read_optrom_data(struct scsi_qla_host *vha, uint16_t reg_code,
 	return NULL;
 }
 
-/**
- * qla29xx_get_flash_version - Retrieve flash version information for QLA29xx adapters.
- * @vha: Pointer to SCSI QLogic host structure.
- * @mbuf: Buffer to store the flash version information.
- *
- * This function retrieves the flash version information for QLA29xx adapters.
- * It initializes the version fields and prepares for future flash read logic.
- *
- * Returns QLA_SUCCESS on success or QLA_FUNCTION_FAILED on failure.
- */
-int
-qla29xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
-{
-	struct qla_hw_data *ha = vha->hw;
-	struct qla_flt_region_data region;
-	uint32_t pcihdr = 0, pcids = 0;
-	uint32_t *dcode = mbuf;
-	uint8_t *bcode = mbuf;
-	uint8_t code_type, last_image;
-	void *buf = NULL;
-	int ret = QLA_SUCCESS;
-
-	if (!mbuf)
-		return QLA_FUNCTION_FAILED;
-
-	memset(ha->bios_revision, 0, sizeof(ha->bios_revision));
-	memset(ha->efi_revision, 0, sizeof(ha->efi_revision));
-	memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
-	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
-
-	ret = qla29xx_get_flash_region(vha, FLT_REG_FW, &region);
-	if (ret != QLA_SUCCESS) {
-		ql_log(ql_log_warn, vha, 0x7033,
-			"Invalid region %x\n", FLT_REG_FW);
-		goto exit_boot;
-	}
-
-	ha->fw_revision[0] = (le32_to_cpu(region.version) >> 16) & 0xff;
-	ha->fw_revision[1] = (le32_to_cpu(region.version) >> 8) & 0xff;
-	ha->fw_revision[2] = le32_to_cpu(region.version) & 0xff;
-
-	do {
-		/* Verify PCI expansion ROM header. */
-		buf = qla29xx_read_optrom_data(vha, FLT_REG_BOOT_CODE, 0,
-					       dcode, 0, 0x20);
-		if (!buf) {
-			ret = QLA_FUNCTION_FAILED;
-			ql_log(ql_log_info, vha, 0x017d,
-			    "Unable to read PCI EXP Rom Header(%x).\n", ret);
-			break;
-		}
-
-		bcode = mbuf + (pcihdr % 4);
-		if (memcmp(bcode, "\x55\xaa", 2)) {
-			/* No signature */
-			ql_log(ql_log_fatal, vha, 0x0059,
-			    "No matching ROM signature.\n");
-			ret = QLA_FUNCTION_FAILED;
-			break;
-		}
-
-		/* Locate PCI data structure. */
-		pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
-
-		buf = qla29xx_read_optrom_data(vha, FLT_REG_BOOT_CODE, 0,
-					       dcode, pcids, 0x20);
-		if (!buf) {
-			ret = QLA_FUNCTION_FAILED;
-			ql_log(ql_log_info, vha, 0x018e,
-			    "Unable to read PCI Data Structure (%x).\n", ret);
-			break;
-		}
-
-		bcode = mbuf + (pcihdr % 4);
-		/* Validate signature of PCI data structure. */
-		if (memcmp(bcode, "PCIR", 4)) {
-			/* Incorrect header. */
-			ql_log(ql_log_fatal, vha, 0x005a,
-			    "PCI data struct not found pcir_adr=%x.\n", pcids);
-			ql_dump_buffer(ql_dbg_init, vha, 0x0059, dcode, 32);
-			ret = QLA_FUNCTION_FAILED;
-			break;
-		}
-
-		/* Read version */
-		code_type = bcode[0x14];
-		switch (code_type) {
-		case ROM_CODE_TYPE_BIOS:
-			/* Intel x86, PC-AT compatible. */
-			ha->bios_revision[0] = bcode[0x12];
-			ha->bios_revision[1] = bcode[0x13];
-			ql_dbg(ql_dbg_init, vha, 0x005b,
-			    "Read BIOS %d.%d.\n",
-			    ha->bios_revision[1], ha->bios_revision[0]);
-			break;
-		case ROM_CODE_TYPE_FCODE:
-			/* Open Firmware standard for PCI (FCode). */
-			ha->fcode_revision[0] = bcode[0x12];
-			ha->fcode_revision[1] = bcode[0x13];
-			ql_dbg(ql_dbg_init, vha, 0x005c,
-			    "Read FCODE %d.%d.\n",
-			    ha->fcode_revision[1], ha->fcode_revision[0]);
-			break;
-		case ROM_CODE_TYPE_EFI:
-			/* Extensible Firmware Interface (EFI). */
-			ha->efi_revision[0] = bcode[0x12];
-			ha->efi_revision[1] = bcode[0x13];
-			ql_dbg(ql_dbg_init, vha, 0x005d,
-			    "Read EFI %d.%d.\n",
-			    ha->efi_revision[1], ha->efi_revision[0]);
-			break;
-		default:
-			ql_log(ql_log_warn, vha, 0x005e,
-			    "Unrecognized code type %x at pcids %x.\n",
-			    code_type, pcids);
-			break;
-		}
-
-		last_image = bcode[0x15] & BIT_7;
-
-		/* Locate next PCI expansion ROM. */
-		pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512;
-	} while (!last_image);
-
-exit_boot:
-	return ret;
-}
-
 /*
  * NVRAM support routines
  */
@@ -4099,6 +3971,86 @@ qla82xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
 	return ret;
 }
 
+/*
+ * Read the boot BIOS/FCODE/EFI version for 29xx adapters.
+ *
+ * 29xx reads flash through an FLT region code plus a region-relative
+ * offset.  The firmware only honours such a read at the region base
+ * (offset 0) and rejects a non-zero offset with MBS_COMMAND_ERROR.  The
+ * PCI expansion ROM header and the PCI data structure it points to both
+ * live within the first dwords of FLT_REG_BOOT_CODE, so read one bounded
+ * block at offset 0 and parse both structures from memory instead of
+ * issuing a second read at the PCI-data-structure offset.
+ */
+#define QLA29XX_BOOT_PROBE_LEN	0x100
+
+static void
+qla29xx_get_boot_version(scsi_qla_host_t *vha, void *mbuf)
+{
+	struct qla_hw_data *ha = vha->hw;
+	uint8_t *bcode = mbuf;
+	uint32_t pcids;
+	uint8_t code_type;
+
+	if (!qla29xx_read_optrom_data(vha, FLT_REG_BOOT_CODE, 0, mbuf, 0,
+				      QLA29XX_BOOT_PROBE_LEN)) {
+		ql_log(ql_log_info, vha, 0x018e,
+		    "Unable to read PCI Data Structure.\n");
+		return;
+	}
+
+	/* Verify PCI expansion ROM header. */
+	if (memcmp(bcode, "\x55\xaa", 2)) {
+		ql_log(ql_log_info, vha, 0x0059,
+		    "No matching ROM signature.\n");
+		return;
+	}
+
+	/* Locate the PCI data structure within the buffer. */
+	pcids = (bcode[0x19] << 8) | bcode[0x18];
+	if (pcids + 0x16 > QLA29XX_BOOT_PROBE_LEN)
+		return;
+
+	bcode += pcids;
+
+	/* Validate signature of PCI data structure. */
+	if (memcmp(bcode, "PCIR", 4)) {
+		ql_log(ql_log_info, vha, 0x005a,
+		    "PCI data struct not found pcir_adr=%x.\n", pcids);
+		return;
+	}
+
+	code_type = bcode[0x14];
+	switch (code_type) {
+	case ROM_CODE_TYPE_BIOS:
+		/* Intel x86, PC-AT compatible. */
+		ha->bios_revision[0] = bcode[0x12];
+		ha->bios_revision[1] = bcode[0x13];
+		ql_dbg(ql_dbg_init, vha, 0x005b, "Read BIOS %d.%d.\n",
+		    ha->bios_revision[1], ha->bios_revision[0]);
+		break;
+	case ROM_CODE_TYPE_FCODE:
+		/* Open Firmware standard for PCI (FCode). */
+		ha->fcode_revision[0] = bcode[0x12];
+		ha->fcode_revision[1] = bcode[0x13];
+		ql_dbg(ql_dbg_init, vha, 0x005c, "Read FCODE %d.%d.\n",
+		    ha->fcode_revision[1], ha->fcode_revision[0]);
+		break;
+	case ROM_CODE_TYPE_EFI:
+		/* Extensible Firmware Interface (EFI). */
+		ha->efi_revision[0] = bcode[0x12];
+		ha->efi_revision[1] = bcode[0x13];
+		ql_dbg(ql_dbg_init, vha, 0x005d, "Read EFI %d.%d.\n",
+		    ha->efi_revision[1], ha->efi_revision[0]);
+		break;
+	default:
+		ql_log(ql_log_warn, vha, 0x005e,
+		    "Unrecognized code type %x at pcids %x.\n",
+		    code_type, pcids);
+		break;
+	}
+}
+
 int
 qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
 {
@@ -4123,12 +4075,31 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
 	memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
 	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
 
+	/* ISP29xx: get FW version from FLT region metadata */
+	if (IS_QLA29XX(ha)) {
+		struct qla_flt_region_data region;
+
+		ret = qla29xx_get_flash_region(vha, FLT_REG_FW, &region);
+		if (ret != QLA_SUCCESS) {
+			ql_log(ql_log_warn, vha, 0x7033,
+					"Invalid region %x\n", FLT_REG_FW);
+			return ret;
+		}
+
+		ha->fw_revision[0] = (le32_to_cpu(region.version) >> 16) & 0xff;
+		ha->fw_revision[1] = (le32_to_cpu(region.version) >> 8) & 0xff;
+		ha->fw_revision[2] = le32_to_cpu(region.version) & 0xff;
+
+		/* BIOS/FCODE/EFI version from the boot-code region. */
+		qla29xx_get_boot_version(vha, mbuf);
+		return ret;
+	}
+
 	pcihdr = ha->flt_region_boot << 2;
 	if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
 		qla27xx_get_active_image(vha, &active_regions);
-		if (active_regions.global == QLA27XX_SECONDARY_IMAGE) {
+		if (active_regions.global == QLA27XX_SECONDARY_IMAGE)
 			pcihdr = ha->flt_region_boot_sec << 2;
-		}
 	}
 
 	do {
@@ -4137,7 +4108,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
 		if (ret) {
 			ql_log(ql_log_info, vha, 0x017d,
 			    "Unable to read PCI EXP Rom Header(%x).\n", ret);
-			return QLA_FUNCTION_FAILED;
+			break;
 		}
 
 		bcode = mbuf + (pcihdr % 4);
@@ -4155,7 +4126,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
 		if (ret) {
 			ql_log(ql_log_info, vha, 0x018e,
 			    "Unable to read PCI Data Structure (%x).\n", ret);
-			return QLA_FUNCTION_FAILED;
+			break;
 		}
 
 		bcode = mbuf + (pcihdr % 4);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 05/60] scsi: qla2xxx: Add 29xx support in queue initialisation path
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (3 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 04/60] scsi: qla2xxx: Add get_flash_version " Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:17   ` sashiko-bot
  2026-06-12 10:49   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 06/60] scsi: qla2xxx: Add FC operational firmware load for 29xx Nilesh Javali
                   ` (54 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Manish Rangankar <mrangankar@marvell.com>

Extend the queue initialisation and multi-queue management mailbox
commands to include IS_QLA29XX() checks, following the same mailbox
interface as 27xx/28xx.

Unlike earlier adapters that use 64-byte request/response ring entries
(request_t / response_t), 29xx uses 128-byte entries.  Add struct
request_ext and struct response_ext, which extend the legacy 64-byte
layout with a 64-byte reserved area.  The first 64 bytes are
layout-compatible with the legacy structures, so common header
accesses remain valid.

The enlarged entry stride doubles the DMA ring memory allocated for
both request and response queues on 29xx, and all ring pointer
arithmetic must account for the wider entries (handled by later
patches in this series).

Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_def.h | 30 ++++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_mbx.c | 20 +++++++++++++-------
 drivers/scsi/qla2xxx/qla_mid.c | 25 +++++++++++++++++++++----
 3 files changed, 64 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 89ddf332cdbd..1ec7ee578e0c 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1989,6 +1989,18 @@ typedef struct {
 #define RESPONSE_PROCESSED	0xDEADDEAD	/* Signature */
 } response_t;
 
+struct response_ext {
+	uint8_t		entry_type;		/* Entry type. */
+	uint8_t		entry_count;		/* Entry count. */
+	uint8_t		sys_define;		/* System defined. */
+	uint8_t		entry_status;		/* Entry Status. */
+	uint32_t	handle;			/* System defined handle */
+	uint8_t		data[52];
+	uint32_t	signature;
+	uint8_t		reserved[64];
+#define RESPONSE_PROCESSED	0xDEADDEAD	/* Signature */
+};
+
 /*
  * ISP queue - ATIO queue entry definition.
  */
@@ -2067,6 +2079,24 @@ typedef struct {
 	struct dsd64 dsd[2];
 } cmd_a64_entry_t, request_t;
 
+struct request_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t handle;		/* System handle. */
+	target_id_t target;		/* SCSI ID */
+	__le16  lun;			/* SCSI LUN */
+	__le16  control_flags;		/* Control flags. */
+	uint16_t reserved_1;
+	__le16  timeout;		/* Command timeout. */
+	__le16  dseg_count;		/* Data segment count. */
+	uint8_t scsi_cdb[MAX_CMDSZ];	/* SCSI command words. */
+	uint32_t byte_count;		/* Total byte count. */
+	struct dsd64 dsd[2];
+	uint8_t reserved[64];
+};
+
 /*
  * ISP queue - continuation entry structure definition.
  */
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 2d052f870b2b..2b232b225c90 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -4584,7 +4584,8 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
 	mcp->mb[12] = req->qos;
 	mcp->mb[11] = req->vp_idx;
 	mcp->mb[13] = req->rid;
-	if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
+	if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
+	    IS_QLA29XX(ha))
 		mcp->mb[15] = 0;
 
 	mcp->mb[4] = req->id;
@@ -4599,9 +4600,10 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
 	mcp->tov = MBX_TOV_SECONDS * 2;
 
 	if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
-	    IS_QLA28XX(ha))
+	    IS_QLA28XX(ha) || IS_QLA29XX(ha))
 		mcp->in_mb |= MBX_1;
-	if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+	if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
+	    IS_QLA29XX(ha)) {
 		mcp->out_mb |= MBX_15;
 		/* debug q create issue in SR-IOV */
 		mcp->in_mb |= MBX_9 | MBX_8 | MBX_7;
@@ -4610,7 +4612,8 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	if (!(req->options & BIT_0)) {
 		wrt_reg_dword(req->req_q_in, 0);
-		if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+		if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha) &&
+		    !IS_QLA29XX(ha))
 			wrt_reg_dword(req->req_q_out, 0);
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -4654,7 +4657,8 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
 	mcp->mb[5] = rsp->length;
 	mcp->mb[14] = rsp->msix->entry;
 	mcp->mb[13] = rsp->rid;
-	if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
+	if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
+	    IS_QLA29XX(ha))
 		mcp->mb[15] = 0;
 
 	mcp->mb[4] = rsp->id;
@@ -4671,7 +4675,8 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
 	if (IS_QLA81XX(ha)) {
 		mcp->out_mb |= MBX_12|MBX_11|MBX_10;
 		mcp->in_mb |= MBX_1;
-	} else if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+	} else if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
+		   IS_QLA29XX(ha)) {
 		mcp->out_mb |= MBX_15|MBX_12|MBX_11|MBX_10;
 		mcp->in_mb |= MBX_1;
 		/* debug q create issue in SR-IOV */
@@ -4681,7 +4686,8 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	if (!(rsp->options & BIT_0)) {
 		wrt_reg_dword(rsp->rsp_q_out, 0);
-		if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+		if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha) &&
+		    !IS_QLA29XX(ha))
 			wrt_reg_dword(rsp->rsp_q_in, 0);
 	}
 
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index c563133f751e..e75b7ae22bc5 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -574,9 +574,13 @@ qla25xx_free_req_que(struct scsi_qla_host *vha, struct req_que *req)
 {
 	struct qla_hw_data *ha = vha->hw;
 	uint16_t que_id = req->id;
+	uint16_t reqsz;
+
+	reqsz = IS_QLA29XX(ha) ? sizeof(struct request_ext) :
+				 sizeof(request_t);
 
 	dma_free_coherent(&ha->pdev->dev, (req->length + 1) *
-		sizeof(request_t), req->ring, req->dma);
+			  reqsz, req->ring, req->dma);
 	req->ring = NULL;
 	req->dma = 0;
 	if (que_id) {
@@ -594,6 +598,10 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
 {
 	struct qla_hw_data *ha = vha->hw;
 	uint16_t que_id = rsp->id;
+	uint16_t rspsz;
+
+	rspsz = IS_QLA29XX(ha) ? sizeof(struct response_ext) :
+				 sizeof(response_t);
 
 	if (rsp->msix && rsp->msix->have_irq) {
 		free_irq(rsp->msix->vector, rsp->msix->handle);
@@ -601,8 +609,9 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
 		rsp->msix->in_use = 0;
 		rsp->msix->handle = NULL;
 	}
+
 	dma_free_coherent(&ha->pdev->dev, (rsp->length + 1) *
-		sizeof(response_t), rsp->ring, rsp->dma);
+			  rspsz, rsp->ring, rsp->dma);
 	rsp->ring = NULL;
 	rsp->dma = 0;
 	if (que_id) {
@@ -706,6 +715,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
 	uint16_t que_id = 0;
 	device_reg_t *reg;
 	uint32_t cnt;
+	uint16_t reqsz;
 
 	req = kzalloc_obj(struct req_que);
 	if (req == NULL) {
@@ -714,9 +724,12 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
 		goto failed;
 	}
 
+	reqsz = IS_QLA29XX(ha) ? sizeof(struct request_ext) :
+				 sizeof(request_t);
+
 	req->length = REQUEST_ENTRY_CNT_24XX;
 	req->ring = dma_alloc_coherent(&ha->pdev->dev,
-			(req->length + 1) * sizeof(request_t),
+			(req->length + 1) * reqsz,
 			&req->dma, GFP_KERNEL);
 	if (req->ring == NULL) {
 		ql_log(ql_log_fatal, base_vha, 0x00da,
@@ -833,6 +846,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
 	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
 	uint16_t que_id = 0;
 	device_reg_t *reg;
+	uint16_t rspsz;
 
 	rsp = kzalloc_obj(struct rsp_que);
 	if (rsp == NULL) {
@@ -841,9 +855,12 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
 		goto failed;
 	}
 
+	rspsz = IS_QLA29XX(ha) ? sizeof(struct response_ext) :
+				 sizeof(response_t);
+
 	rsp->length = RESPONSE_ENTRY_CNT_MQ;
 	rsp->ring = dma_alloc_coherent(&ha->pdev->dev,
-			(rsp->length + 1) * sizeof(response_t),
+			(rsp->length + 1) * rspsz,
 			&rsp->dma, GFP_KERNEL);
 	if (rsp->ring == NULL) {
 		ql_log(ql_log_warn, base_vha, 0x00e1,
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 06/60] scsi: qla2xxx: Add FC operational firmware load for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (4 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 05/60] scsi: qla2xxx: Add 29xx support in queue initialisation path Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:14   ` sashiko-bot
  2026-06-12 10:52   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 07/60] scsi: qla2xxx: Add flash block read/write BSG support " Nilesh Javali
                   ` (53 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Manish Rangankar <mrangankar@marvell.com>

Add support to load the 29xx FC operational firmware from the
filesystem and to set up the corresponding firmware dump
template.  This follows the same request_firmware / segment-load
pattern used by earlier adapters.

Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_fw.h   |  36 +++
 drivers/scsi/qla2xxx/qla_gbl.h  |   3 +-
 drivers/scsi/qla2xxx/qla_init.c | 512 +++++++++++++++++++++++++++++++-
 drivers/scsi/qla2xxx/qla_mbx.c  |  19 +-
 drivers/scsi/qla2xxx/qla_nx.c   |   2 +-
 drivers/scsi/qla2xxx/qla_os.c   |  47 ++-
 drivers/scsi/qla2xxx/qla_sup.c  |   4 +-
 7 files changed, 611 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 6502eff1c0f6..050986c6217f 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -2378,4 +2378,40 @@ struct qla_flash_memo_block {
 	struct qla_fmb_version  tool_version;
 };
 
+#define TIM_DEST_ADDR	0xffffffff
+#define CHUNK_SIZE	0x10000
+
+#define TIM	0
+#define ARR1	1
+#define ARR2	2
+#define ARR3	3
+#define ARR4	4
+
+#define LD_FL_HEADER_SIGNATURE	0x46434F50
+#define LD_FL_HEADER_VERSION	0x01
+#define LD_FL_HEADER_SIZE	(0x14 * 4)
+
+struct fcop_header {
+	uint32_t signature;
+	uint32_t header_length;
+	uint32_t header_version;
+	uint32_t segment_size;
+	uint32_t tim_length;
+	uint32_t fc_major_version;
+	uint32_t fc_minor_version;
+	uint32_t fc_subminor_version;
+	uint32_t array1_length;
+	uint32_t array1_destination_addr;
+	uint32_t array2_length;
+	uint32_t array2_destination_addr;
+	uint32_t array3_length;
+	uint32_t array4_length;
+	uint32_t attribute;
+	uint32_t extended_attribute;
+	uint32_t reserved0;
+	uint32_t reserved1;
+	uint32_t reserved2;
+	uint32_t image_checksum;
+};
+
 #endif
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index a032dd047a8f..ca5a80b9c3d2 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -38,6 +38,7 @@ extern void qla24xx_update_fw_options(scsi_qla_host_t *);
 extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *);
 extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *);
 extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *);
+extern int qla29xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr);
 
 extern int qla2x00_perform_loop_resync(scsi_qla_host_t *);
 extern int qla2x00_loop_resync(scsi_qla_host_t *);
@@ -336,7 +337,7 @@ void qla2x00_els_dcmd2_iocb_timeout(void *data);
  * Global Function Prototypes in qla_mbx.c source file.
  */
 extern int
-qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
+qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t, int);
 
 extern int
 qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 4acbbe0161df..123e8e7f40e1 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -8669,7 +8669,8 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
 			for (i = 0; i < dlen; i++)
 				dcode[i] = swab32(dcode[i]);
 
-			rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen);
+			rval = qla2x00_load_ram(vha, req->dma, risc_addr,
+			    dlen, 0);
 			if (rval) {
 				ql_log(ql_log_fatal, vha, 0x008f,
 				    "-> Failed load firmware fragment %u.\n",
@@ -8839,7 +8840,7 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
 				wcode[i] = swab16((__force u32)fwcode[i]);
 
 			rval = qla2x00_load_ram(vha, req->dma, risc_addr,
-			    wlen);
+			    wlen, 0);
 			if (rval) {
 				ql_log(ql_log_fatal, vha, 0x008a,
 				    "Failed to load segment %d of firmware.\n",
@@ -8929,7 +8930,8 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
 			for (i = 0; i < dlen; i++)
 				dcode[i] = swab32((__force u32)fwcode[i]);
 
-			rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen);
+			rval = qla2x00_load_ram(vha, req->dma, risc_addr,
+			    dlen, 0);
 			if (rval) {
 				ql_log(ql_log_fatal, vha, 0x0098,
 				    "-> Failed load firmware fragment %u.\n",
@@ -9128,6 +9130,510 @@ qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
 	return rval;
 }
 
+static int qla29xx_validate_firmware_image(scsi_qla_host_t *vha,
+					   __be32 *dword)
+{
+	if (be32_to_cpu(dword[0]) != LD_FL_HEADER_SIGNATURE) {
+		ql_dbg(ql_dbg_init, vha, 0x0093,
+		       "Firmware image Signature does not match (0x%x).\n",
+		       be32_to_cpu(dword[0]));
+		return QLA_FUNCTION_FAILED;
+	}
+	if (be32_to_cpu(dword[2]) != LD_FL_HEADER_VERSION) {
+		ql_dbg(ql_dbg_init, vha, 0x0093,
+		       "Firmware image Version does not match (0x%x).\n",
+		       be32_to_cpu(dword[2]));
+		return QLA_FUNCTION_FAILED;
+	}
+	return QLA_SUCCESS;
+}
+
+static int qla29xx_process_rd_image(struct scsi_qla_host *vha,
+				    struct fcop_header *header,
+				    __be32 *fwcode, int section,
+				    uint32_t risc_addr, uint32_t section_size)
+{
+	int rval = QLA_SUCCESS;
+	uint32_t *dcode = NULL;
+	struct qla_hw_data *ha = vha->hw;
+	struct req_que *req = ha->req_q_map[0];
+	int num_segments = 0, segment = 0;
+	int chunks_per_segment = 0, chunk = 0;
+	int is_first_chunk = 0;
+	int is_last_chunk = 0;
+	int is_first_segment = 0;
+	int is_last_segment = 0;
+	int opt = 0;
+	uint32_t size = 0;
+	uint32_t size_remainder = 0;
+	uint32_t seg_size_remainder = 0;
+	int i = 0;
+
+	dcode = (uint32_t *)req->ring;
+
+	if (section == TIM) {
+		if (section_size > req->length * qla_req_entry_size(ha)) {
+			ql_log(ql_log_fatal, vha, 0x0098,
+			    "TIM section too large (0x%x bytes, ring 0x%lx bytes).\n",
+			    section_size,
+			    req->length * qla_req_entry_size(ha));
+			return QLA_FUNCTION_FAILED;
+		}
+
+		opt = BIT_15 | BIT_2 | BIT_1 | BIT_0;
+		for (i = 0; i < (section_size >> 2); i++)
+			dcode[i] = swab32((__force u32)fwcode[i]);
+
+		ql_dbg(ql_dbg_init, vha, 0x0098,
+		       "TIM : process_rd_image [opt 0x%x]\n", opt);
+		rval = qla2x00_load_ram(vha, req->dma, risc_addr,
+					section_size >> 2, opt);
+		if (rval) {
+			ql_log(ql_log_fatal, vha, 0x0098,
+			       "-> Failed load TIM\n");
+			return QLA_FUNCTION_FAILED;
+		}
+	} else {
+		size_remainder = section_size;
+		num_segments += (section_size % header->segment_size == 0) ?
+			(section_size / header->segment_size) :
+			(section_size / header->segment_size) + 1;
+		chunks_per_segment =
+			(header->segment_size % CHUNK_SIZE == 0) ?
+			(header->segment_size / CHUNK_SIZE) :
+			(header->segment_size / CHUNK_SIZE) + 1;
+
+		ql_dbg(ql_dbg_init, vha, 0x0098,
+		       "num seg 0x%x chunk per seg 0x%x\n",
+		       num_segments, chunks_per_segment);
+
+		for (segment = 0; segment < num_segments; segment++) {
+			for (chunk = 0; chunk < chunks_per_segment; chunk++) {
+				is_first_chunk = (chunk == 0);
+				if (chunk == 0) {
+					if (size_remainder >=
+					    header->segment_size)
+						seg_size_remainder =
+							header->segment_size;
+					else
+						seg_size_remainder =
+							size_remainder;
+				}
+
+				is_first_segment =
+					(section == ARR1 && segment == 0);
+				is_last_segment =
+					(section == ARR2 &&
+					 (segment == (num_segments - 1)));
+				is_last_chunk =
+					(chunk == (chunks_per_segment - 1) ||
+					 size_remainder < CHUNK_SIZE);
+
+				if (seg_size_remainder < CHUNK_SIZE)
+					size = seg_size_remainder % CHUNK_SIZE;
+				else
+					size = CHUNK_SIZE;
+
+				ql_dbg(ql_dbg_init, vha, 0x0098,
+				       "[%d]chunk 0x%x segment 0x%x first_segment 0x%x first_chunk 0x%x last_segment 0x%x last_chunk 0x%x\n",
+				       __LINE__, chunk, segment,
+				       is_first_segment, is_first_chunk,
+				       is_last_segment, is_last_chunk);
+
+				opt = BIT_2;
+				if (is_first_chunk)
+					opt |= BIT_0;
+				if (is_last_chunk)
+					opt |= BIT_1;
+				if (is_first_segment)
+					opt |= BIT_3;
+				if (is_last_segment)
+					opt |= BIT_4;
+
+				memcpy((char *)dcode, (char *)fwcode, size);
+
+			ql_dbg(ql_dbg_init, vha, 0x0098,
+			       "ARR[0x%x] : opt 0x%x\n", size, opt);
+				rval = qla2x00_load_ram(vha, req->dma,
+							risc_addr,
+							size >> 2, opt);
+				if (rval) {
+					ql_log(ql_log_fatal, vha, 0x0098,
+					       "-> Failed load ram\n");
+					return QLA_FUNCTION_FAILED;
+				}
+
+				fwcode += size >> 2;
+				size_remainder -= size;
+				seg_size_remainder -= size;
+				if (size_remainder == 0)
+					break;
+			}
+			risc_addr += header->segment_size >> 2;
+		}
+	}
+	return rval;
+}
+
+static int
+qla29xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
+{
+	int rval;
+	struct fcop_header *header;
+	uint32_t *dcode = NULL;
+	struct fw_blob *blob;
+	__be32 *fwcode, *array1_addr, *array3_addr;
+	uint templates;
+	uint32_t array_size, risc_attr = 0;
+	ulong i;
+	uint j;
+	ulong dlen, array3_offset;
+	struct qla_hw_data *ha = vha->hw;
+	struct fwdt *fwdt = ha->fwdt;
+
+	header = vmalloc(sizeof(*header));
+	if (!header)
+		return QLA_FUNCTION_FAILED;
+
+	ql_dbg(ql_dbg_init, vha, 0x0090,
+	       "-> FW: Loading via request-firmware.\n");
+
+	blob = qla2x00_request_firmware(vha);
+	if (!blob) {
+		ql_log(ql_log_warn, vha, 0x0092,
+		       "-> Firmware file not found.\n");
+		vfree(header);
+		return QLA_FUNCTION_FAILED;
+	}
+
+	fwcode = (__force __be32 *)blob->fw->data;
+
+	if (blob->fw->size < sizeof(*header)) {
+		ql_log(ql_log_fatal, vha, 0x0093,
+		       "Firmware image too small (%zu bytes, need %zu).\n",
+		       blob->fw->size, sizeof(*header));
+		vfree(header);
+		return QLA_FUNCTION_FAILED;
+	}
+
+	rval = qla29xx_validate_firmware_image(vha, fwcode);
+	if (rval != QLA_SUCCESS) {
+		ql_log(ql_log_fatal, vha, 0x0093,
+		       "Unable to verify integrity of firmware image\n");
+		vfree(header);
+		return QLA_FUNCTION_FAILED;
+	}
+
+	/* byte-swap big-endian firmware header to CPU endian */
+	for (i = 0; i < sizeof(*header) / sizeof(__be32); i++)
+		((uint32_t *)header)[i] = be32_to_cpu(fwcode[i]);
+
+	header->header_length <<= 2;
+	header->tim_length <<= 2;
+	header->array1_length <<= 2;
+	header->array2_length <<= 2;
+	header->array3_length <<= 2;
+	header->array4_length <<= 2;
+
+	if (!header->segment_size) {
+		ql_log(ql_log_fatal, vha, 0x0098,
+		       "FW image has zero segment_size.\n");
+		goto img_corrupt;
+	}
+
+	{
+		size_t fw_size = blob->fw->size;
+		size_t offset;
+
+		/* TIM */
+		offset = header->header_length;
+		if (offset + header->tim_length > fw_size) {
+			ql_log(ql_log_fatal, vha, 0x0098,
+			       "FW image too small for TIM (%#zx > %#zx).\n",
+			       offset + header->tim_length, fw_size);
+			goto img_corrupt;
+		}
+		rval = qla29xx_process_rd_image(vha, header,
+			(__be32 *)((char *)fwcode + offset),
+			TIM, TIM_DEST_ADDR, header->tim_length);
+		if (rval) {
+			ql_log(ql_log_fatal, vha, 0x0098,
+			       "-> Failed load TIM\n");
+			goto img_corrupt;
+		}
+
+		/* Array 1 */
+		offset += header->tim_length;
+		if (offset + header->array1_length > fw_size) {
+			ql_log(ql_log_fatal, vha, 0x0098,
+			       "FW image too small for Arr1 (%#zx > %#zx).\n",
+			       offset + header->array1_length, fw_size);
+			goto img_corrupt;
+		}
+		rval = qla29xx_process_rd_image(vha, header,
+			(__be32 *)((char *)fwcode + offset),
+			ARR1, header->array1_destination_addr,
+			header->array1_length);
+		if (rval) {
+			ql_log(ql_log_fatal, vha, 0x0098,
+			       "-> Failed load Arr1\n");
+			goto img_corrupt;
+		}
+
+		/* Array 2 */
+		offset += header->array1_length;
+		if (offset + header->array2_length > fw_size) {
+			ql_log(ql_log_fatal, vha, 0x0098,
+			       "FW image too small for Arr2 (%#zx > %#zx).\n",
+			       offset + header->array2_length, fw_size);
+			goto img_corrupt;
+		}
+		rval = qla29xx_process_rd_image(vha, header,
+			(__be32 *)((char *)fwcode + offset),
+			ARR2, header->array2_destination_addr,
+			header->array2_length);
+		if (rval) {
+			ql_log(ql_log_fatal, vha, 0x0098,
+			       "-> Failed load Arr2\n");
+			goto img_corrupt;
+		}
+
+		/* Array 3: FW_DUMP template */
+		if (offset + 10 * sizeof(__be32) > fw_size) {
+			ql_log(ql_log_fatal, vha, 0x0098,
+			       "FW image too small for risc_attr.\n");
+			goto img_corrupt;
+		}
+		array1_addr = (__be32 *)((char *)fwcode +
+				header->header_length +
+				header->tim_length);
+		risc_attr = swab32(array1_addr[9]);
+	}
+	templates = (risc_attr & BIT_9) ? 2 : 1;
+	ql_dbg(ql_dbg_init, vha, 0x0160,
+	       "-> templates = %u\n", templates);
+
+	array3_offset = header->header_length + header->tim_length +
+		header->array1_length + header->array2_length;
+	if (array3_offset > blob->fw->size) {
+		ql_log(ql_log_fatal, vha, 0x0098,
+		       "FW image too small for Arr3 (%#lx > %#zx).\n",
+		       array3_offset, blob->fw->size);
+		goto img_corrupt;
+	}
+
+	array3_addr = (__be32 *)(((char *)fwcode) + array3_offset);
+	for (j = 0; j < templates; j++, fwdt++) {
+		vfree(fwdt->template);
+		fwdt->template = NULL;
+		fwdt->length = 0;
+
+		array_size = be32_to_cpu(array3_addr[2]);
+		ql_dbg(ql_dbg_init, vha, 0x0161,
+		       "-> fwdt%u template array at %p (%#x dwords)\n",
+		       j, array3_addr, array_size);
+
+		if (!array_size || !~array_size || array_size <= 8) {
+			ql_dbg(ql_dbg_init, vha, 0x0162,
+			       "-> fwdt%u failed to read array\n", j);
+			goto failed;
+		}
+
+		array3_addr += 7;
+		array_size -= 8;
+
+		if ((char *)&array3_addr[array_size] >
+		    (char *)blob->fw->data + blob->fw->size) {
+			ql_log(ql_log_warn, vha, 0x0163,
+			    "-> fwdt%u template array exceeds firmware blob.\n",
+			    j);
+			goto failed;
+		}
+
+		ql_dbg(ql_dbg_init, vha, 0x0163,
+		       "-> fwdt%u template allocate template %#x words...\n",
+		       j, array_size);
+		fwdt->template = vmalloc_array(array_size, sizeof(*dcode));
+		if (!fwdt->template) {
+			ql_log(ql_log_warn, vha, 0x0164,
+			       "-> fwdt%u failed allocate template.\n", j);
+			goto failed;
+		}
+
+		dcode = fwdt->template;
+		for (i = 0; i < array_size; i++)
+			dcode[i] = (__force u32)array3_addr[i];
+
+		if (!qla27xx_fwdt_template_valid(dcode)) {
+			ql_log(ql_log_warn, vha, 0x0165,
+			       "-> fwdt%u failed template validate\n", j);
+			goto failed;
+		}
+
+		dlen = qla27xx_fwdt_template_size(dcode);
+		ql_dbg(ql_dbg_init, vha, 0x0166,
+		       "-> fwdt%u template size %#lx bytes (%#lx words)\n",
+		       j, dlen, dlen / sizeof(*dcode));
+		if (dlen > array_size * sizeof(*dcode)) {
+			ql_log(ql_log_warn, vha, 0x0167,
+			       "-> fwdt%u template exceeds array (%-lu bytes)\n",
+			       j, dlen - array_size * sizeof(*dcode));
+			goto failed;
+		}
+
+		fwdt->length = dlen;
+		ql_dbg(ql_dbg_init, vha, 0x0168,
+		       "-> fwdt%u loaded template ok\n", j);
+
+		array3_addr += array_size + 1;
+	}
+	vfree(header);
+	return QLA_SUCCESS;
+
+failed:
+	vfree(fwdt->template);
+	fwdt->template = NULL;
+	fwdt->length = 0;
+img_corrupt:
+	vfree(header);
+	return QLA_FUNCTION_FAILED;
+}
+
+static int
+qla29xx_load_fw_template(scsi_qla_host_t *vha)
+{
+	struct qla_hw_data *ha = vha->hw;
+	struct fwdt *fwdt = ha->fwdt;
+	uint templates = 1;
+	void *fw_dump_tmplt;
+	uint32_t *dcode;
+	void *buf = NULL;
+	uint32_t len;
+	uint32_t template_size;
+	uint j = 0;
+	int rval = 0;
+
+	ql_dbg(ql_dbg_init, vha, 0x01bf,
+	       "-> templates = %u fw_dump_tmplt_len = 0x%x\n",
+	       templates, ha->fw_dump_tmplt_len);
+
+	if (!ha->fw_dump_tmplt_len) {
+		ql_dbg(ql_dbg_init, vha, 0x01bf,
+		       "no fw dump template available\n");
+		return QLA_SUCCESS;
+	}
+
+	fw_dump_tmplt = kzalloc(ha->fw_dump_tmplt_len, GFP_KERNEL);
+	if (!fw_dump_tmplt) {
+		ql_log(ql_log_info, vha, 0x0013,
+		       "Unable to allocate memory\n");
+		return QLA_FUNCTION_FAILED;
+	}
+
+	buf = qla29xx_read_optrom_data(vha, FLT_REG_FW_DUMP_TMPLT, 0,
+				       fw_dump_tmplt, 0,
+				       ha->fw_dump_tmplt_len);
+	if (!buf) {
+		ql_log(ql_log_info, vha, 0x0013,
+		       "Unable to read fw dump temp info.\n");
+		goto free_fw_dump;
+	}
+
+	ql_dump_buffer(ql_dbg_init, vha, 0x006b,
+		       (char *)fw_dump_tmplt, 1024);
+
+	for (j = 0; j < templates; j++, fwdt++) {
+		vfree(fwdt->template);
+		fwdt->template = NULL;
+		fwdt->length = 0;
+
+		template_size = le32_to_cpu(((__le32 *)fw_dump_tmplt)[2]);
+
+		ql_dbg(ql_dbg_init, vha, 0x0161,
+		       "-> fwdt%u template array at %p (0x%x bytes)\n",
+		       j, fw_dump_tmplt, template_size);
+
+		if (!template_size || !~template_size) {
+			ql_dbg(ql_dbg_init, vha, 0x0162,
+			       "-> fwdt%u failed to read array\n", j);
+			goto failed;
+		}
+
+		fwdt->template = vmalloc(template_size);
+		if (!fwdt->template) {
+			ql_log(ql_log_warn, vha, 0x0164,
+			       "-> fwdt%u failed allocate template.\n", j);
+			goto failed;
+		}
+
+		dcode = fwdt->template;
+		memcpy((char *)dcode, (char *)fw_dump_tmplt, template_size);
+
+		if (!qla27xx_fwdt_template_valid(dcode)) {
+			ql_log(ql_log_warn, vha, 0x0165,
+			       "-> fwdt%u failed template validate (rval %x)\n",
+			       j, rval);
+			goto failed;
+		}
+
+		len = qla27xx_fwdt_template_size(dcode);
+		if (len > template_size) {
+			ql_log(ql_log_warn, vha, 0x0167,
+			       "-> fwdt%u template exceeds array (%-u bytes)\n",
+			       j, len - template_size);
+			goto failed;
+		}
+
+		fwdt->length = len;
+	}
+
+	kfree(fw_dump_tmplt);
+	return QLA_SUCCESS;
+
+failed:
+	if (fwdt->template) {
+		vfree(fwdt->template);
+		fwdt->template = NULL;
+		fwdt->length = 0;
+	}
+free_fw_dump:
+	kfree(fw_dump_tmplt);
+	return QLA_FUNCTION_FAILED;
+}
+
+int
+qla29xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
+{
+	int rval;
+
+	*srisc_addr = 0x100000;
+
+	if (ql2xfwloadbin == 2) {
+		rval = qla29xx_load_risc_blob(vha, srisc_addr);
+		if (rval != QLA_SUCCESS) {
+			ql_log(ql_log_fatal, vha, 0x019e,
+			       "Failed to load firmware from file.\n");
+			return QLA_FUNCTION_FAILED;
+		}
+	} else {
+		rval = qla28xx_load_flash_firmware(vha);
+		if (rval != QLA_SUCCESS) {
+			ql_log(ql_log_fatal, vha, 0x019e,
+			       "Failed to load flash firmware.\n");
+			return QLA_FUNCTION_FAILED;
+		}
+
+		rval = qla29xx_load_fw_template(vha);
+		if (rval != QLA_SUCCESS) {
+			ql_log(ql_log_warn, vha, 0x01bd,
+			       "failed to read firmware template\n");
+			return QLA_FUNCTION_FAILED;
+		}
+	}
+
+	return rval;
+}
+
 void
 qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha)
 {
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 2b232b225c90..d49dacf6d576 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -618,7 +618,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
 
 int
 qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr,
-    uint32_t risc_code_size)
+		 uint32_t risc_code_size, int opt)
 {
 	int rval;
 	struct qla_hw_data *ha = vha->hw;
@@ -651,7 +651,14 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr,
 		mcp->out_mb |= MBX_4;
 	}
 
-	mcp->in_mb = MBX_1|MBX_0;
+	if (IS_QLA29XX(ha)) {
+		mcp->mb[9] = opt;
+		mcp->out_mb |= MBX_9;
+		mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+	} else {
+		mcp->in_mb = MBX_1|MBX_0;
+	}
+
 	mcp->tov = MBX_TOV_SECONDS;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(vha, mcp);
@@ -846,15 +853,19 @@ qla28xx_load_flash_firmware(scsi_qla_host_t *vha)
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (!IS_QLA28XX(ha))
+	if (!IS_QLA28XX(ha) && !IS_QLA29XX(ha))
 		return rval;
 
 	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x11a6,
 	       "Entered %s.\n", __func__);
 
 	mcp->mb[0] = MBC_LOAD_FLASH_FIRMWARE;
+	mcp->mb[1] = 0;
 	mcp->out_mb = MBX_2 | MBX_1 | MBX_0;
-	mcp->in_mb = MBX_0;
+	if (IS_QLA29XX(ha))
+		mcp->in_mb = MBX_1 | MBX_0;
+	else
+		mcp->in_mb = MBX_0;
 	mcp->tov = MBX_TOV_SECONDS;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(vha, mcp);
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index 298c060c1292..2366cca51bce 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -2663,7 +2663,7 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, __le32 *dwptr,
 
 			ret = qla2x00_load_ram(vha, optrom_dma,
 			    (ha->flash_data_off | faddr),
-			    OPTROM_BURST_DWORDS);
+			    OPTROM_BURST_DWORDS, 0);
 			if (ret != QLA_SUCCESS) {
 				ql_log(ql_log_warn, vha, 0xb01e,
 				    "Unable to burst-write optrom segment "
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index c3eb941f71ad..6560e58ad87c 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2640,6 +2640,45 @@ static struct isp_operations qla27xx_isp_ops = {
 	.initialize_adapter	= qla2x00_initialize_adapter,
 };
 
+static struct isp_operations qla29xx_isp_ops = {
+	.pci_config		= qla25xx_pci_config,
+	.reset_chip		= qla24xx_reset_chip,
+	.chip_diag		= qla24xx_chip_diag,
+	.config_rings		= qla24xx_config_rings,
+	.reset_adapter		= qla24xx_reset_adapter,
+	.nvram_config		= qla81xx_nvram_config,
+	.update_fw_options	= qla24xx_update_fw_options,
+	.load_risc		= qla29xx_load_risc,
+	.pci_info_str		= qla24xx_pci_info_str,
+	.fw_version_str		= qla24xx_fw_version_str,
+	.intr_handler		= qla24xx_intr_handler,
+	.enable_intrs		= qla24xx_enable_intrs,
+	.disable_intrs		= qla24xx_disable_intrs,
+	.abort_command		= qla24xx_abort_command,
+	.target_reset		= qla24xx_abort_target,
+	.lun_reset		= qla24xx_lun_reset,
+	.fabric_login		= qla24xx_login_fabric,
+	.fabric_logout		= qla24xx_fabric_logout,
+	.calc_req_entries	= NULL,
+	.build_iocbs		= NULL,
+	.prep_ms_iocb		= qla24xx_prep_ms_iocb,
+	.prep_ms_fdmi_iocb	= qla24xx_prep_ms_fdmi_iocb,
+	.read_nvram		= NULL,
+	.write_nvram		= NULL,
+	.fw_dump		= qla27xx_fwdump,
+	.mpi_fw_dump		= qla27xx_mpi_fwdump,
+	.beacon_on		= qla24xx_beacon_on,
+	.beacon_off		= qla24xx_beacon_off,
+	.beacon_blink		= qla83xx_beacon_blink,
+	.read_optrom		= qla25xx_read_optrom_data,
+	.write_optrom		= qla24xx_write_optrom_data,
+	.get_flash_version	= qla24xx_get_flash_version,
+	.start_scsi_mq		= qla2xxx_dif_start_scsi_mq,
+	.abort_isp		= qla2x00_abort_isp,
+	.iospace_config		= qla83xx_iospace_config,
+	.initialize_adapter	= qla2x00_initialize_adapter,
+};
+
 static inline void
 qla2x00_set_isp_flags(struct qla_hw_data *ha)
 {
@@ -3232,7 +3271,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 		ha->gid_list_info_size = 8;
 		ha->optrom_size = OPTROM_SIZE_28XX;
 		ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
-		ha->isp_ops = &qla27xx_isp_ops;
+		ha->isp_ops = &qla29xx_isp_ops;
 		ha->flash_conf_off = ~0;
 		ha->flash_data_off = ~0;
 		ha->nvram_conf_off = ~0;
@@ -7676,6 +7715,7 @@ qla2x00_timer(struct timer_list *t)
 #define FW_ISP8031	9
 #define FW_ISP27XX	10
 #define FW_ISP28XX	11
+#define FW_ISP29XX	12
 
 #define FW_FILE_ISP21XX	"ql2100_fw.bin"
 #define FW_FILE_ISP22XX	"ql2200_fw.bin"
@@ -7689,6 +7729,7 @@ qla2x00_timer(struct timer_list *t)
 #define FW_FILE_ISP8031	"ql8300_fw.bin"
 #define FW_FILE_ISP27XX	"ql2700_fw.bin"
 #define FW_FILE_ISP28XX	"ql2800_fw.bin"
+#define FW_FILE_ISP29XX	"ql2900_fw.bin"
 
 
 static DEFINE_MUTEX(qla_fw_lock);
@@ -7706,6 +7747,7 @@ static struct fw_blob qla_fw_blobs[] = {
 	{ .name = FW_FILE_ISP8031, },
 	{ .name = FW_FILE_ISP27XX, },
 	{ .name = FW_FILE_ISP28XX, },
+	{ .name = FW_FILE_ISP29XX, },
 	{ .name = NULL, },
 };
 
@@ -7739,6 +7781,8 @@ qla2x00_request_firmware(scsi_qla_host_t *vha)
 		blob = &qla_fw_blobs[FW_ISP27XX];
 	} else if (IS_QLA28XX(ha)) {
 		blob = &qla_fw_blobs[FW_ISP28XX];
+	} else if (IS_QLA29XX(ha)) {
+		blob = &qla_fw_blobs[FW_ISP29XX];
 	} else {
 		return NULL;
 	}
@@ -8445,3 +8489,4 @@ MODULE_FIRMWARE(FW_FILE_ISP2300);
 MODULE_FIRMWARE(FW_FILE_ISP2322);
 MODULE_FIRMWARE(FW_FILE_ISP24XX);
 MODULE_FIRMWARE(FW_FILE_ISP25XX);
+MODULE_FIRMWARE(FW_FILE_ISP29XX);
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 2229c2b084cf..1d5ea5e432ed 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -1897,7 +1897,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, __le32 *dwptr, uint32_t faddr,
 			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
 			    "Write burst (%#lx dwords)...\n", dburst);
 			ret = qla2x00_load_ram(vha, optrom_dma,
-			    flash_data_addr(ha, faddr), dburst);
+			    flash_data_addr(ha, faddr), dburst, 0);
 			if (!ret) {
 				liter += dburst - 1;
 				faddr += dburst - 1;
@@ -3497,7 +3497,7 @@ qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
 		ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
 		    "Write burst (%#lx dwords)...\n", dburst);
 		rval = qla2x00_load_ram(vha, optrom_dma,
-		    flash_data_addr(ha, faddr), dburst);
+		    flash_data_addr(ha, faddr), dburst, 0);
 		if (rval != QLA_SUCCESS) {
 			ql_log(ql_log_warn, vha, 0x7097,
 			    "Failed burst write at %x (%p/%#llx)...\n",
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 07/60] scsi: qla2xxx: Add flash block read/write BSG support for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (5 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 06/60] scsi: qla2xxx: Add FC operational firmware load for 29xx Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:11   ` sashiko-bot
  2026-06-12 10:55   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 08/60] scsi: qla2xxx: Add BSG MPI firmware load/dump " Nilesh Javali
                   ` (52 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Manish Rangankar <mrangankar@marvell.com>

Introduce QL_VND_READ_FLASH_BLOCK and QL_VND_WRITE_FLASH_BLOCK
BSG vendor commands so that userspace tools can perform flash
block-level operations on 29xx adapters via the isp_ops
interface.

Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_attr.c |   1 -
 drivers/scsi/qla2xxx/qla_bsg.c  | 286 +++++++++++++++++++++++++++-----
 drivers/scsi/qla2xxx/qla_bsg.h  |  16 ++
 drivers/scsi/qla2xxx/qla_def.h  |   7 +
 drivers/scsi/qla2xxx/qla_os.c   |  24 ++-
 5 files changed, 292 insertions(+), 42 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 6a05ce195aa0..800751ab562a 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -580,7 +580,6 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
 	ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size);
 	mutex_unlock(&ha->optrom_mutex);
 
-	ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size);
 skip:
 	return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
 }
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 5e910b5ca670..0baf486e8fb8 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -1407,23 +1407,14 @@ qla24xx_iidma(struct bsg_job *bsg_job)
 
 static int
 qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
-	uint8_t is_update)
+	uint32_t start, uint8_t is_update)
 {
-	struct fc_bsg_request *bsg_request = bsg_job->request;
-	uint32_t start = 0;
 	int valid = 0;
 	struct qla_hw_data *ha = vha->hw;
 
 	if (unlikely(pci_channel_offline(ha->pdev)))
 		return -EINVAL;
 
-	start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
-	if (start > ha->optrom_size) {
-		ql_log(ql_log_warn, vha, 0x7055,
-		    "start %d > optrom_size %d.\n", start, ha->optrom_size);
-		return -EINVAL;
-	}
-
 	if (ha->optrom_state != QLA_SWAITING) {
 		ql_log(ql_log_info, vha, 0x7056,
 		    "optrom_state %d.\n", ha->optrom_state);
@@ -1431,42 +1422,79 @@ qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
 	}
 
 	ha->optrom_region_start = start;
-	ql_dbg(ql_dbg_user, vha, 0x7057, "is_update=%d.\n", is_update);
-	if (is_update) {
-		if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
-			valid = 1;
-		else if (start == (ha->flt_region_boot * 4) ||
-		    start == (ha->flt_region_fw * 4))
-			valid = 1;
-		else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
-		    IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
-		    IS_QLA28XX(ha))
-			valid = 1;
-		if (!valid) {
-			ql_log(ql_log_warn, vha, 0x7058,
-			    "Invalid start region 0x%x/0x%x.\n", start,
-			    bsg_job->request_payload.payload_len);
+
+	if (IS_QLA29XX(ha)) {
+		if (start > ha->optrom_size) {
+			ql_log(ql_log_warn, vha, 0x7055,
+			    "start %d > optrom_size %d.\n", start,
+			    ha->optrom_size);
 			return -EINVAL;
 		}
 
-		ha->optrom_region_size = start +
-		    bsg_job->request_payload.payload_len > ha->optrom_size ?
-		    ha->optrom_size - start :
-		    bsg_job->request_payload.payload_len;
-		ha->optrom_state = QLA_SWRITING;
+		if (is_update) {
+			ha->optrom_region_size = start +
+			    bsg_job->request_payload.payload_len >
+			    ha->optrom_size ?
+			    ha->optrom_size - start :
+			    bsg_job->request_payload.payload_len;
+			ha->optrom_state = QLA_SWRITING;
+		} else {
+			ha->optrom_region_size = start +
+			    bsg_job->reply_payload.payload_len >
+			    ha->optrom_size ?
+			    ha->optrom_size - start :
+			    bsg_job->reply_payload.payload_len;
+			ha->optrom_state = QLA_SREADING;
+		}
 	} else {
-		ha->optrom_region_size = start +
-		    bsg_job->reply_payload.payload_len > ha->optrom_size ?
-		    ha->optrom_size - start :
-		    bsg_job->reply_payload.payload_len;
-		ha->optrom_state = QLA_SREADING;
+		if (start > ha->optrom_size) {
+			ql_log(ql_log_warn, vha, 0x7055,
+			    "start %d > optrom_size %d.\n", start,
+			    ha->optrom_size);
+			return -EINVAL;
+		}
+
+		ql_dbg(ql_dbg_user, vha, 0x7057,
+		    "is_update=%d.\n", is_update);
+		if (is_update) {
+			if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
+				valid = 1;
+			else if (start == (ha->flt_region_boot * 4) ||
+			    start == (ha->flt_region_fw * 4))
+				valid = 1;
+			else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
+			    IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) ||
+			    IS_QLA27XX(ha) || IS_QLA28XX(ha))
+				valid = 1;
+			if (!valid) {
+				ql_log(ql_log_warn, vha, 0x7058,
+				    "Invalid start region 0x%x/0x%x.\n",
+				    start,
+				    bsg_job->request_payload.payload_len);
+				return -EINVAL;
+			}
+
+			ha->optrom_region_size = start +
+			    bsg_job->request_payload.payload_len >
+			    ha->optrom_size ?
+			    ha->optrom_size - start :
+			    bsg_job->request_payload.payload_len;
+			ha->optrom_state = QLA_SWRITING;
+		} else {
+			ha->optrom_region_size = start +
+			    bsg_job->reply_payload.payload_len >
+			    ha->optrom_size ?
+			    ha->optrom_size - start :
+			    bsg_job->reply_payload.payload_len;
+			ha->optrom_state = QLA_SREADING;
+		}
 	}
 
 	ha->optrom_buffer = vzalloc(ha->optrom_region_size);
 	if (!ha->optrom_buffer) {
 		ql_log(ql_log_warn, vha, 0x7059,
-		    "Read: Unable to allocate memory for optrom retrieval "
-		    "(%x)\n", ha->optrom_region_size);
+		    "%s: Unable to allocate memory for optrom retrieval (%x)\n",
+		    __func__, ha->optrom_region_size);
 
 		ha->optrom_state = QLA_SWAITING;
 		return -ENOMEM;
@@ -1478,17 +1506,25 @@ qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
 static int
 qla2x00_read_optrom(struct bsg_job *bsg_job)
 {
+	struct fc_bsg_request *bsg_request = bsg_job->request;
 	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
 	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
 	scsi_qla_host_t *vha = shost_priv(host);
 	struct qla_hw_data *ha = vha->hw;
+	uint32_t start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
 	int rval = 0;
 
 	if (ha->flags.nic_core_reset_hdlr_active)
 		return -EBUSY;
 
+	if (IS_QLA29XX(ha)) {
+		ql_log(ql_log_warn, vha, 0x7070,
+		    "Legacy optrom read not supported on 29xx.\n");
+		return -EINVAL;
+	}
+
 	mutex_lock(&ha->optrom_mutex);
-	rval = qla2x00_optrom_setup(bsg_job, vha, 0);
+	rval = qla2x00_optrom_setup(bsg_job, vha, start, 0);
 	if (rval) {
 		mutex_unlock(&ha->optrom_mutex);
 		return rval;
@@ -1515,14 +1551,16 @@ qla2x00_read_optrom(struct bsg_job *bsg_job)
 static int
 qla2x00_update_optrom(struct bsg_job *bsg_job)
 {
+	struct fc_bsg_request *bsg_request = bsg_job->request;
 	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
 	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
 	scsi_qla_host_t *vha = shost_priv(host);
 	struct qla_hw_data *ha = vha->hw;
+	uint32_t start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
 	int rval = 0;
 
 	mutex_lock(&ha->optrom_mutex);
-	rval = qla2x00_optrom_setup(bsg_job, vha, 1);
+	rval = qla2x00_optrom_setup(bsg_job, vha, start, 1);
 	if (rval) {
 		mutex_unlock(&ha->optrom_mutex);
 		return rval;
@@ -1554,6 +1592,170 @@ qla2x00_update_optrom(struct bsg_job *bsg_job)
 	return rval;
 }
 
+/**
+ * qla29xx_bsg_flash_block_read - Read flash block for QLA29XX.
+ * @bsg_job: BSG job structure.
+ *
+ * Returns 0 on success, error code on failure.
+ */
+static int qla29xx_bsg_flash_block_read(struct bsg_job *bsg_job)
+{
+	struct fc_bsg_request *bsg_req = bsg_job->request;
+	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
+	scsi_qla_host_t *vha = shost_priv(host);
+	struct qla_hw_data *ha = vha->hw;
+	struct qla_block_rw *brcmd;
+	void *buf;
+	uint16_t opts = 0;
+	int rval = 0;
+
+	if (bsg_job->request_len < sizeof(struct fc_bsg_request) +
+	    2 * sizeof(uint32_t) + sizeof(struct qla_block_rw))
+		return -EINVAL;
+
+	brcmd =
+	(struct qla_block_rw *)&bsg_req->rqst_data.h_vendor.vendor_cmd[2];
+
+	ql_log(ql_log_info, vha, 0x7062,
+	       "%s: region 0x%x options 0x%x rw_length 0x%x offset 0x%x chunk_length 0x%x\n",
+		__func__, brcmd->region, brcmd->options, brcmd->rw_length,
+		brcmd->region_offset, brcmd->chunk_length);
+
+	mutex_lock(&ha->optrom_mutex);
+	rval = qla2x00_optrom_setup(bsg_job, vha, brcmd->region_offset, 0);
+	if (rval) {
+		mutex_unlock(&ha->optrom_mutex);
+		return rval;
+	}
+
+	check_and_set_mbc_bits(brcmd->options, opts, QLA_IS_TIM, BIT_15);
+	check_and_set_mbc_bits(brcmd->options, opts, QLA_IS_SECURE, BIT_7);
+	check_and_set_mbc_bits(brcmd->options, opts, QLA_UPDATE_MBR, BIT_8);
+
+	if (!ha->isp_ops->read_optrom_region) {
+		vfree(ha->optrom_buffer);
+		ha->optrom_buffer = NULL;
+		ha->optrom_state = QLA_SWAITING;
+		mutex_unlock(&ha->optrom_mutex);
+		return -EINVAL;
+	}
+
+	buf = ha->isp_ops->read_optrom_region(vha, brcmd->region, opts,
+				ha->optrom_buffer, ha->optrom_region_start,
+				ha->optrom_region_size);
+	if (!buf) {
+		ql_log(ql_log_warn, vha, 0x7063,
+			"%s failed to read flash region 0x%x\n",
+			__func__, brcmd->region);
+		bsg_reply->result = -EINVAL;
+		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
+							EXT_STATUS_MAILBOX;
+		bsg_reply->reply_payload_rcv_len = 0;
+	} else {
+		bsg_reply->result = DID_OK;
+		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
+			EXT_STATUS_OK;
+
+		ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x72a6,
+			       ha->optrom_buffer, ha->optrom_region_size);
+
+		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+				    bsg_job->reply_payload.sg_cnt,
+				    ha->optrom_buffer,
+				    ha->optrom_region_size);
+
+		bsg_reply->reply_payload_rcv_len = ha->optrom_region_size;
+	}
+	vfree(ha->optrom_buffer);
+	ha->optrom_buffer = NULL;
+	ha->optrom_state = QLA_SWAITING;
+	mutex_unlock(&ha->optrom_mutex);
+	bsg_job_done(bsg_job, bsg_reply->result,
+		     bsg_reply->reply_payload_rcv_len);
+
+	return rval;
+}
+
+/**
+ * qla29xx_bsg_flash_block_write - Write flash block for QLA29XX.
+ * @bsg_job: BSG job structure.
+ *
+ * Returns 0 on success, error code on failure.
+ */
+static int qla29xx_bsg_flash_block_write(struct bsg_job *bsg_job)
+{
+	struct fc_bsg_request *bsg_req = bsg_job->request;
+	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
+	scsi_qla_host_t *vha = shost_priv(host);
+	struct qla_hw_data *ha = vha->hw;
+	struct qla_block_rw *bwcmd;
+	uint16_t opts = 0;
+	int rval = 0;
+
+	if (bsg_job->request_len < sizeof(struct fc_bsg_request) +
+	    2 * sizeof(uint32_t) + sizeof(struct qla_block_rw))
+		return -EINVAL;
+
+	bwcmd =
+	   (struct qla_block_rw *)&bsg_req->rqst_data.h_vendor.vendor_cmd[2];
+
+	ql_log(ql_log_info, vha, 0x7064,
+	       "%s: region 0x%x options 0x%x rw_length 0x%x offset 0x%x chunk_length 0x%x\n",
+		__func__, bwcmd->region, bwcmd->options, bwcmd->rw_length,
+		bwcmd->region_offset, bwcmd->chunk_length);
+
+	mutex_lock(&ha->optrom_mutex);
+	rval = qla2x00_optrom_setup(bsg_job, vha, bwcmd->region_offset, 1);
+	if (rval) {
+		mutex_unlock(&ha->optrom_mutex);
+		return rval;
+	}
+
+	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+			bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
+			ha->optrom_region_size);
+
+	ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x73a6,
+		       ha->optrom_buffer, ha->optrom_region_size);
+
+	check_and_set_mbc_bits(bwcmd->options, opts, QLA_IS_TIM, BIT_15);
+	check_and_set_mbc_bits(bwcmd->options, opts, QLA_IS_SECURE, BIT_7);
+	check_and_set_mbc_bits(bwcmd->options, opts, QLA_UPDATE_MBR, BIT_8);
+
+	if (!ha->isp_ops->write_optrom_region) {
+		vfree(ha->optrom_buffer);
+		ha->optrom_buffer = NULL;
+		ha->optrom_state = QLA_SWAITING;
+		mutex_unlock(&ha->optrom_mutex);
+		return -EINVAL;
+	}
+
+	rval = ha->isp_ops->write_optrom_region(vha, bwcmd->region, opts,
+				ha->optrom_buffer, ha->optrom_region_start,
+				ha->optrom_region_size);
+	if (rval) {
+		ql_log(ql_log_warn, vha, 0x7065,
+			"%s failed to write flash %x\n", __func__, rval);
+		bsg_reply->result = -EINVAL;
+		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
+							EXT_STATUS_MAILBOX;
+	} else {
+		bsg_reply->result = DID_OK;
+		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
+			EXT_STATUS_OK;
+	}
+	vfree(ha->optrom_buffer);
+	ha->optrom_buffer = NULL;
+	ha->optrom_state = QLA_SWAITING;
+	mutex_unlock(&ha->optrom_mutex);
+	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+	bsg_job_done(bsg_job, bsg_reply->result,
+			bsg_reply->reply_payload_rcv_len);
+	return 0;
+}
+
 static int
 qla2x00_update_fru_versions(struct bsg_job *bsg_job)
 {
@@ -3007,6 +3209,12 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_j
 	case QL_VND_MBX_PASSTHRU:
 		return qla2x00_mailbox_passthru(bsg_job);
 
+	case QL_VND_READ_FLASH_BLOCK:
+		return qla29xx_bsg_flash_block_read(bsg_job);
+
+	case QL_VND_WRITE_FLASH_BLOCK:
+		return qla29xx_bsg_flash_block_write(bsg_job);
+
 	default:
 		return -ENOSYS;
 	}
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index a920c8e482bc..ca0d83986b57 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -40,6 +40,8 @@
 #define QL_VND_MBX_PASSTHRU		0x2B
 #define QL_VND_DPORT_DIAGNOSTICS_V2	0x2C
 #define QL_VND_IMG_SET_VALID	0x30
+#define QL_VND_READ_FLASH_BLOCK		0x33
+#define QL_VND_WRITE_FLASH_BLOCK	0x34
 
 /* BSG Vendor specific subcode returns */
 #define EXT_STATUS_OK			0
@@ -83,6 +85,20 @@
 #define ELS_OPCODE_BYTE			0x10
 
 /* BSG Vendor specific definations */
+
+#define QLA_IS_TIM	0x1
+#define QLA_IS_SECURE	0x2
+#define QLA_UPDATE_MBR	0x4
+
+struct qla_block_rw {
+	uint32_t region;
+	uint32_t rw_length;
+	uint32_t options;
+	uint32_t region_offset;
+	uint32_t chunk_length;
+	uint8_t  reserved[44];
+} __packed;
+
 #define A84_ISSUE_WRITE_TYPE_CMD        0
 #define A84_ISSUE_READ_TYPE_CMD         1
 #define A84_CLEANUP_CMD                 2
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 1ec7ee578e0c..719b6a1f9123 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3534,6 +3534,13 @@ struct isp_operations {
 	int (*write_optrom)(struct scsi_qla_host *, void *, uint32_t,
 		uint32_t);
 
+	void *(*read_optrom_region)(struct scsi_qla_host *vha,
+		uint16_t reg_code, uint16_t opts, void *buf,
+		uint32_t offset, uint32_t length);
+	int (*write_optrom_region)(struct scsi_qla_host *vha,
+		uint16_t reg_code, uint16_t opts, void *buf,
+		uint32_t offset, uint32_t length);
+
 	int (*get_flash_version) (struct scsi_qla_host *, void *);
 	int (*start_scsi) (srb_t *);
 	int (*start_scsi_mq) (srb_t *);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 6560e58ad87c..948242f0088e 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2640,6 +2640,24 @@ static struct isp_operations qla27xx_isp_ops = {
 	.initialize_adapter	= qla2x00_initialize_adapter,
 };
 
+static void *
+qla29xx_read_optrom_stub(struct scsi_qla_host *vha, void *buf,
+			 uint32_t offset, uint32_t length)
+{
+	ql_dbg(ql_dbg_init, vha, 0x0191,
+	    "read_optrom not supported on 29xx, use read_optrom_region.\n");
+	return NULL;
+}
+
+static int
+qla29xx_write_optrom_stub(struct scsi_qla_host *vha, void *buf,
+			  uint32_t offset, uint32_t length)
+{
+	ql_dbg(ql_dbg_init, vha, 0x0192,
+	    "write_optrom not supported on 29xx, use write_optrom_region.\n");
+	return QLA_FUNCTION_FAILED;
+}
+
 static struct isp_operations qla29xx_isp_ops = {
 	.pci_config		= qla25xx_pci_config,
 	.reset_chip		= qla24xx_reset_chip,
@@ -2670,8 +2688,10 @@ static struct isp_operations qla29xx_isp_ops = {
 	.beacon_on		= qla24xx_beacon_on,
 	.beacon_off		= qla24xx_beacon_off,
 	.beacon_blink		= qla83xx_beacon_blink,
-	.read_optrom		= qla25xx_read_optrom_data,
-	.write_optrom		= qla24xx_write_optrom_data,
+	.read_optrom		= qla29xx_read_optrom_stub,
+	.write_optrom		= qla29xx_write_optrom_stub,
+	.read_optrom_region	= qla29xx_read_optrom_data,
+	.write_optrom_region	= qla29xx_write_optrom_data,
 	.get_flash_version	= qla24xx_get_flash_version,
 	.start_scsi_mq		= qla2xxx_dif_start_scsi_mq,
 	.abort_isp		= qla2x00_abort_isp,
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 08/60] scsi: qla2xxx: Add BSG MPI firmware load/dump for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (6 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 07/60] scsi: qla2xxx: Add flash block read/write BSG support " Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:14   ` sashiko-bot
  2026-06-12 10:57   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 09/60] scsi: qla2xxx: Add 128-byte IOCB definitions " Nilesh Javali
                   ` (51 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Manish Rangankar <mrangankar@marvell.com>

Add BSG vendor commands for loading and dumping MPI firmware on
29xx adapters.  This extends the existing BSG infrastructure with
the necessary mailbox wrappers and flash helpers for MPI
operations.

Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_bsg.c | 153 +++++++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_bsg.h |  18 ++++
 drivers/scsi/qla2xxx/qla_def.h |   5 ++
 drivers/scsi/qla2xxx/qla_gbl.h |   5 ++
 drivers/scsi/qla2xxx/qla_mbx.c |  45 ++++++++++
 drivers/scsi/qla2xxx/qla_sup.c | 117 +++++++++++++++++++++++++
 6 files changed, 343 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 0baf486e8fb8..92a0bc6dc7bc 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -1756,6 +1756,153 @@ static int qla29xx_bsg_flash_block_write(struct bsg_job *bsg_job)
 	return 0;
 }
 
+static int qla2900_bsg_dump_mpi(struct bsg_job *bsg_job)
+{
+	struct fc_bsg_request *bsg_req = bsg_job->request;
+	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
+	scsi_qla_host_t *vha = shost_priv(host);
+	struct qla_hw_data *ha = vha->hw;
+	struct qla_load_dump_mpi *dmcmd;
+	uint16_t opts = 0;
+	int rval = 0;
+
+	if (bsg_job->request_len < sizeof(struct fc_bsg_request) +
+	    2 * sizeof(uint32_t) + sizeof(struct qla_load_dump_mpi))
+		return -EINVAL;
+
+	dmcmd =
+	(struct qla_load_dump_mpi *)&bsg_req->rqst_data.h_vendor.vendor_cmd[2];
+
+	ql_log(ql_log_info, vha, 0xffff,
+	       "%s: mpi_address 0x%x mpi options 0x%x length 0x%x\n",
+		__func__, dmcmd->mpi_address, dmcmd->options, dmcmd->length);
+
+	mutex_lock(&ha->optrom_mutex);
+	rval = qla2x00_optrom_setup(bsg_job, vha, dmcmd->mpi_address, 1);
+	if (rval) {
+		mutex_unlock(&ha->optrom_mutex);
+		return rval;
+	}
+
+	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+			  bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
+			  ha->optrom_region_size);
+
+	ql_dump_buffer(ql_dbg_init, vha, 0x00d7, ha->optrom_buffer,
+			ha->optrom_region_size);
+
+	check_and_set_mbc_bits(dmcmd->options, opts, QLA_LDM_SECURE_ENABLE,
+			       BIT_3);
+	check_and_set_mbc_bits(dmcmd->options, opts, QLA_LDM_OTP_PROV, BIT_4);
+	check_and_set_mbc_bits(dmcmd->options, opts, QLA_LDM_DEV_CSR, BIT_5);
+	check_and_set_mbc_bits(dmcmd->options, opts, QLA_LDM_AUTH_CMD_BIN,
+			       BIT_6);
+	check_and_set_mbc_bits(dmcmd->options, opts, QLA_LDM_MLDSA_ALGO,
+			       BIT_9);
+
+	rval = qla29xx_mpi_optrom_data(vha, opts, ha->optrom_buffer,
+				       ha->optrom_region_start,
+				       ha->optrom_region_size,
+				       QLA29XX_MPI_OP_DUMP);
+	if (rval) {
+		ql_log(ql_log_warn, vha, 0xffff,
+			"%s failed mpi dump %x\n", __func__, rval);
+		bsg_reply->result = -EINVAL;
+		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
+							EXT_STATUS_MAILBOX;
+	} else {
+		bsg_reply->result = DID_OK;
+		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
+			EXT_STATUS_OK;
+	}
+
+	vfree(ha->optrom_buffer);
+	ha->optrom_buffer = NULL;
+	ha->optrom_state = QLA_SWAITING;
+	mutex_unlock(&ha->optrom_mutex);
+	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+	bsg_job_done(bsg_job, bsg_reply->result,
+			bsg_reply->reply_payload_rcv_len);
+	return 0;
+}
+
+static int qla2900_bsg_load_mpi(struct bsg_job *bsg_job)
+{
+	struct fc_bsg_request *bsg_req = bsg_job->request;
+	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
+	scsi_qla_host_t *vha = shost_priv(host);
+	struct qla_hw_data *ha = vha->hw;
+	struct qla_load_dump_mpi *lmcmd;
+	uint16_t opts = 0;
+	int rval = 0;
+
+	if (bsg_job->request_len < sizeof(struct fc_bsg_request) +
+	    2 * sizeof(uint32_t) + sizeof(struct qla_load_dump_mpi))
+		return -EINVAL;
+
+	lmcmd =
+	(struct qla_load_dump_mpi *)&bsg_req->rqst_data.h_vendor.vendor_cmd[2];
+
+	ql_log(ql_log_info, vha, 0xffff,
+	       "%s: mpi_address 0x%x mpi options 0x%x length 0x%x\n",
+		__func__, lmcmd->mpi_address, lmcmd->options, lmcmd->length);
+
+	mutex_lock(&ha->optrom_mutex);
+	rval = qla2x00_optrom_setup(bsg_job, vha, lmcmd->mpi_address, 0);
+	if (rval) {
+		mutex_unlock(&ha->optrom_mutex);
+		return rval;
+	}
+
+	check_and_set_mbc_bits(lmcmd->options, opts, QLA_LDM_SECURE_ENABLE,
+			       BIT_3);
+	check_and_set_mbc_bits(lmcmd->options, opts, QLA_LDM_DEV_CSR, BIT_5);
+	check_and_set_mbc_bits(lmcmd->options, opts, QLA_LDM_SHADOW_REGS,
+			       BIT_7);
+	check_and_set_mbc_bits(lmcmd->options, opts, QLA_LDM_CA_CSR, BIT_8);
+	check_and_set_mbc_bits(lmcmd->options, opts, QLA_LDM_MLDSA_ALGO,
+			       BIT_9);
+	check_and_set_mbc_bits(lmcmd->options, opts, QLA_LDM_MLDSA_SIGNATURE,
+			       BIT_10);
+
+	rval = qla29xx_mpi_optrom_data(vha, opts, ha->optrom_buffer,
+				       ha->optrom_region_start,
+				       ha->optrom_region_size,
+				       QLA29XX_MPI_OP_LOAD);
+	if (rval) {
+		ql_log(ql_log_warn, vha, 0xffff,
+			"%s failed mpi load %x\n", __func__, rval);
+		bsg_reply->result = -EINVAL;
+		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
+							EXT_STATUS_MAILBOX;
+	} else {
+		bsg_reply->result = DID_OK;
+		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
+			EXT_STATUS_OK;
+	}
+
+	ql_dump_buffer(ql_dbg_init, vha, 0x00d7, ha->optrom_buffer,
+			ha->optrom_region_size);
+
+	sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+			    bsg_job->reply_payload.sg_cnt,
+			    ha->optrom_buffer,
+			    ha->optrom_region_size);
+
+	bsg_reply->reply_payload_rcv_len = ha->optrom_region_size;
+	vfree(ha->optrom_buffer);
+	ha->optrom_buffer = NULL;
+	ha->optrom_state = QLA_SWAITING;
+	mutex_unlock(&ha->optrom_mutex);
+	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+	bsg_job_done(bsg_job, bsg_reply->result,
+		     bsg_reply->reply_payload_rcv_len);
+
+	return rval;
+}
+
 static int
 qla2x00_update_fru_versions(struct bsg_job *bsg_job)
 {
@@ -3215,6 +3362,12 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_j
 	case QL_VND_WRITE_FLASH_BLOCK:
 		return qla29xx_bsg_flash_block_write(bsg_job);
 
+	case QL_VND_LOAD_MPI:
+		return qla2900_bsg_load_mpi(bsg_job);
+
+	case QL_VND_DUMP_MPI:
+		return qla2900_bsg_dump_mpi(bsg_job);
+
 	default:
 		return -ENOSYS;
 	}
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index ca0d83986b57..8a784b8226cc 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -42,6 +42,8 @@
 #define QL_VND_IMG_SET_VALID	0x30
 #define QL_VND_READ_FLASH_BLOCK		0x33
 #define QL_VND_WRITE_FLASH_BLOCK	0x34
+#define QL_VND_LOAD_MPI			0x35
+#define QL_VND_DUMP_MPI			0x36
 
 /* BSG Vendor specific subcode returns */
 #define EXT_STATUS_OK			0
@@ -99,6 +101,22 @@ struct qla_block_rw {
 	uint8_t  reserved[44];
 } __packed;
 
+struct qla_load_dump_mpi {
+	uint32_t mpi_address;
+	uint32_t length;
+	uint32_t options;
+#define	QLA_LDM_SECURE_ENABLE	0x1
+#define	QLA_LDM_OTP_PROV	0x2
+#define	QLA_LDM_DEV_CSR		0x4
+#define	QLA_LDM_AUTH_CMD_BIN	0x8
+#define	QLA_LDM_SHADOW_REGS	0x10
+#define	QLA_LDM_CA_CSR		0x20
+#define	QLA_LDM_MLDSA_ALGO	0x40
+#define	QLA_LDM_MLDSA_SIGNATURE	0x80
+
+	uint8_t reserved[52];
+} __packed;
+
 #define A84_ISSUE_WRITE_TYPE_CMD        0
 #define A84_ISSUE_READ_TYPE_CMD         1
 #define A84_CLEANUP_CMD                 2
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 719b6a1f9123..7423687578dc 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1548,6 +1548,11 @@ typedef struct {
 #define PD_STATE_PORT_LOGOUT			10
 #define PD_STATE_WAIT_PORT_LOGOUT_ACK		11
 
+enum qla29xx_mpi_optrom_op {
+	QLA29XX_MPI_OP_DUMP,
+	QLA29XX_MPI_OP_LOAD,
+};
+
 
 #define QLA_ZIO_MODE_6		(BIT_2 | BIT_1)
 #define QLA_ZIO_DISABLED	0
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index ca5a80b9c3d2..84aaff130400 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -697,6 +697,11 @@ extern int qla29xx_write_optrom_data(struct scsi_qla_host *vha,
 				     uint16_t reg_code, uint16_t opts,
 				     void *buf, uint32_t offset,
 				     uint32_t length);
+extern int qla29xx_mpi_optrom_data(struct scsi_qla_host *vha, uint16_t opts,
+				   void *buf, uint32_t offset, uint32_t length,
+				   enum qla29xx_mpi_optrom_op op);
+extern int qla29xx_load_dump_mpi(scsi_qla_host_t *vha, uint16_t opt,
+				 uint32_t mpi_addr, uint32_t dlen, dma_addr_t req_dma);
 /*
  * Global Function Prototypes in qla_dbg.c source file.
  */
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index d49dacf6d576..9c2633ca5036 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -7415,3 +7415,48 @@ int qla29xx_flash_block_write(scsi_qla_host_t *vha, dma_addr_t req_dma,
 
 	return rval;
 }
+
+int
+qla29xx_load_dump_mpi(scsi_qla_host_t *vha, uint16_t opt, uint32_t mpi_addr,
+		      uint32_t dlen, dma_addr_t req_dma)
+{
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	int rval = 0;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0xffff,
+	       "Entered %s mpi_addr 0x%x len 0x%x opt 0x%x.\n",
+		__func__, mpi_addr, dlen, opt);
+
+	memset(mcp->mb, 0, sizeof(mcp->mb));
+
+	mcp->mb[0] = MBC_LOAD_DUMP_MPI_RAM;
+	mcp->mb[9] = opt;
+	mcp->mb[1] = LSW(mpi_addr);
+	mcp->mb[8] = MSW(mpi_addr);
+
+	mcp->mb[2] = MSW(req_dma);
+	mcp->mb[3] = LSW(req_dma);
+	mcp->mb[6] = MSW(MSD(req_dma));
+	mcp->mb[7] = LSW(MSD(req_dma));
+
+	mcp->mb[4] = MSW(dlen);
+	mcp->mb[5] = LSW(dlen);
+
+	mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_1|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS)
+		ql_dbg(ql_dbg_mbx, vha, 0x110a,
+		       "Failed=%x mb=(0x%x,0x%x).\n",
+			rval, mcp->mb[0], mcp->mb[1]);
+	else
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x110b,
+		       "Done %s mb=(0x%x,0x%x,0x%x).\n", __func__,
+		       mcp->mb[0], mcp->mb[1],  mcp->mb[2]);
+
+	return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 1d5ea5e432ed..af7509083910 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -527,6 +527,123 @@ qla29xx_read_optrom_data(struct scsi_qla_host *vha, uint16_t reg_code,
 	return NULL;
 }
 
+static void set_chunk_mpi_bits(uint16_t *options, int count, int total)
+{
+	/* - Single chunk complete segment/image
+	 * - 1st chunk of a segment/image
+	 * - Last chunk of a segment/image
+	 */
+	if (total == 1)
+		*options |= BIT_2 | BIT_1;
+	else if (count == 0)
+		*options |= BIT_1;
+	else if (count == total - 1)
+		*options |= BIT_2;
+}
+
+/**
+ * qla29xx_mpi_optrom_data - Dump/load MPI optrom data for 29xx.
+ * @vha: Pointer to SCSI QLogic host structure.
+ * @opts: Options for the operation.
+ * @buf: Buffer to read from/write to.
+ * @offset: Offset into the device memory.
+ * @length: Length of data, in bytes.
+ * @op: Operation, either QLA29XX_MPI_OP_DUMP or QLA29XX_MPI_OP_LOAD.
+ *
+ * Returns:
+ * QLA_SUCCESS on success or an error code on failure.
+ */
+int
+qla29xx_mpi_optrom_data(struct scsi_qla_host *vha, uint16_t opts, void *buf,
+		       uint32_t offset, uint32_t length, enum qla29xx_mpi_optrom_op op)
+{
+	struct qla_hw_data *ha = vha->hw;
+	dma_addr_t optrom_dma;
+	void *optrom;
+	uint32_t mpi_addr, mpi_size, burst = 0;
+	uint32_t total_chunks = 0;
+	uint32_t *dcode, *fwcode;
+	uint16_t chunk_count = 0;
+	int rval = -EINVAL;
+
+	optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+				    &optrom_dma, GFP_KERNEL);
+	if (!optrom) {
+		ql_log(ql_log_warn, vha, 0x0090,
+			"Unable to allocate memory for optrom burst read (%x KB).\n",
+			OPTROM_BURST_SIZE / 1024);
+		rval = -ENOMEM;
+		goto exit_mpi_op;
+	}
+
+	mpi_addr = offset;
+	dcode = (uint32_t *)optrom;
+	memset(dcode, 0, OPTROM_BURST_SIZE);
+
+	fwcode = (uint32_t *)buf;
+	mpi_size = length >> 2;
+	burst = OPTROM_BURST_SIZE >> 2;
+	total_chunks = (mpi_size + burst - 1) / burst;
+
+	while (mpi_size > 0) {
+		uint16_t options = 0;
+
+		if (burst > mpi_size)
+			burst = mpi_size;
+
+		set_chunk_mpi_bits(&options, chunk_count, total_chunks);
+
+		if (op == QLA29XX_MPI_OP_DUMP) {
+			options |= (BIT_0);
+			options |= opts;
+
+			ql_log(ql_log_info, vha, 0x008b,
+				"-> %s (DUMP): %#x <-(%#x words) (0x%x options) chunk (0x%x, 0x%x)\n",
+				__func__, mpi_addr, burst, options, chunk_count,
+				total_chunks);
+
+			memcpy(dcode, fwcode, burst * 4);
+
+			rval = qla29xx_load_dump_mpi(vha, options, mpi_addr, burst,
+						     optrom_dma);
+			if (rval) {
+				ql_log(ql_log_fatal, vha, 0x0098,
+					"Failed dump mpi firmware.\n");
+				goto free_buf;
+			}
+		} else if (op == QLA29XX_MPI_OP_LOAD) {
+			options |= opts;
+
+			ql_log(ql_log_info, vha, 0x008b,
+				"-> %s (LOAD): %#x <-(%#x words) (0x%x options) chunk (0x%x, 0x%x)\n",
+				__func__, mpi_addr, burst, options, chunk_count,
+				total_chunks);
+
+			rval = qla29xx_load_dump_mpi(vha, options, mpi_addr, burst,
+						     optrom_dma);
+			if (rval) {
+				ql_log(ql_log_fatal, vha, 0x0098,
+					"Failed load mpi firmware.\n");
+				goto free_buf;
+			}
+			memcpy(fwcode, dcode, burst * 4);
+		}
+
+		chunk_count++;
+		fwcode += burst;
+		mpi_addr += burst;
+		mpi_size -= burst;
+	}
+
+	rval = QLA_SUCCESS;
+free_buf:
+	dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
+			  optrom_dma);
+
+exit_mpi_op:
+	return rval;
+}
+
 /*
  * NVRAM support routines
  */
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 09/60] scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (7 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 08/60] scsi: qla2xxx: Add BSG MPI firmware load/dump " Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 11:01   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 10/60] scsi: qla2xxx: Add extended status continuation and marker IOCBs Nilesh Javali
                   ` (50 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Anil Gurumurthy <agurumurthy@marvell.com>

The 29xx series uses 128-byte IOCBs instead of the 64-byte IOCBs
used by earlier adapters.  Add a new header (qla_fw29.h) with the
extended IOCB structure definitions that match the 29xx firmware
interface.

Signed-off-by: Anil Gurumurthy <agurumurthy@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_fw29.h | 725 ++++++++++++++++++++++++++++++++
 1 file changed, 725 insertions(+)
 create mode 100644 drivers/scsi/qla2xxx/qla_fw29.h

diff --git a/drivers/scsi/qla2xxx/qla_fw29.h b/drivers/scsi/qla2xxx/qla_fw29.h
new file mode 100644
index 000000000000..e294b3f033db
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_fw29.h
@@ -0,0 +1,725 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c)  2026- Marvell.
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#ifndef __QLA_FW29_H
+#define __QLA_FW29_H
+
+#include "qla_fw.h"
+
+/* Control Flags 2 common for cmd6 and 7 */
+#define CF2_VMID_ENABLE			BIT_0
+#define CF2_CSCTL_PRIORITY_TAG		BIT_1
+#define CF2_NO_TRNF_READY_ENABLE	BIT_2
+#define CF2_RX_ID_ENABLE		BIT_3
+
+/*
+ * vp_index layout for 29xx extended command IOCBs
+ * (cmd_type_6_ext, cmd_type_7_ext, cmd_type_crc_2_ext, ...):
+ *   bits [8:0]   - VP index (9 bits)
+ *   bits [15:9]  - reserved, must be zero
+ * Access on a host-endian value via le16_to_cpu(vp_index) & CMD_EXT_VP_INDEX_MASK.
+ */
+#define CMD_EXT_VP_INDEX_MASK		0x01ff
+/*
+ * ISP queue - command entry structure definition.
+ */
+#define NUM_CMD67_DSDS	4
+struct cmd_type_6_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	uint32_t handle;		/* System handle. */
+
+	__le16	nport_handle;		/* N_PORT handle. */
+	__le16	timeout;		/* Command timeout. */
+
+	__le16	dseg_count;		/* Data segment count. */
+
+	__le16	fcp_rsp_dsd_len;	/* FCP_RSP DSD length. */
+
+	struct scsi_lun lun;		/* FCP LUN (BE). */
+
+	__le16	control_flags;		/* Control flags. */
+
+	__le16	fcp_cmnd_dseg_len;	/* Data segment length. */
+					/* Data segment address. */
+	__le64	 fcp_cmnd_dseg_address __packed;
+					/* Data segment address. */
+	__le64	 fcp_rsp_dseg_address __packed;
+
+	__le32	byte_count;		/* Total byte count. */
+	__le16	control_flags_2;		/* Control flags 2. */
+
+	__le16	vp_index;		/* VP Index 9bits*/
+	__le32	fburstlen_rxid;		/* First Burst length/RX ID */
+	__le16 io_tag;			/* I/O Tag */
+	uint8_t vl_n_fctl;		/* VL (7-4) | RSVD (3-2) | F_CTL [17] (1) | RSVD (0) */
+	uint8_t prtag_csctl;		/* Priority Tag or CS_CTL */
+	__le32	src_vm_id;		/* Source VM ID */
+	uint8_t reserved_2[16];		/* Reserved */
+	struct dsd64 dsd[NUM_CMD67_DSDS];		/* Data Segment Descriptors */
+};
+
+struct cmd_type_7_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t handle;		/* System handle. */
+	__le16	nport_handle;		/* N_PORT handle. */
+	__le16	timeout;		/* Command timeout. */
+
+	__le16	dseg_count;		/* Data segment count. */
+	uint16_t reserved_1;
+
+	struct scsi_lun lun;		/* FCP LUN (BE). */
+
+	__le16	task_mgmt_flags;	/* Task management flags. */
+
+	uint8_t task;
+	uint8_t crn;
+	uint8_t fcp_cdb[MAX_CMDSZ];	/* SCSI command words. */
+	__le32	byte_count;		/* Total byte count. */
+	__le16	ctrl_flags_2;		/* Control flags 2 */
+	__le16	vp_index;		/* VP Index 9bits*/
+	__le32	rx_id;			/* Receive Exchange ID */
+	__le16	io_tag;			/* I/O Tag */
+	uint8_t vl_n_fctl;		/* VL (7-4) | RSVD (3-2) | F_CTL [17] (1) | RSVD (0) */
+	uint8_t reserved_3[21];		/* Reserved */
+	struct dsd64 dsd[NUM_CMD67_DSDS];	/* Data Segment Descriptors */
+};
+
+struct cmd_type_crc_2_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	uint32_t handle;		/* System handle. */
+
+	__le16	nport_handle;		/* N_PORT handle. */
+	__le16	timeout;		/* Command timeout. */
+
+	__le16	dseg_count;		/* Data segment count. */
+	__le16	fcp_rsp_dseg_len;	/* FCP_RSP DSD length. */
+
+	struct scsi_lun lun;		/* FCP LUN (BE). */
+
+	__le16	control_flags_1;		/* Control flags. */
+	__le16	fcp_cmnd_dseg_len;	/* Data segment length. */
+
+	__le64	 fcp_cmnd_dseg_address __packed;
+					/* Data segment address. */
+	__le64	 fcp_rsp_dseg_address __packed;
+
+	__le32	byte_count;		/* Total byte count. */
+
+	__le16	control_flags_2;		/* Control flags - 2 */
+	__le16	vp_index;		/* VP Index (bits [8:0]); bits [15:9] reserved.
+					 * See CMD_EXT_VP_INDEX_MASK.
+					 */
+
+	uint32_t reserved_1;
+
+	__le16	 iocb_tag; /* Unused */
+	__le16 vl_prio; /* Bit 1 - F_CTL, Bits 4-7 VL, rest are rsvd */
+
+	uint32_t reserved_2; /* 3C-3F offset */
+
+	__le32 ref_tag;
+	uint8_t ref_tag_mask[4];	/* Validation/Replacement Mask*/
+
+	__le16 app_tag;
+	uint8_t app_tag_mask[2];	/* Validation/Replacement Mask*/
+
+	__le16 blk_size;		/* Data size in bytes */
+	__le16 prot_opts;		/* Requested Data Protection Mode */
+
+	__le32 tot_byte_count;		/* Total byte count/ total data
+					 * transfer count
+					 */
+	union {
+		struct {
+			uint32_t	reserved_1; /* offset 54 */
+			uint16_t	reserved_2;
+			__le16		guard_seed; /* offset 5A */
+			struct dsd64	data_dsd[1];
+			uint32_t	reserved_5[2];
+			uint32_t	reserved_6;
+		} nobundling;
+		struct {
+			__le32	dif_byte_count;	/* Total DIF byte
+						 * count
+						 */
+			__le16	dseg_count;	/* Data segment count */
+			__le16 guard_seed;      /* Initial Guard Seed */
+			struct dsd64	data_dsd[1];
+			struct dsd64	dif_dsd;
+		} bundling;
+	} u;
+	uint8_t reserved_3[12];			/* MUST be set to 0. */
+};
+
+/*
+ * ISP queue - status entry structure definition.
+ */
+struct sts_entry_24xx_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	uint32_t handle;		/* System handle. */
+
+	__le16	comp_status;		/* Completion status. */
+	__le16	ox_id;			/* OX_ID used by the firmware. */
+
+	__le32	residual_len;		/* FW calc residual transfer length. */
+
+	union {
+		__le16 reserved_1;
+		__le16 nvme_rsp_pyld_len;
+	} u1;
+
+	__le16	state_flags;		/* State flags. */
+
+	__le16 read_sa_index;
+	__le16 wr_sa_index;
+	uint8_t	reserved_2[8];
+	uint8_t act_dif[8];
+	uint8_t exp_dif[8];
+	union {
+		struct {
+			__le32	rsp_data_len_dma;	/* FCP response data length  */
+			uint8_t reserved_3[76];
+		};
+		struct {
+			uint8_t nvme_ersp_data[32];
+			uint8_t reserved_4[48];
+		};
+		struct {
+			__le32	bid_rd_rsp_residual_count;	/* BID read rsp residual cnt */
+			__le16	retry_delay_timer;	/* Retry delay timer. */
+			__le16	scsi_status;		/* SCSI status. */
+			__le32	rsp_residual_count;	/* FCP RSP residual count. */
+			__le32	sense_len;		/* FCP SENSE length. */
+			__le32	rsp_data_len_ndma;	/* FCP response data length  */
+			uint8_t	data[60];	/* FCP rsp/sense information */
+		};
+	} u2;
+
+	/*
+	 * If DIF Error is set in comp_status, these additional fields are
+	 * defined:
+	 *
+	 * !!! NOTE: Firmware sends expected/actual DIF data in big endian
+	 * format; but all of the "data" field gets swab32-d in the beginning
+	 * of qla2900_status_entry().
+	 *
+	 * &data[10] : uint8_t report_runt_bg[2];	- computed guard
+	 * &data[12] : uint8_t actual_dif[8];		- DIF Data received
+	 * &data[20] : uint8_t expected_dif[8];		- DIF Data computed
+	 */
+};
+
+/*
+ * ISP queue - marker entry structure definition.
+ */
+struct mrk_entry_24xx_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t handle_count;		/* Handle count. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	uint32_t handle;		/* System handle. */
+
+	__le16	nport_handle;		/* N_PORT handle. */
+
+	uint8_t modifier;		/* Modifier (7-0). */
+	uint8_t reserved_1;
+
+	__le16	vp_index;	/* VP Index. 9bits*/
+	uint16_t reserved_3;
+
+	uint8_t lun[8];			/* FCP LUN (BE). */
+	uint8_t reserved_4[104];
+};
+
+/*
+ * ISP queue - CT Pass-Through entry structure definition.
+ */
+#define NUM_CT_DSDS	5
+struct ct_entry_24xx_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System Defined. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	uint32_t handle;		/* System handle. */
+
+	__le16	comp_status;		/* Completion status. */
+
+	__le16	nport_handle;		/* N_PORT handle. */
+
+	__le16	cmd_dsd_count;
+
+	__le16	vp_index;		/* vp index 9 bits*/
+
+	__le16	timeout;		/* Command timeout. */
+	uint16_t reserved_2;
+
+	__le16	rsp_dsd_count;
+
+	uint8_t reserved_3[10];
+	uint8_t reserved_4[28];		/* Reserved. */
+
+	__le32	rsp_byte_count;
+	__le32	cmd_byte_count;
+	struct dsd64 dsd[NUM_CT_DSDS];	/* Data Segment Descriptors */
+};
+
+/*
+ * ISP queue - PUREX IOCB entry structure definition
+ */
+struct purex_entry_24xx_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	__le16	reserved1;
+	__le16	vp_idx;			/* VP index 9 bits*/
+
+	__le16	status_flags;
+	__le16	nport_handle;
+
+	__le16	frame_size;
+	__le16	trunc_frame_size;
+
+	__le32	rx_xchg_addr;
+
+	uint8_t d_id[3];
+	uint8_t r_ctl;
+
+	uint8_t s_id[3];
+	uint8_t cs_ctl;
+
+	uint8_t f_ctl[3];
+	uint8_t type;
+
+	__le16	seq_cnt;
+	uint8_t df_ctl;
+	uint8_t seq_id;
+
+	__le16	rx_id;
+	__le16	ox_id;
+	__le32	param;
+
+	uint8_t els_frame_payload[84];
+};
+
+/*
+ * ISP queue - ELS Pass-Through entry structure definition.
+ * ELS_EXT_EST_SOFI*: 4-bit sof_type for extended IOCBs (qla_fw.h EST_SOFI*
+ * is for els_entry_24xx byte layout).
+ */
+#define ELS_EXT_EST_SOFI3	(1 << 1)
+#define ELS_EXT_EST_SOFI2	(3 << 3)
+
+struct els_entry_24xx_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System Defined. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	uint32_t handle;		/* System handle. */
+
+	__le16	comp_status;		/* response only */
+	__le16	nport_handle;
+
+	__le16	tx_dsd_count;
+
+	__le16	vp_index : 9;		/* VP Index 9bits */
+	__le16	reserved_1_sof : 3;
+	__le16	sof_type : 4;
+
+	__le32	rx_xchg_address;	/* Receive exchange address. */
+	__le16	rx_dsd_count;
+
+	uint8_t opcode;
+	uint8_t reserved_2;
+
+	uint8_t d_id[3];
+	uint8_t s_id[3];
+
+	__le16	control_flags;		/* Control flags. */
+
+	union {
+		struct {
+			__le32	 rx_byte_count;
+			__le32	 tx_byte_count;
+
+			__le64	 tx_address __packed;	/* DSD 0 address. */
+			__le32	 tx_len;		/* DSD 0 length. */
+
+			__le64	 rx_address __packed;	/* DSD 1 address. */
+			__le32	 rx_len;		/* DSD 1 length. */
+		};
+		struct {
+			__le32	total_byte_count;
+			__le32	error_subcode_1;
+			__le32	error_subcode_2;
+			__le32	error_subcode_3;
+			uint8_t reserved_3[16];
+		};
+	};
+	uint8_t reserved_4[64];
+};
+
+struct els_sts_entry_24xx_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System Defined. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	__le32	handle;		/* System handle. */
+
+	__le16	comp_status;
+
+	__le16	nport_handle;		/* N_PORT handle. */
+
+	__le16	reserved_1;
+
+	__le16	vp_index : 9;		/* VP Index 9bits */
+	__le16	reserved_1_sof : 3;
+	__le16	sof_type : 4;
+
+	__le32	rx_xchg_address;	/* Receive exchange address. */
+	__le16	reserved_2;
+
+	uint8_t opcode;
+	uint8_t reserved_3;
+
+	uint8_t d_id[3];
+	uint8_t s_id[3];
+
+	__le16	control_flags;		/* Control flags. */
+	__le32	total_byte_count;
+	__le32	error_subcode_1;
+	__le32	error_subcode_2;
+	__le32	error_subcode_3;
+
+	uint8_t	reserved_4[80];
+};
+
+struct logio_entry_24xx_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	uint32_t handle;		/* System handle. */
+
+	__le16	comp_status;		/* Completion status. */
+
+	__le16	nport_handle;		/* N_PORT handle. */
+
+	__le16	control_flags;		/* Control flags. */
+
+	__le16	vp_index;		/* VP Index 9bits*/
+
+	uint8_t port_id[3];		/* PortID of destination port. */
+
+	uint8_t rsp_size;		/* Response size in 32bit words. */
+
+	__le32	io_parameter[11];	/* General I/O parameters. */
+	uint8_t reserved_2[64];		/* Reserved*/
+};
+
+struct tsk_mgmt_entry_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t handle_count;		/* Handle count. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	uint32_t handle;		/* System handle. */
+
+	__le16	nport_handle;		/* N_PORT handle. */
+
+	__le16	reserved_1;
+
+	__le16	delay;			/* Activity delay in seconds. */
+
+	__le16	timeout;		/* Command timeout. */
+
+	struct scsi_lun lun;		/* FCP LUN (BE). */
+
+	__le32	control_flags;		/* Control Flags. */
+
+	__le16	vp_index;	/* VP Index 9bits */
+
+	uint8_t reserved_3[98];
+};
+
+struct abort_entry_24xx_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t handle_count;		/* Handle count. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	uint32_t handle;		/* System handle. */
+
+	union {
+		__le16 nport_handle;            /* N_PORT handle. */
+		__le16 comp_status;             /* Completion status. */
+	};
+
+	__le16	options;		/* Options. */
+
+	uint32_t handle_to_abort;	/* System handle to abort. */
+
+	__le16	req_que_no;
+
+	__le16	vp_index;		/* VP Index 9bits*/
+	u8	reserved_2[4];
+	union {
+		struct {
+			__le16 abts_rty_cnt;
+			__le16 rsp_timeout;
+		} drv;
+		struct {
+			u8	ba_rjt_vendorUnique;
+			u8	ba_rjt_reasonCodeExpl;
+			u8	ba_rjt_reasonCode;
+			u8	reserved_3;
+		} fw;
+	};
+	u8	reserved_4[100];
+};
+
+struct abts_entry_24xx_ext {
+	uint8_t entry_type;
+	uint8_t entry_count;
+	uint8_t handle_count;
+	uint8_t entry_status;
+
+	__le32	handle;		/* type 0x55 only */
+
+	__le16	comp_status;		/* type 0x55 only */
+	__le16	nport_handle;		/* type 0x54 only */
+
+	__le16	control_flags;		/* type 0x55 only */
+	__le16	vp_idx : 9;		/* VP index 9 bits */
+	__le16	reserved_1_sof : 3;
+	__le16	sof_type : 4;		/* sof_type is upper nibble */
+
+	__le32	rx_xch_addr;
+
+	uint8_t d_id[3];
+	uint8_t r_ctl;
+
+	uint8_t s_id[3];
+	uint8_t cs_ctl;
+
+	uint8_t f_ctl[3];
+	uint8_t type;
+
+	__le16	seq_cnt;
+	uint8_t df_ctl;
+	uint8_t seq_id;
+
+	__le16	rx_id;
+	__le16	ox_id;
+
+	__le32	param;
+
+	union {
+		struct {
+			__le32	subcode3;
+			__le32	rsvd;
+			__le32	subcode1;
+			__le32	subcode2;
+		} error;
+		struct {
+			__le16	rsrvd1;
+			uint8_t last_seq_id;
+			uint8_t seq_id_valid;
+			__le16	aborted_rx_id;
+			__le16	aborted_ox_id;
+			__le16	high_seq_cnt;
+			__le16	low_seq_cnt;
+		} ba_acc;
+		struct {
+			uint8_t vendor_unique;
+			uint8_t explanation;
+			uint8_t reason;
+		} ba_rjt;
+	} payload;
+
+	__le32	rx_xch_addr_to_abort;
+	uint8_t reserved_2[64];
+} __packed;
+/*
+ * Virtual Port Control IOCB
+ */
+struct vp_ctrl_entry_24xx_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	uint32_t handle;		/* System handle. */
+
+	__le16	vp_idx_failed;
+
+	__le16	comp_status;		/* Completion status. */
+
+	__le16	command;
+
+	__le16	vp_count;
+
+	uint8_t vp_idx_map[16];
+	__le16	flags;
+	__le16	id;
+	uint16_t reserved_4;
+	__le16	hopct;
+	uint8_t reserved_5[88];
+};
+
+/*
+ * Modify Virtual Port Configuration IOCB
+ */
+struct vp_config_entry_24xx_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t handle_count;
+	uint8_t entry_status;		/* Entry Status. */
+
+	uint32_t handle;		/* System handle. */
+
+	__le16	flags;
+
+	__le16	comp_status;		/* Completion status. */
+
+	uint8_t command;
+
+	uint8_t vp_count;
+
+	uint8_t vp_index1;
+	uint8_t vp_index2;
+
+	uint8_t options_idx1;
+	uint8_t hard_address_idx1;
+	uint16_t reserved_vp1;
+	uint8_t port_name_idx1[WWN_SIZE];
+	uint8_t node_name_idx1[WWN_SIZE];
+
+	uint8_t options_idx2;
+	uint8_t hard_address_idx2;
+	uint16_t reserved_vp2;
+	uint8_t port_name_idx2[WWN_SIZE];
+	uint8_t node_name_idx2[WWN_SIZE];
+	__le16	id;
+	uint16_t reserved_4;
+	__le16	hopct;
+	uint8_t reserved_5[66];
+};
+
+struct vp_rpt_id_entry_24xx_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	__le32 resv1;
+	uint8_t vp_acquired;
+	uint8_t vp_setup;
+	__le16	vp_idx : 9;		/* VP Index 9bits */
+	__le16	vp_status : 7;		/* VP Status 7bits */
+
+	uint8_t port_id[3];
+	uint8_t format;
+	union {
+		struct vp_rpt_id_ext_f1 {
+			/* format 1 fabric */
+			uint8_t vpstat1_subcode; /* vp_status=1 subcode */
+			uint8_t flags;
+
+			uint16_t fip_flags;
+			uint8_t rsv2[12];
+
+			uint8_t ls_rjt_vendor;
+			uint8_t ls_rjt_explanation;
+			uint8_t ls_rjt_reason;
+			uint8_t rsv3;
+			__le16	rsv8;
+			__le16	flogi_acc_payload_size;	/* bits [8:0] meaningful */
+			uint8_t port_name[8];
+			uint8_t node_name[8];
+			uint16_t bbcr;
+			uint8_t reserved_5[6];
+		} f1;
+		struct vp_rpt_id_ext_f2 { /* format 2: N2N direct connect */
+			uint8_t vpstat1_subcode;
+			uint8_t flags;
+			uint16_t fip_flags;
+			uint8_t rsv2[12];
+
+			uint8_t ls_rjt_vendor;
+			uint8_t ls_rjt_explanation;
+			uint8_t ls_rjt_reason;
+			uint8_t rsv3[5];
+
+			uint8_t port_name[8];
+			uint8_t node_name[8];
+			uint16_t bbcr;
+			uint8_t reserved_5[2];
+			uint8_t remote_nport_id[4];
+		} f2;
+	} u;
+};
+
+struct qla_fmb_version {
+	uint8_t major;
+	uint8_t minor;
+	uint8_t sub;
+	uint8_t build;
+};
+
+struct qla_fmb_upd_time {
+	uint16_t year;
+	uint8_t  month;
+	uint8_t  day;
+
+	uint8_t  hour;
+	uint8_t  minute;
+	uint8_t  second;
+	uint8_t  reserved;
+};
+
+struct qla_flash_memo_block {
+	int32_t  signature;	/* "FMBS" */
+#define QLFC_FMB_SIG 0x464D4253
+	uint32_t length;
+	uint32_t version;
+#define QLFC_FMB_VERSION 3
+	uint32_t checksum;
+	struct qla_fmb_version ffv_ver;
+	struct qla_fmb_version mbi_ver;
+	struct  {    /* offset 0x18: MBI package build time: YYYYMMDD */
+		uint16_t year;
+		uint8_t  month;
+		uint8_t  day;
+		uint8_t  reserve[4];
+	} bld_time;
+	uint8_t tool_id[4];
+	struct qla_fmb_upd_time upd_time;	/* offset 0x24: flash update time stamp */
+	struct qla_fmb_version  tool_version;	/* offset 0x2C: FW/tool version */
+};
+
+#endif
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 10/60] scsi: qla2xxx: Add extended status continuation and marker IOCBs
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (8 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 09/60] scsi: qla2xxx: Add 128-byte IOCB definitions " Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 11:02   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 11/60] scsi: qla2xxx: Remove duplicate flash memo block definitions Nilesh Javali
                   ` (49 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Anil Gurumurthy <agurumurthy@marvell.com>

Add the 128-byte sts_cont_entry_ext_t and mrk_entry_ext_t
structures required by 29xx firmware.  Include the qla_fw29.h
header from qla_def.h so the new types are available throughout
the driver.

Signed-off-by: Anil Gurumurthy <agurumurthy@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_def.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 7423687578dc..4de0de5cccc8 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -337,6 +337,7 @@ static inline void wrt_reg_dword(volatile __le32 __iomem *addr, u32 data)
 
 #define MAX_CMDSZ	16		/* SCSI maximum CDB size. */
 #include "qla_fw.h"
+#include "qla_fw29.h"
 
 struct name_list_extended {
 	struct get_name_list_extended *l;
@@ -2360,6 +2361,15 @@ typedef struct {
 	uint8_t reserved_2[48];
 } mrk_entry_t;
 
+/* 29xx definitions */
+struct sts_cont_entry_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint8_t data[124];		/* data */
+};
+
 /*
  * ISP queue - Management Server entry structure definition.
  */
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 11/60] scsi: qla2xxx: Remove duplicate flash memo block definitions
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (9 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 10/60] scsi: qla2xxx: Add extended status continuation and marker IOCBs Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 11:03   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 12/60] scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx Nilesh Javali
                   ` (48 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Anil Gurumurthy <agurumurthy@marvell.com>

The qla_flash_memo_block and related structures in qla_fw29.h
duplicate definitions already present elsewhere.  Remove the
duplicates to avoid divergence and build warnings.

Signed-off-by: Anil Gurumurthy <agurumurthy@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_fw29.h | 39 ---------------------------------
 1 file changed, 39 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_fw29.h b/drivers/scsi/qla2xxx/qla_fw29.h
index e294b3f033db..efe1c60bee81 100644
--- a/drivers/scsi/qla2xxx/qla_fw29.h
+++ b/drivers/scsi/qla2xxx/qla_fw29.h
@@ -683,43 +683,4 @@ struct vp_rpt_id_entry_24xx_ext {
 		} f2;
 	} u;
 };
-
-struct qla_fmb_version {
-	uint8_t major;
-	uint8_t minor;
-	uint8_t sub;
-	uint8_t build;
-};
-
-struct qla_fmb_upd_time {
-	uint16_t year;
-	uint8_t  month;
-	uint8_t  day;
-
-	uint8_t  hour;
-	uint8_t  minute;
-	uint8_t  second;
-	uint8_t  reserved;
-};
-
-struct qla_flash_memo_block {
-	int32_t  signature;	/* "FMBS" */
-#define QLFC_FMB_SIG 0x464D4253
-	uint32_t length;
-	uint32_t version;
-#define QLFC_FMB_VERSION 3
-	uint32_t checksum;
-	struct qla_fmb_version ffv_ver;
-	struct qla_fmb_version mbi_ver;
-	struct  {    /* offset 0x18: MBI package build time: YYYYMMDD */
-		uint16_t year;
-		uint8_t  month;
-		uint8_t  day;
-		uint8_t  reserve[4];
-	} bld_time;
-	uint8_t tool_id[4];
-	struct qla_fmb_upd_time upd_time;	/* offset 0x24: flash update time stamp */
-	struct qla_fmb_version  tool_version;	/* offset 0x2C: FW/tool version */
-};
-
 #endif
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 12/60] scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (10 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 11/60] scsi: qla2xxx: Remove duplicate flash memo block definitions Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:29   ` sashiko-bot
  2026-06-12 11:12   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 13/60] scsi: qla2xxx: Replace IS_QLA29XX() size checks with entry-size helpers Nilesh Javali
                   ` (47 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Anil Gurumurthy <agurumurthy@marvell.com>

Wire the 128-byte extended IOCB structures into the IO submission,
completion, and queue-management paths.  On 29xx adapters the driver
now builds cmd_type_6_ext / cmd_type_7_ext command IOCBs and processes
the corresponding extended status entries, while falling back to the
existing 64-byte IOCBs for earlier adapters.

Ring entry-size selection uses the qla_req_entry_size() /
qla_rsp_entry_size() helpers and ring slot advancement uses
qla_req_ring_advance() rather than open-coding IS_QLA29XX() branches
at every call site.

Signed-off-by: Anil Gurumurthy <agurumurthy@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_dbg.c    |  31 +-
 drivers/scsi/qla2xxx/qla_def.h    |  24 +
 drivers/scsi/qla2xxx/qla_edif.c   |  18 +-
 drivers/scsi/qla2xxx/qla_fw29.h   |  77 +++
 drivers/scsi/qla2xxx/qla_gbl.h    |   4 +-
 drivers/scsi/qla2xxx/qla_init.c   |  59 +-
 drivers/scsi/qla2xxx/qla_inline.h | 174 +++++-
 drivers/scsi/qla2xxx/qla_iocb.c   | 940 +++++++++++++++++++++++++-----
 drivers/scsi/qla2xxx/qla_isr.c    |  48 +-
 drivers/scsi/qla2xxx/qla_mid.c    |  31 +-
 drivers/scsi/qla2xxx/qla_nvme.c   | 123 ++--
 drivers/scsi/qla2xxx/qla_os.c     |  33 +-
 drivers/scsi/qla2xxx/qla_target.c |  17 +-
 13 files changed, 1323 insertions(+), 256 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index a7e3ec9bba47..acb58daacf35 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -89,16 +89,17 @@ qla2xxx_copy_queues(struct qla_hw_data *ha, void *ptr)
 {
 	struct req_que *req = ha->req_q_map[0];
 	struct rsp_que *rsp = ha->rsp_q_map[0];
+	size_t req_entry_size = qla_req_entry_size(ha);
+	size_t rsp_entry_size = qla_rsp_entry_size(ha);
+
 	/* Request queue. */
-	memcpy(ptr, req->ring, req->length *
-	    sizeof(request_t));
+	memcpy(ptr, req->ring, req->length * req_entry_size);
 
 	/* Response queue. */
-	ptr += req->length * sizeof(request_t);
-	memcpy(ptr, rsp->ring, rsp->length  *
-	    sizeof(response_t));
+	ptr += req->length * req_entry_size;
+	memcpy(ptr, rsp->ring, rsp->length * rsp_entry_size);
 
-	return ptr + (rsp->length * sizeof(response_t));
+	return ptr + (rsp->length * rsp_entry_size);
 }
 
 int
@@ -606,6 +607,8 @@ qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, __be32 **last_chain)
 	struct req_que *req;
 	struct rsp_que *rsp;
 	int que;
+	size_t req_entry_size = qla_req_entry_size(ha);
+	size_t rsp_entry_size = qla_rsp_entry_size(ha);
 
 	if (!ha->mqenable)
 		return ptr;
@@ -623,19 +626,19 @@ qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, __be32 **last_chain)
 		q->chain_size = htonl(
 		    sizeof(struct qla2xxx_mqueue_chain) +
 		    sizeof(struct qla2xxx_mqueue_header) +
-		    (req->length * sizeof(request_t)));
+		    (req->length * req_entry_size));
 		ptr += sizeof(struct qla2xxx_mqueue_chain);
 
 		/* Add header. */
 		qh = ptr;
 		qh->queue = htonl(TYPE_REQUEST_QUEUE);
 		qh->number = htonl(que);
-		qh->size = htonl(req->length * sizeof(request_t));
+		qh->size = htonl(req->length * req_entry_size);
 		ptr += sizeof(struct qla2xxx_mqueue_header);
 
 		/* Add data. */
-		memcpy(ptr, req->ring, req->length * sizeof(request_t));
-		ptr += req->length * sizeof(request_t);
+		memcpy(ptr, req->ring, req->length * req_entry_size);
+		ptr += req->length * req_entry_size;
 	}
 
 	/* Response queues */
@@ -651,19 +654,19 @@ qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, __be32 **last_chain)
 		q->chain_size = htonl(
 		    sizeof(struct qla2xxx_mqueue_chain) +
 		    sizeof(struct qla2xxx_mqueue_header) +
-		    (rsp->length * sizeof(response_t)));
+		    (rsp->length * rsp_entry_size));
 		ptr += sizeof(struct qla2xxx_mqueue_chain);
 
 		/* Add header. */
 		qh = ptr;
 		qh->queue = htonl(TYPE_RESPONSE_QUEUE);
 		qh->number = htonl(que);
-		qh->size = htonl(rsp->length * sizeof(response_t));
+		qh->size = htonl(rsp->length * rsp_entry_size);
 		ptr += sizeof(struct qla2xxx_mqueue_header);
 
 		/* Add data. */
-		memcpy(ptr, rsp->ring, rsp->length * sizeof(response_t));
-		ptr += rsp->length * sizeof(response_t);
+		memcpy(ptr, rsp->ring, rsp->length * rsp_entry_size);
+		ptr += rsp->length * rsp_entry_size;
 	}
 
 	return ptr;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 4de0de5cccc8..2b57782b3cd3 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2528,6 +2528,14 @@ struct imm_ntfy_from_isp {
 #define REQUEST_ENTRY_SIZE	(sizeof(request_t))
 
 
+/*
+ * 29xx (qla29xx) uses 128-byte ring entries for both request and response
+ * queues.  These macros give the size of an extended IOCB slot and are
+ * used when allocating from / zeroing the 29xx request ring via ring_ext_ptr.
+ */
+#define RESPONSE_ENTRY_SIZE_EXT (sizeof(struct response_ext))
+#define REQUEST_ENTRY_SIZE_EXT  (sizeof(struct request_ext))
+
 
 /*
  * Switch info gathering structure.
@@ -3789,6 +3797,14 @@ struct rsp_que {
 	dma_addr_t  dma;
 	response_t *ring;
 	response_t *ring_ptr;
+	/*
+	 * 29xx extended IOCB ring (128-byte entries) aliases of ring/ring_ptr.
+	 * Allocated when IS_QLA29XX(ha); set up at queue-init time to point at
+	 * the same DMA memory as 'ring' but typed for the 29xx stride.  24xx
+	 * code paths walk via ring_ptr; 29xx paths walk via ring_ext_ptr.
+	 */
+	struct response_ext *ring_ext;
+	struct response_ext *ring_ext_ptr;
 	__le32	__iomem *rsp_q_in;	/* FWI2-capable only. */
 	__le32	__iomem *rsp_q_out;
 	uint16_t  ring_index;
@@ -3816,6 +3832,14 @@ struct req_que {
 	dma_addr_t  dma;
 	request_t *ring;
 	request_t *ring_ptr;
+	/*
+	 * 29xx extended IOCB ring (128-byte entries) aliases of ring/ring_ptr.
+	 * Allocated when IS_QLA29XX(ha); set up at queue-init time to point at
+	 * the same DMA memory as 'ring' but typed for the 29xx stride.  24xx
+	 * code paths must not run on 29xx HW, and vice-versa.
+	 */
+	struct request_ext *ring_ext;
+	struct request_ext *ring_ext_ptr;
 	__le32	__iomem *req_q_in;	/* FWI2-capable only. */
 	__le32	__iomem *req_q_out;
 	uint16_t  ring_index;
diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
index eccedb38a515..4416197a35b0 100644
--- a/drivers/scsi/qla2xxx/qla_edif.c
+++ b/drivers/scsi/qla2xxx/qla_edif.c
@@ -2989,6 +2989,21 @@ qla28xx_start_scsi_edif(srb_t *sp)
 	struct req_que *req = sp->qpair->req;
 	spinlock_t *lock = sp->qpair->qp_lock_ptr;
 
+	/*
+	 * EDIF on 29xx is not supported by this driver yet.  The EDIF fast
+	 * path builds 64-byte cmd_type_6 IOCBs and advances req->ring_ptr
+	 * with a 64-byte stride, which would corrupt the 128-byte extended
+	 * request ring that 29xx hardware uses.  A proper 29xx EDIF port
+	 * requires a cmd_type_6_ext-shaped submission path; until that is
+	 * implemented, refuse the command rather than risk ring corruption.
+	 */
+	if (IS_QLA29XX(ha)) {
+		ql_log(ql_log_warn, vha, 0x13ae,
+		    "EDIF is not supported on 29xx hardware; failing cmd sp=%p.\n",
+		    sp);
+		return QLA_FUNCTION_FAILED;
+	}
+
 	/* Setup device pointers. */
 	cmd = GET_CMD_SP(sp);
 
@@ -3129,7 +3144,8 @@ qla28xx_start_scsi_edif(srb_t *sp)
 			 * Five DSDs are available in the Continuation
 			 * Type 1 IOCB.
 			 */
-			cont_pkt = qla2x00_prep_cont_type1_iocb(vha, req);
+			cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
+			    ha, req);
 			cur_dsd = cont_pkt->dsd;
 			avail_dsds = 5;
 		}
diff --git a/drivers/scsi/qla2xxx/qla_fw29.h b/drivers/scsi/qla2xxx/qla_fw29.h
index efe1c60bee81..088a220472a5 100644
--- a/drivers/scsi/qla2xxx/qla_fw29.h
+++ b/drivers/scsi/qla2xxx/qla_fw29.h
@@ -95,6 +95,17 @@ struct cmd_type_7_ext {
 	struct dsd64 dsd[NUM_CMD67_DSDS];	/* Data Segment Descriptors */
 };
 
+/*
+ * Inline data-DSD capacity of the 29xx cmd_type_crc_2_ext IOCB.  Unlike
+ * cmd_type_6_ext / cmd_type_7_ext (which carry NUM_CMD67_DSDS inline DSDs),
+ * CRC_2 places the bulk of its DSDs in the separate CRC-context DMA; only
+ * a single data_dsd is carried inline in both the u.nobundling and
+ * u.bundling variants.  Use this constant wherever the IOCB-reservation
+ * calculator needs the CRC_2 ext inline capacity so it stays in sync with
+ * the firmware-facing layout below.
+ */
+#define NUM_CRC2_EXT_INLINE_DSDS	1
+
 struct cmd_type_crc_2_ext {
 	uint8_t entry_type;		/* Entry type. */
 	uint8_t entry_count;		/* Entry count. */
@@ -683,4 +694,70 @@ struct vp_rpt_id_entry_24xx_ext {
 		} f2;
 	} u;
 };
+
+/*
+ * ISP queue - 64-Bit addressing, continuation entry structure definition
+ * for the 29xx extended (128-byte) IOCB ring.  Mirrors cont_a64_entry_t
+ * but carries 10 DSDs per entry instead of 5.
+ */
+#define NUM_CONT1_DSDS	10
+struct cont_a64_entry_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t reserved;
+	struct dsd64 dsd[NUM_CONT1_DSDS];
+};
+
+/*
+ * 29xx extended Command Type FC-NVMe IOCB (128 bytes).
+ *
+ * The header layout up through 'byte_count' (offset 48) is identical to the
+ * 64-byte struct cmd_nvme used by 24xx-class adapters, so common code can
+ * populate those fields via either type.  Fields beyond 'byte_count' diverge:
+ * 29xx adds control_flags_2/vp_index/first_burst_rx_id/io_tag/..., drops
+ * port_id[3]+vp_index(byte), and carries NUM_NVME_DSDS inline DSDs.
+ */
+#define NUM_NVME_DSDS	4
+struct cmd_nvme_ext {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+
+	uint32_t handle;		/* System handle. */
+	__le16	nport_handle;		/* N_PORT handle. */
+	__le16	timeout;		/* Command timeout. */
+
+	__le16	dseg_count;		/* Data segment count. */
+	__le16	nvme_rsp_dsd_len;	/* NVMe RSP DSD length */
+
+	uint64_t rsvd;
+
+	__le16	control_flags;		/* Control Flags (see struct cmd_nvme) */
+	__le16	nvme_cmnd_dseg_len;			/* Data segment length. */
+
+	__le64	 nvme_cmnd_dseg_address __packed;	/* Data segment address. */
+
+	__le64	 nvme_rsp_dseg_address __packed;	/* Data segment address. */
+
+	__le32	byte_count;		/* Total byte count. */
+
+	__le16	control_flags_2;
+	/*
+	 * vp_index layout matches the other 29xx extended IOCBs: only bits
+	 * [8:0] are meaningful (see CMD_EXT_VP_INDEX_MASK).
+	 */
+	__le16	vp_index;
+	__le32	first_burst_rx_id;
+	__le16	io_tag;
+	uint8_t vl_n_fctl;	/* VL(7:4) | RSVD(3:2) | F_CTL[17](1) | RSVD(0) */
+	uint8_t prtag_csctl;	/* Priority Tag or CS_CTL */
+	__le32	src_vm_id;	/* Source VM ID */
+	uint8_t reserved_2[16];
+
+	struct dsd64 nvme_dsd[NUM_NVME_DSDS];
+};
+
 #endif
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 84aaff130400..04f4cfadc510 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -297,7 +297,9 @@ void qla_adjust_buf(struct scsi_qla_host *);
 void qla_els_pt_iocb(struct scsi_qla_host *vha,
 	struct els_entry_24xx *pkt, struct qla_els_pt_arg *a);
 cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha,
-		struct req_que *que);
+		struct qla_hw_data *ha, struct req_que *que);
+struct cont_a64_entry_ext *qla2900_prep_cont_type1_iocb(scsi_qla_host_t *vha,
+		struct req_que *req);
 extern uint16_t qla2x00_calc_iocbs_32(uint16_t);
 extern uint16_t qla2x00_calc_iocbs_64(uint16_t);
 extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 123e8e7f40e1..292ffabcba99 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3852,9 +3852,13 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
 			 * Resizing must be done at end-of-dump processing.
 			 */
 			mq_size += (ha->max_req_queues - 1) *
-			    (req->length * sizeof(request_t));
+			    (req->length *
+			     (IS_QLA29XX(ha) ? sizeof(struct request_ext) :
+					       sizeof(request_t)));
 			mq_size += (ha->max_rsp_queues - 1) *
-			    (rsp->length * sizeof(response_t));
+			    (rsp->length *
+			     (IS_QLA29XX(ha) ? sizeof(struct response_ext) :
+					       sizeof(response_t)));
 		}
 		if (ha->tgt.atio_ring)
 			mq_size += ha->tgt.atio_q_length * sizeof(request_t);
@@ -3890,8 +3894,12 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
 		/* Add space for spare MPI fw dump. */
 		dump_size += ha->fwdt[1].dump_size;
 	} else {
-		req_q_size = req->length * sizeof(request_t);
-		rsp_q_size = rsp->length * sizeof(response_t);
+		req_q_size = req->length *
+		    (IS_QLA29XX(ha) ? sizeof(struct request_ext) :
+				      sizeof(request_t));
+		rsp_q_size = rsp->length *
+		    (IS_QLA29XX(ha) ? sizeof(struct response_ext) :
+				      sizeof(response_t));
 		dump_size = offsetof(struct qla2xxx_fw_dump, isp);
 		dump_size += fixed_size + mem_size + req_q_size + rsp_q_size
 			+ eft_size;
@@ -4478,15 +4486,33 @@ void
 qla2x00_init_response_q_entries(struct rsp_que *rsp)
 {
 	uint16_t cnt;
-	response_t *pkt;
 
 	rsp->ring_ptr = rsp->ring;
 	rsp->ring_index    = 0;
 	rsp->status_srb = NULL;
-	pkt = rsp->ring_ptr;
-	for (cnt = 0; cnt < rsp->length; cnt++) {
-		pkt->signature = RESPONSE_PROCESSED;
-		pkt++;
+
+	if (rsp->hw && IS_QLA29XX(rsp->hw)) {
+		/*
+		 * 29xx uses a 128-byte response-ring stride.  The signature
+		 * field offset matches response_t, but the entry pitch is
+		 * sizeof(struct response_ext); walk via ring_ext_ptr / struct response_ext.
+		 */
+		struct response_ext *pkt;
+
+		rsp->ring_ext_ptr = rsp->ring_ext;
+		pkt = rsp->ring_ext_ptr;
+		for (cnt = 0; cnt < rsp->length; cnt++) {
+			pkt->signature = RESPONSE_PROCESSED;
+			pkt++;
+		}
+	} else {
+		response_t *pkt;
+
+		pkt = rsp->ring_ptr;
+		for (cnt = 0; cnt < rsp->length; cnt++) {
+			pkt->signature = RESPONSE_PROCESSED;
+			pkt++;
+		}
 	}
 }
 
@@ -4807,7 +4833,12 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
 		req = ha->req_q_map[que];
 		if (!req || !test_bit(que, ha->req_qid_map))
 			continue;
-		req->out_ptr = (uint16_t *)(req->ring + req->length);
+		if (IS_QLA29XX(ha))
+			req->out_ptr =
+			    (uint16_t *)(req->ring_ext + req->length);
+		else
+			req->out_ptr =
+			    (uint16_t *)(req->ring + req->length);
 		*req->out_ptr = 0;
 		for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++)
 			req->outstanding_cmds[cnt] = NULL;
@@ -4818,13 +4849,19 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
 		req->ring_ptr  = req->ring;
 		req->ring_index    = 0;
 		req->cnt      = req->length;
+		if (IS_QLA29XX(ha))
+			req->ring_ext_ptr = req->ring_ext;
 	}
 
 	for (que = 0; que < ha->max_rsp_queues; que++) {
 		rsp = ha->rsp_q_map[que];
 		if (!rsp || !test_bit(que, ha->rsp_qid_map))
 			continue;
-		rsp->in_ptr = (uint16_t *)(rsp->ring + rsp->length);
+		if (IS_QLA29XX(ha))
+			rsp->in_ptr =
+			    (uint16_t *)(rsp->ring_ext + rsp->length);
+		else
+			rsp->in_ptr = (uint16_t *)(rsp->ring + rsp->length);
 		*rsp->in_ptr = 0;
 		/* Initialize response queue entries */
 		if (IS_QLAFX00(ha))
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 53eaff1e0f65..cdbc3c5abf75 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -54,6 +54,55 @@ qla2x00_debounce_register(volatile __le16 __iomem *addr)
 	return (first);
 }
 
+/**
+ * qla29xx_calc_iocbs() - Determine number of Command-Type and Continuation
+ * IOCBs to allocate for the 29xx extended (128-byte) IOCB ring.
+ * @vha: HA context
+ * @dsds: number of data segment descriptors needed
+ * @iocb_dsds: number of DSDs embedded in the first (command) IOCB.  The
+ *	remaining DSDs ride on Continuation Type 1 Ext IOCBs which hold
+ *	NUM_CONT1_DSDS (10) each.
+ *
+ * Returns the total number of IOCB entries needed to carry @dsds.
+ */
+static inline uint16_t
+qla29xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds, uint8_t iocb_dsds)
+{
+	uint16_t iocbs = 1;
+
+	if (dsds > iocb_dsds) {
+		iocbs += (dsds - iocb_dsds) / NUM_CONT1_DSDS;
+		if ((dsds - iocb_dsds) % NUM_CONT1_DSDS)
+			iocbs++;
+	}
+	return iocbs;
+}
+
+/**
+ * qla_req_entry_size() - request-ring entry stride.
+ * @ha: HBA pointer
+ *
+ * Returns sizeof(struct request_ext) (128) on 29xx, sizeof(request_t) (64)
+ * everywhere else.
+ */
+static inline size_t
+qla_req_entry_size(struct qla_hw_data *ha)
+{
+	return IS_QLA29XX(ha) ? sizeof(struct request_ext) : sizeof(request_t);
+}
+
+/**
+ * qla_rsp_entry_size() - response-ring entry stride.
+ * @ha: HBA pointer
+ *
+ * Counterpart of qla_req_entry_size() for the response ring.
+ */
+static inline size_t
+qla_rsp_entry_size(struct qla_hw_data *ha)
+{
+	return IS_QLA29XX(ha) ? sizeof(struct response_ext) : sizeof(response_t);
+}
+
 static inline void
 qla2x00_poll(struct rsp_que *rsp)
 {
@@ -358,17 +407,132 @@ static inline void
 qla_83xx_start_iocbs(struct qla_qpair *qpair)
 {
 	struct req_que *req = qpair->req;
+	struct qla_hw_data *ha = qpair->vha->hw;
 
+	/*
+	 * 29xx uses the 128-byte-strided extended request ring; advance the
+	 * matching ring_ext_ptr so the next IOCB allocator sees the correct
+	 * slot.  All other 83xx-family generations (83xx/27xx/28xx) keep the
+	 * 64-byte ring_ptr.
+	 */
 	req->ring_index++;
-	if (req->ring_index == req->length) {
-		req->ring_index = 0;
-		req->ring_ptr = req->ring;
-	} else
-		req->ring_ptr++;
+	if (IS_QLA29XX(ha)) {
+		if (req->ring_index == req->length) {
+			req->ring_index = 0;
+			req->ring_ext_ptr = req->ring_ext;
+		} else {
+			req->ring_ext_ptr++;
+		}
+	} else {
+		if (req->ring_index == req->length) {
+			req->ring_index = 0;
+			req->ring_ptr = req->ring;
+		} else {
+			req->ring_ptr++;
+		}
+	}
 
 	wrt_reg_dword(req->req_q_in, req->ring_index);
 }
 
+/**
+ * qla_rsp_ring_advance() - Advance the response queue consumer pointer
+ * to the next IOCB slot, handling both 24xx (64-byte) and 29xx (128-byte)
+ * ring strides.
+ *
+ * On 29xx, ring_ext_ptr is the authoritative slot pointer (correct 128-byte
+ * pitch) and ring_ptr is kept in sync as a response_t view of the same slot
+ * so existing 24xx-shaped reads (rsp->ring_ptr->signature,
+ * (struct sts_entry_24xx *)rsp->ring_ptr, etc.) keep working unchanged; the
+ * first 64 bytes of struct response_ext are layout-compatible with response_t.
+ */
+static inline void
+qla_rsp_ring_advance(struct rsp_que *rsp)
+{
+	rsp->ring_index++;
+	if (rsp->ring_index == rsp->length) {
+		rsp->ring_index = 0;
+		rsp->ring_ptr = rsp->ring;
+		if (rsp->hw && IS_QLA29XX(rsp->hw))
+			rsp->ring_ext_ptr = rsp->ring_ext;
+	} else if (rsp->hw && IS_QLA29XX(rsp->hw)) {
+		rsp->ring_ext_ptr++;
+		rsp->ring_ptr = (response_t *)rsp->ring_ext_ptr;
+	} else {
+		rsp->ring_ptr++;
+	}
+}
+
+/**
+ * qla_req_ring_slot() - return the current request-ring producer slot.
+ * @ha: HBA pointer
+ * @req: request queue
+ *
+ * On 29xx the firmware-visible ring uses 128-byte-strided entries
+ * referenced by ring_ext_ptr; on earlier adapters the 64-byte ring
+ * referenced by ring_ptr is used.  The returned pointer is
+ * layout-compatible with request_t for common header writes; callers
+ * needing 29xx-specific fields should cast to struct request_ext.
+ */
+static inline void *
+qla_req_ring_slot(struct qla_hw_data *ha, struct req_que *req)
+{
+	return IS_QLA29XX(ha) ? (void *)req->ring_ext_ptr
+			      : (void *)req->ring_ptr;
+}
+
+/**
+ * qla_req_ring_advance() - advance request-ring producer pointer.
+ * @ha: HBA pointer
+ * @req: request queue
+ *
+ * Mirrors qla_rsp_ring_advance().  Does NOT publish the new producer
+ * index to firmware; callers that need to do so should follow with a
+ * wrt_reg_dword or qla_83xx_start_iocbs().
+ */
+static inline void
+qla_req_ring_advance(struct qla_hw_data *ha, struct req_que *req)
+{
+	req->ring_index++;
+	if (IS_QLA29XX(ha)) {
+		if (req->ring_index == req->length) {
+			req->ring_index = 0;
+			req->ring_ext_ptr = req->ring_ext;
+		} else {
+			req->ring_ext_ptr++;
+		}
+	} else {
+		if (req->ring_index == req->length) {
+			req->ring_index = 0;
+			req->ring_ptr = req->ring;
+		} else {
+			req->ring_ptr++;
+		}
+	}
+}
+
+/**
+ * qla_rsp_ring_rewind_to() - Restore the response queue consumer pointer
+ * to a previously-observed slot (used when we need to defer processing an
+ * IOCB whose continuation entries have not yet arrived).
+ * @rsp: response queue
+ * @pkt: 64-byte view of the slot to rewind to (captured from a prior read
+ *       of rsp->ring_ptr)
+ * @idx: matching ring_index value (also captured before the advance)
+ *
+ * On 29xx, pkt was originally obtained as (response_t *)rsp->ring_ext_ptr,
+ * so casting back to struct response_ext * recovers the 128-byte-stride slot
+ * pointer.
+ */
+static inline void
+qla_rsp_ring_rewind_to(struct rsp_que *rsp, response_t *pkt, uint16_t idx)
+{
+	rsp->ring_ptr = pkt;
+	rsp->ring_index = idx;
+	if (rsp->hw && IS_QLA29XX(rsp->hw))
+		rsp->ring_ext_ptr = (struct response_ext *)pkt;
+}
+
 static inline int
 qla2xxx_get_fc4_priority(struct scsi_qla_host *vha)
 {
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 9038f6723444..6b8be182cdb8 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -12,6 +12,19 @@
 #include <scsi/scsi_tcq.h>
 
 static int qla_start_scsi_type6(srb_t *sp);
+
+/*
+ * 29xx extended IOCB builders, implemented later in this file.  Forward
+ * declared here because the unified 24xx/29xx fast paths dispatch to them
+ * via IS_QLA29XX() branches.
+ */
+static void qla29xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_ext *cmd_pkt,
+	uint16_t tot_dsds, struct req_que *req);
+static void qla29xx_build_scsi_type_6_iocbs(srb_t *sp,
+	struct cmd_type_6_ext *cmd_pkt, uint16_t tot_dsds);
+static int qla29xx_build_scsi_crc_2_iocbs(srb_t *sp,
+	struct cmd_type_crc_2_ext *cmd_pkt, uint16_t tot_dsds,
+	uint16_t tot_prot_dsds, uint16_t fw_prot_opts, uint8_t dif_bundling);
 /**
  * qla2x00_get_cmd_direction() - Determine control_flag data direction.
  * @sp: SCSI command
@@ -120,20 +133,15 @@ qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha)
  * Returns a pointer to the continuation type 1 IOCB packet.
  */
 cont_a64_entry_t *
-qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req)
+qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct qla_hw_data *ha,
+			      struct req_que *req)
 {
 	cont_a64_entry_t *cont_pkt;
 
 	/* Adjust ring index. */
-	req->ring_index++;
-	if (req->ring_index == req->length) {
-		req->ring_index = 0;
-		req->ring_ptr = req->ring;
-	} else {
-		req->ring_ptr++;
-	}
+	qla_req_ring_advance(ha, req);
 
-	cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
+	cont_pkt = (cont_a64_entry_t *)qla_req_ring_slot(ha, req);
 
 	/* Load packet defaults. */
 	put_unaligned_le32(IS_QLAFX00(vha->hw) ? CONTINUE_A64_TYPE_FX00 :
@@ -284,7 +292,8 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
 			 * Five DSDs are available in the Continuation
 			 * Type 1 IOCB.
 			 */
-			cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req);
+			cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
+			    vha->hw, vha->req);
 			cur_dsd = cont_pkt->dsd;
 			avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
 		}
@@ -464,13 +473,12 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
 	if (IS_P3P_TYPE(ha)) {
 		qla82xx_start_iocbs(vha);
 	} else {
-		/* Adjust ring index. */
-		req->ring_index++;
-		if (req->ring_index == req->length) {
-			req->ring_index = 0;
-			req->ring_ptr = req->ring;
-		} else
-			req->ring_ptr++;
+		/*
+		 * Adjust ring index.  29xx uses a 128-byte-strided ring, so
+		 * advance the extended pointer; all other generations advance
+		 * the 64-byte ring_ptr.
+		 */
+		qla_req_ring_advance(ha, req);
 
 		/* Set chip new ring index. */
 		if (ha->mqenable || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
@@ -523,6 +531,29 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair,
 		return (QLA_FUNCTION_FAILED);
 	}
 
+	/*
+	 * 29xx uses the extended marker IOCB (128 bytes) with a __le16
+	 * vp_index field.  The first 64 bytes of mrk_entry_24xx_ext are
+	 * layout-compatible with mrk_entry_24xx except for the vp_index
+	 * storage, which differs in width and offset, so handle it via
+	 * a dedicated branch.
+	 */
+	if (IS_QLA29XX(ha)) {
+		struct mrk_entry_24xx_ext *mrk29 =
+			(struct mrk_entry_24xx_ext *)mrk;
+
+		mrk29->entry_type = MARKER_TYPE;
+		mrk29->modifier = type;
+		if (type != MK_SYNC_ALL) {
+			mrk29->nport_handle = cpu_to_le16(loop_id);
+			int_to_scsilun(lun, (struct scsi_lun *)&mrk29->lun);
+			host_to_fcp_swap(mrk29->lun, sizeof(mrk29->lun));
+			mrk29->vp_index = cpu_to_le16(vha->vp_idx);
+		}
+		mrk29->handle = QLA_SKIP_HANDLE;
+		goto post;
+	}
+
 	mrk24 = (struct mrk_entry_24xx *)mrk;
 
 	mrk->entry_type = MARKER_TYPE;
@@ -542,6 +573,8 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair,
 	if (IS_FWI2_CAPABLE(ha))
 		mrk24->handle = QLA_SKIP_HANDLE;
 
+post:
+
 	wmb();
 
 	qla2x00_start_iocbs(vha, req);
@@ -747,7 +780,8 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
 			 * Five DSDs are available in the Continuation
 			 * Type 1 IOCB.
 			 */
-			cont_pkt = qla2x00_prep_cont_type1_iocb(vha, req);
+			cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
+			    vha->hw, req);
 			cur_dsd = cont_pkt->dsd;
 			avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
 		}
@@ -1620,7 +1654,7 @@ qla24xx_start_scsi(srb_t *sp)
 	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
 	req->cnt -= req_cnt;
 
-	cmd_pkt = (struct cmd_type_7 *)req->ring_ptr;
+	cmd_pkt = (struct cmd_type_7 *)qla_req_ring_slot(ha, req);
 	cmd_pkt->handle = make_handle(req->id, handle);
 
 	/* Zero out remaining portion of packet. */
@@ -1654,12 +1688,7 @@ qla24xx_start_scsi(srb_t *sp)
 	cmd_pkt->entry_count = (uint8_t)req_cnt;
 	wmb();
 	/* Adjust ring index. */
-	req->ring_index++;
-	if (req->ring_index == req->length) {
-		req->ring_index = 0;
-		req->ring_ptr = req->ring;
-	} else
-		req->ring_ptr++;
+	qla_req_ring_advance(ha, req);
 
 	sp->qpair->cmd_cnt++;
 	sp->flags |= SRB_DMA_VALID;
@@ -1829,7 +1858,7 @@ qla24xx_dif_start_scsi(srb_t *sp)
 	req->cnt -= req_cnt;
 
 	/* Fill-in common area */
-	cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr;
+	cmd_pkt = (struct cmd_type_crc_2 *)qla_req_ring_slot(ha, req);
 	cmd_pkt->handle = make_handle(req->id, handle);
 
 	clr_ptr = (uint32_t *)cmd_pkt + 2;
@@ -1849,8 +1878,8 @@ qla24xx_dif_start_scsi(srb_t *sp)
 
 	/* Build IOCB segments and adjust for data protection segments */
 	if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *)
-	    req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) !=
-		QLA_SUCCESS)
+	    qla_req_ring_slot(ha, req), tot_dsds, tot_prot_dsds,
+	    fw_prot_opts) != QLA_SUCCESS)
 		goto queuing_error;
 
 	cmd_pkt->entry_count = (uint8_t)req_cnt;
@@ -1860,12 +1889,7 @@ qla24xx_dif_start_scsi(srb_t *sp)
 	wmb();
 
 	/* Adjust ring index. */
-	req->ring_index++;
-	if (req->ring_index == req->length) {
-		req->ring_index = 0;
-		req->ring_ptr = req->ring;
-	} else
-		req->ring_ptr++;
+	qla_req_ring_advance(ha, req);
 
 	sp->qpair->cmd_cnt++;
 	/* Set chip new ring index. */
@@ -1954,7 +1978,17 @@ qla2xxx_start_scsi_mq(srb_t *sp)
 		nseg = 0;
 
 	tot_dsds = nseg;
-	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
+	/*
+	 * 29xx posts into the 128-byte extended IOCB ring (cmd_type_7_ext,
+	 * NUM_CMD67_DSDS inline DSDs) via ring_ext_ptr; all other FWI2-capable
+	 * generations use the 64-byte cmd_type_7 / ring_ptr path.  The common
+	 * skeleton (marker/handle/sg-map/resource-check/ring advance) is
+	 * shared; only the cmd_pkt field-writes and ring stride differ.
+	 */
+	if (IS_QLA29XX(ha))
+		req_cnt = qla29xx_calc_iocbs(vha, tot_dsds, NUM_CMD67_DSDS);
+	else
+		req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
 
 	sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
 	sp->iores.exch_cnt = 1;
@@ -1987,46 +2021,84 @@ qla2xxx_start_scsi_mq(srb_t *sp)
 	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
 	req->cnt -= req_cnt;
 
-	cmd_pkt = (struct cmd_type_7 *)req->ring_ptr;
-	cmd_pkt->handle = make_handle(req->id, handle);
+	if (IS_QLA29XX(ha)) {
+		/*
+		 * cmd_type_7_ext diverges from cmd_type_7 past offset 48
+		 * (port_id[3]+vp_index vs ctrl_flags_2+__le16 vp_index),
+		 * so the packet-field writes can't be shared via a common
+		 * pointer type.
+		 */
+		struct cmd_type_7_ext *cmd_pkt_ext =
+			(struct cmd_type_7_ext *)req->ring_ext_ptr;
 
-	/* Zero out remaining portion of packet. */
-	/*    tagged queuing modifier -- default is TSK_SIMPLE (0). */
-	clr_ptr = (uint32_t *)cmd_pkt + 2;
-	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
-	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
+		cmd_pkt_ext->handle = make_handle(req->id, handle);
 
-	/* Set NPORT-ID and LUN number*/
-	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
-	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
-	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
-	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
-	cmd_pkt->vp_index = sp->fcport->vha->vp_idx;
+		/* Zero out remaining portion of packet. */
+		/*    tagged queuing modifier -- default is TSK_SIMPLE (0). */
+		clr_ptr = (uint32_t *)cmd_pkt_ext + 2;
+		memset(clr_ptr, 0, REQUEST_ENTRY_SIZE_EXT - 8);
+		cmd_pkt_ext->dseg_count = cpu_to_le16(tot_dsds);
 
-	int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
-	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
+		/* Set NPORT-ID and LUN number. */
+		cmd_pkt_ext->nport_handle =
+			cpu_to_le16(sp->fcport->loop_id);
+		cmd_pkt_ext->vp_index =
+			cpu_to_le16(sp->fcport->vha->vp_idx);
 
-	cmd_pkt->task = TSK_SIMPLE;
+		int_to_scsilun(cmd->device->lun, &cmd_pkt_ext->lun);
+		host_to_fcp_swap((uint8_t *)&cmd_pkt_ext->lun,
+				sizeof(cmd_pkt_ext->lun));
 
-	/* Load SCSI command packet. */
-	memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
-	host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));
+		cmd_pkt_ext->task = TSK_SIMPLE;
 
-	cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
+		memcpy(cmd_pkt_ext->fcp_cdb, cmd->cmnd, cmd->cmd_len);
+		host_to_fcp_swap(cmd_pkt_ext->fcp_cdb,
+				sizeof(cmd_pkt_ext->fcp_cdb));
 
-	/* Build IOCB segments */
-	qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req);
+		cmd_pkt_ext->byte_count =
+			cpu_to_le32((uint32_t)scsi_bufflen(cmd));
+
+		qla29xx_build_scsi_iocbs(sp, cmd_pkt_ext, tot_dsds, req);
+
+		cmd_pkt_ext->entry_count = (uint8_t)req_cnt;
+	} else {
+		cmd_pkt = (struct cmd_type_7 *)req->ring_ptr;
+		cmd_pkt->handle = make_handle(req->id, handle);
+
+		/* Zero out remaining portion of packet. */
+		/*    tagged queuing modifier -- default is TSK_SIMPLE (0). */
+		clr_ptr = (uint32_t *)cmd_pkt + 2;
+		memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
+		cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
+
+		/* Set NPORT-ID and LUN number. */
+		cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+		cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
+		cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
+		cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
+		cmd_pkt->vp_index = sp->fcport->vha->vp_idx;
+
+		int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
+		host_to_fcp_swap((uint8_t *)&cmd_pkt->lun,
+				sizeof(cmd_pkt->lun));
+
+		cmd_pkt->task = TSK_SIMPLE;
+
+		memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
+		host_to_fcp_swap(cmd_pkt->fcp_cdb,
+				sizeof(cmd_pkt->fcp_cdb));
+
+		cmd_pkt->byte_count =
+			cpu_to_le32((uint32_t)scsi_bufflen(cmd));
+
+		qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req);
+
+		cmd_pkt->entry_count = (uint8_t)req_cnt;
+	}
 
-	/* Set total data segment count. */
-	cmd_pkt->entry_count = (uint8_t)req_cnt;
 	wmb();
 	/* Adjust ring index. */
-	req->ring_index++;
-	if (req->ring_index == req->length) {
-		req->ring_index = 0;
-		req->ring_ptr = req->ring;
-	} else
-		req->ring_ptr++;
+	qla_req_ring_advance(ha, req);
 
 	sp->qpair->cmd_cnt++;
 	sp->flags |= SRB_DMA_VALID;
@@ -2034,8 +2106,12 @@ qla2xxx_start_scsi_mq(srb_t *sp)
 	/* Set chip new ring index. */
 	wrt_reg_dword(req->req_q_in, req->ring_index);
 
-	/* Manage unprocessed RIO/ZIO commands in response queue. */
-	if (vha->flags.process_response_queue &&
+	/*
+	 * Manage unprocessed RIO/ZIO commands in response queue. 29xx skips
+	 * this optimization until rsp_que is made 128-byte-stride aware;
+	 * completions still arrive via the regular ISR path.
+	 */
+	if (!IS_QLA29XX(ha) && vha->flags.process_response_queue &&
 	    rsp->ring_ptr->signature != RESPONSE_PROCESSED)
 		qla24xx_process_response_queue(vha, rsp);
 
@@ -2180,7 +2256,20 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp)
 
 	sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
 	sp->iores.exch_cnt = 1;
-	sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
+	/*
+	 * Unlike cmd_type_6_ext / cmd_type_7_ext (which carry NUM_CMD67_DSDS
+	 * inline DSDs), cmd_type_crc_2_ext carries only a single inline
+	 * data_dsd; the remaining DSDs live in the separate CRC-context DMA.
+	 * Size the firmware IOCB-pool reservation against the CRC_2 ext inline
+	 * capacity (NUM_CRC2_EXT_INLINE_DSDS) so it mirrors the 24xx path
+	 * (qla24xx_calc_iocbs assumes 1 inline DSD for cmd_type_crc_2) and
+	 * doesn't under-count continuations expected by firmware.
+	 */
+	if (IS_QLA29XX(ha))
+		sp->iores.iocb_cnt = qla29xx_calc_iocbs(vha, tot_dsds,
+						       NUM_CRC2_EXT_INLINE_DSDS);
+	else
+		sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
 	if (qla_get_fw_resources(sp->qpair, &sp->iores))
 		goto queuing_error;
 
@@ -2211,18 +2300,35 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp)
 	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
 	req->cnt -= req_cnt;
 
-	/* Fill-in common area */
-	cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr;
+	/*
+	 * cmd_type_crc_2 and cmd_type_crc_2_ext share an identical header
+	 * layout through byte_count (offset 44); the trailing port_id /
+	 * vp_index / CRC-context fields diverge.  The common header writes
+	 * (handle, memset, nport_handle, lun, dseg_count, entry_count,
+	 * timeout) are performed via the 24xx-typed pointer in both paths;
+	 * the divergent tail and builder use hardware-specific handling.
+	 */
+	if (IS_QLA29XX(ha))
+		cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ext_ptr;
+	else
+		cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr;
 	cmd_pkt->handle = make_handle(req->id, handle);
 
 	clr_ptr = (uint32_t *)cmd_pkt + 2;
-	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
+	memset(clr_ptr, 0, qla_req_entry_size(ha) - 8);
 
 	/* Set NPORT-ID and LUN number*/
 	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
-	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
-	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
-	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
+	if (!IS_QLA29XX(ha)) {
+		cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
+		cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
+		cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
+	}
+	/*
+	 * vp_index: 24xx uses a uint8_t field at offset 51 (in port_id
+	 * group); 29xx replaces that region with control_flags_2/vp_index as
+	 * __le16s starting at offset 48.
+	 */
 
 	int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
 	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
@@ -2231,29 +2337,41 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp)
 	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
 
 	/* Build IOCB segments and adjust for data protection segments */
-	if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *)
-	    req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) !=
-		QLA_SUCCESS)
-		goto queuing_error;
+	if (IS_QLA29XX(ha)) {
+		struct cmd_type_crc_2_ext *cmd_pkt_ext =
+			(struct cmd_type_crc_2_ext *)cmd_pkt;
+
+		cmd_pkt_ext->vp_index = cpu_to_le16(sp->vha->vp_idx);
+
+		if (qla29xx_build_scsi_crc_2_iocbs(sp, cmd_pkt_ext, tot_dsds,
+						   tot_prot_dsds,
+						   fw_prot_opts, 0) !=
+		    QLA_SUCCESS)
+			goto queuing_error;
+	} else {
+		if (qla24xx_build_scsi_crc_2_iocbs(sp, cmd_pkt, tot_dsds,
+						   tot_prot_dsds,
+						   fw_prot_opts) !=
+		    QLA_SUCCESS)
+			goto queuing_error;
+	}
 
 	cmd_pkt->entry_count = (uint8_t)req_cnt;
 	cmd_pkt->timeout = cpu_to_le16(0);
 	wmb();
 
-	/* Adjust ring index. */
-	req->ring_index++;
-	if (req->ring_index == req->length) {
-		req->ring_index = 0;
-		req->ring_ptr = req->ring;
-	} else
-		req->ring_ptr++;
+	/* Adjust ring index.  29xx uses the 128-byte extended ring pointer. */
+	qla_req_ring_advance(ha, req);
 
 	sp->qpair->cmd_cnt++;
 	/* Set chip new ring index. */
 	wrt_reg_dword(req->req_q_in, req->ring_index);
 
-	/* Manage unprocessed RIO/ZIO commands in response queue. */
-	if (vha->flags.process_response_queue &&
+	/*
+	 * Manage unprocessed RIO/ZIO commands in response queue. 29xx skips
+	 * this optimization until rsp_que is made 128-byte-stride aware.
+	 */
+	if (!IS_QLA29XX(ha) && vha->flags.process_response_queue &&
 	    rsp->ring_ptr->signature != RESPONSE_PROCESSED)
 		qla24xx_process_response_queue(vha, rsp);
 
@@ -2343,10 +2461,20 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp)
 		sp->handle = handle;
 	}
 
-	/* Prep packet */
+	/*
+	 * Prep packet.  29xx posts into a 128-byte-strided ring via
+	 * ring_ext_ptr; the first 8 bytes of struct request_ext overlay the
+	 * common request_t header, so entry_count/handle writes are
+	 * layout-compatible once we return the pkt as request_t *.
+	 */
 	req->cnt -= req_cnt;
-	pkt = req->ring_ptr;
-	memset(pkt, 0, REQUEST_ENTRY_SIZE);
+	if (IS_QLA29XX(ha)) {
+		pkt = (request_t *)req->ring_ext_ptr;
+		memset(pkt, 0, REQUEST_ENTRY_SIZE_EXT);
+	} else {
+		pkt = req->ring_ptr;
+		memset(pkt, 0, REQUEST_ENTRY_SIZE);
+	}
 	if (IS_QLAFX00(ha)) {
 		wrt_reg_byte((u8 __force __iomem *)&pkt->entry_count, req_cnt);
 		wrt_reg_dword((__le32 __force __iomem *)&pkt->handle, handle);
@@ -3271,7 +3399,7 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb)
 			* Type 1 IOCB.
 			       */
 			cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
-			    vha->hw->req_q_map[0]);
+			    ha, ha->req_q_map[0]);
 			cur_dsd = cont_pkt->dsd;
 			avail_dsds = 5;
 			entry_count++;
@@ -3297,7 +3425,6 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
 	struct qla_hw_data *ha = vha->hw;
 	struct bsg_job *bsg_job = sp->u.bsg_job;
 	int entry_count = 1;
-	cont_a64_entry_t *cont_pkt = NULL;
 
 	ct_iocb->entry_type = CT_IOCB_TYPE;
         ct_iocb->entry_status = 0;
@@ -3322,16 +3449,29 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
 	index = 0;
 
 	for_each_sg(bsg_job->request_payload.sg_list, sg, cmd_dsds, index) {
-		/* Allocate additional continuation packets? */
+		/*
+		 * Allocate additional continuation packets.  24xx uses the
+		 * 64-byte cont_a64_entry_t (5 DSDs); 29xx uses the 128-byte
+		 * cont_a64_entry_ext_t (NUM_CONT1_DSDS) and advances through
+		 * the ring_ext_ptr stride so the CT head IOCB isn't
+		 * overlapped.
+		 */
 		if (avail_dsds == 0) {
-			/*
-			 * Five DSDs are available in the Cont.
-			 * Type 1 IOCB.
-			 */
-			cont_pkt = qla2x00_prep_cont_type1_iocb(
-			    vha, ha->req_q_map[0]);
-			cur_dsd = cont_pkt->dsd;
-			avail_dsds = 5;
+			if (IS_QLA29XX(ha)) {
+				struct cont_a64_entry_ext *cont_pkt;
+
+				cont_pkt = qla2900_prep_cont_type1_iocb(vha,
+				    ha->req_q_map[0]);
+				cur_dsd = cont_pkt->dsd;
+				avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
+			} else {
+				cont_a64_entry_t *cont_pkt;
+
+				cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
+				    ha, ha->req_q_map[0]);
+				cur_dsd = cont_pkt->dsd;
+				avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
+			}
 			entry_count++;
 		}
 
@@ -3342,16 +3482,22 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
 	index = 0;
 
 	for_each_sg(bsg_job->reply_payload.sg_list, sg, rsp_dsds, index) {
-		/* Allocate additional continuation packets? */
 		if (avail_dsds == 0) {
-			/*
-			* Five DSDs are available in the Cont.
-			* Type 1 IOCB.
-			       */
-			cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
-			    ha->req_q_map[0]);
-			cur_dsd = cont_pkt->dsd;
-			avail_dsds = 5;
+			if (IS_QLA29XX(ha)) {
+				struct cont_a64_entry_ext *cont_pkt;
+
+				cont_pkt = qla2900_prep_cont_type1_iocb(vha,
+				    ha->req_q_map[0]);
+				cur_dsd = cont_pkt->dsd;
+				avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
+			} else {
+				cont_a64_entry_t *cont_pkt;
+
+				cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
+				    ha, ha->req_q_map[0]);
+				cur_dsd = cont_pkt->dsd;
+				avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
+			}
 			entry_count++;
 		}
 
@@ -4100,7 +4246,8 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha,
 			/* Continuation type 1 IOCB can accomodate
 			 * 5 DSDS
 			 */
-			cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req);
+			cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
+			    vha->hw, vha->req);
 			cur_dsd = cont_pkt->dsd;
 			avail_dsds = 5;
 			entry_count++;
@@ -4122,7 +4269,8 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha,
 			/* Continuation type 1 IOCB can accomodate
 			 * 5 DSDS
 			 */
-			cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req);
+			cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
+			    vha->hw, vha->req);
 			cur_dsd = cont_pkt->dsd;
 			avail_dsds = 5;
 			entry_count++;
@@ -4154,6 +4302,21 @@ qla2x00_start_bidir(srb_t *sp, struct scsi_qla_host *vha, uint32_t tot_dsds)
 	rsp = ha->rsp_q_map[0];
 	req = vha->req;
 
+	/*
+	 * 29xx uses a 128-byte extended IOCB ring, but no extended
+	 * COMMAND_BIDIRECTIONAL IOCB layout has been defined and no
+	 * firmware-spec'd cmd_bidir_ext exists.  Posting the 64-byte
+	 * struct cmd_bidir against req->ring_ptr would overlap the next
+	 * ring slot on 29xx HW (see BUILD_BUG_ON(sizeof(struct cmd_bidir)
+	 * != 64) in qla_os.c), so refuse BSG BIDIR on 29xx rather than
+	 * corrupt the request ring.
+	 */
+	if (IS_QLA29XX(ha)) {
+		ql_log(ql_log_warn, vha, 0x70af,
+		    "BSG BIDIR not supported on 29xx adapters.\n");
+		return EXT_STATUS_INVALID_PARAM;
+	}
+
 	/* Send marker if required */
 	if (vha->marker_needed != 0) {
 		if (qla2x00_marker(vha, ha->base_qpair,
@@ -4291,8 +4454,15 @@ qla_start_scsi_type6(srb_t *sp)
 
 	tot_dsds = nseg;
 
-	/* eventhough driver only need 1 T6 IOCB, FW still convert DSD to Continueation IOCB */
-	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
+	/*
+	 * Even though the driver only needs 1 T6 IOCB, FW still converts the
+	 * DSD list into continuation IOCBs for reservation purposes.  29xx
+	 * follows the same rule against its extended-IOCB inline DSD count.
+	 */
+	if (IS_QLA29XX(ha))
+		req_cnt = qla29xx_calc_iocbs(vha, tot_dsds, NUM_CMD67_DSDS);
+	else
+		req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
 
 	sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
 	sp->iores.exch_cnt = 1;
@@ -4396,23 +4566,44 @@ qla_start_scsi_type6(srb_t *sp)
 	cmd->host_scribble = (unsigned char *)(unsigned long)handle;
 	req->cnt -= req_cnt;
 
-	cmd_pkt = (struct cmd_type_6 *)req->ring_ptr;
+	/*
+	 * cmd_type_6 and cmd_type_6_ext share an identical header layout
+	 * from offset 0 through byte_count (offset 48), so the common
+	 * header/nport/lun writes go through the 24xx-typed cmd_pkt even on
+	 * 29xx.  Only the divergent port_id/vp_index tail and the DSD layout
+	 * need hardware-specific handling.
+	 */
+	if (IS_QLA29XX(ha))
+		cmd_pkt = (struct cmd_type_6 *)req->ring_ext_ptr;
+	else
+		cmd_pkt = (struct cmd_type_6 *)req->ring_ptr;
 	cmd_pkt->handle = make_handle(req->id, handle);
 
 	/* tagged queuing modifier -- default is TSK_SIMPLE (0). */
 	clr_ptr = (uint32_t *)cmd_pkt + 2;
-	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
+	memset(clr_ptr, 0, qla_req_entry_size(ha) - 8);
 	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
 
 	/* Set NPORT-ID and LUN number */
 	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
-	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
-	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
-	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
-	cmd_pkt->vp_index = sp->vha->vp_idx;
 
-	/* Build IOCB segments */
-	qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds);
+	if (IS_QLA29XX(ha)) {
+		struct cmd_type_6_ext *cmd_pkt_ext =
+			(struct cmd_type_6_ext *)cmd_pkt;
+
+		cmd_pkt_ext->vp_index = cpu_to_le16(sp->vha->vp_idx);
+
+		/* Build IOCB segments (dsd[] in 29xx extended layout). */
+		qla29xx_build_scsi_type_6_iocbs(sp, cmd_pkt_ext, tot_dsds);
+	} else {
+		cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
+		cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
+		cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
+		cmd_pkt->vp_index = sp->vha->vp_idx;
+
+		/* Build IOCB segments (24xx fcp_dsd single-DSD layout). */
+		qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds);
+	}
 
 	int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
 	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
@@ -4447,14 +4638,8 @@ qla_start_scsi_type6(srb_t *sp)
 	cmd_pkt->entry_count = (uint8_t)req_cnt;
 
 	wmb();
-	/* Adjust ring index. */
-	req->ring_index++;
-	if (req->ring_index == req->length) {
-		req->ring_index = 0;
-		req->ring_ptr = req->ring;
-	} else {
-		req->ring_ptr++;
-	}
+	/* Adjust ring index. 29xx uses the 128-byte extended ring pointer.*/
+	qla_req_ring_advance(ha, req);
 
 	sp->qpair->cmd_cnt++;
 	sp->flags |= SRB_DMA_VALID;
@@ -4462,8 +4647,11 @@ qla_start_scsi_type6(srb_t *sp)
 	/* Set chip new ring index. */
 	wrt_reg_dword(req->req_q_in, req->ring_index);
 
-	/* Manage unprocessed RIO/ZIO commands in response queue. */
-	if (vha->flags.process_response_queue &&
+	/*
+	 * Manage unprocessed RIO/ZIO commands in response queue. 29xx skips
+	 * this optimization until rsp_que is made 128-byte-stride aware.
+	 */
+	if (!IS_QLA29XX(ha) &&  vha->flags.process_response_queue &&
 	    rsp->ring_ptr->signature != RESPONSE_PROCESSED)
 		qla24xx_process_response_queue(vha, rsp);
 
@@ -4489,3 +4677,491 @@ qla_start_scsi_type6(srb_t *sp)
 
 	return QLA_FUNCTION_FAILED;
 }
+
+/*
+ * ---------------------------------------------------------------------------
+ * 29xx extended (128-byte) IOCB fast-path helpers.
+ *
+ * These helpers drive the extended IOCB ring used by 29xx-class adapters and
+ * operate on the *_ext IOCB variants declared in qla_fw29.h
+ * (cmd_type_6_ext, cmd_type_7_ext, cmd_type_crc_2_ext, struct cont_a64_entry_ext).
+ *
+ * They are not yet wired into any dispatch path; the top-level entry points
+ * (e.g. qla29xx_start_scsi / qla29xx_dif_start_scsi_mq) and isp_ops hooks are
+ * added in subsequent merge phases.  Until then the top-of-tree builder
+ * functions are marked __maybe_unused so the build stays warning-clean.
+ *
+ * Ported from the out-of-tree qla29xx driver.  Signatures have been adapted
+ * to the Mach qla2xxx single-srb_t model:
+ *   struct qla_io_srb *  -->  srb_t *
+ *   sp->qcb.qpair        -->  sp->qpair
+ *   sp->qcb.iores        -->  sp->iores
+ *   sp->qcb.handle       -->  sp->handle
+ *   qla2900_hba_err_chk_enabled()  -->  qla2x00_hba_err_chk_enabled()
+ * ---------------------------------------------------------------------------
+ */
+
+static void qla29xx_copy_dif_iocb_data(struct cmd_type_crc_2_ext *cmd_pkt,
+	struct crc_context *crc_ctx_pkt, uint8_t dif_bundling);
+
+/**
+ * qla2900_prep_cont_type1_iocb() - Initialize a 29xx-ext Continuation
+ * Type 1 IOCB on the extended IOCB ring.
+ * @vha: HA context
+ * @req: request queue
+ *
+ * Returns a pointer to the continuation type 1 IOCB packet.
+ */
+struct cont_a64_entry_ext *
+qla2900_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req)
+{
+	struct cont_a64_entry_ext *cont_pkt;
+
+	/*
+	 * 29xx uses the 128-byte extended IOCB ring.  Advance via ring_ext_ptr
+	 * so the pointer arithmetic matches the on-ring stride.
+	 */
+	req->ring_index++;
+	if (req->ring_index == req->length) {
+		req->ring_index = 0;
+		req->ring_ext_ptr = req->ring_ext;
+	} else {
+		req->ring_ext_ptr++;
+	}
+
+	cont_pkt = (struct cont_a64_entry_ext *)req->ring_ext_ptr;
+
+	/* Load packet defaults. */
+	put_unaligned_le32(CONTINUE_A64_TYPE, &cont_pkt->entry_type);
+
+	return cont_pkt;
+}
+
+/*
+ * Note: the 29xx extended path reuses qla24xx_configure_prot_mode() -- the
+ * SCSI-prot-op to PO_MODE_DIF_* translation is independent of the IOCB
+ * generation.
+ */
+
+/**
+ * qla29xx_build_scsi_type_6_iocbs() - Build IOCB command utilizing Command
+ * Type 6 IOCB types on the 29xx extended ring.
+ * @sp: SRB command to process
+ * @cmd_pkt: Command type 6 extended IOCB
+ * @tot_dsds: Total number of segments to transfer
+ */
+static void
+qla29xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6_ext *cmd_pkt,
+	uint16_t tot_dsds)
+{
+	struct dsd64 *cur_dsd = NULL, *next_dsd;
+	scsi_qla_host_t	*vha;
+	struct qla_hw_data *ha;
+	struct scsi_cmnd *cmd;
+	struct	scatterlist *cur_seg;
+	uint8_t avail_dsds;
+	uint8_t first_iocb = 1;
+	uint32_t dsd_list_len;
+	struct dsd_dma *dsd_ptr;
+	struct ct6_dsd *ctx;
+	struct qla_qpair *qpair = sp->qpair;
+
+	cmd = GET_CMD_SP(sp);
+
+	/* Update entry type to indicate Command Type 6 IOCB */
+	put_unaligned_le32(COMMAND_TYPE_6, &cmd_pkt->entry_type);
+
+	/* No data transfer */
+	if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
+		cmd_pkt->byte_count = cpu_to_le32(0);
+		goto function_end;
+	}
+
+	vha = sp->vha;
+	ha = vha->hw;
+
+	/* Set transfer direction */
+	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+		cmd_pkt->control_flags = cpu_to_le16(CF_WRITE_DATA);
+		qpair->counters.output_bytes += scsi_bufflen(cmd);
+		qpair->counters.output_requests++;
+	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
+		cmd_pkt->control_flags = cpu_to_le16(CF_READ_DATA);
+		qpair->counters.input_bytes += scsi_bufflen(cmd);
+		qpair->counters.input_requests++;
+	}
+
+	cur_seg = scsi_sglist(cmd);
+	ctx = &sp->u.scmd.ct6_ctx;
+
+	while (tot_dsds) {
+		avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ?
+		    QLA_DSDS_PER_IOCB : tot_dsds;
+		tot_dsds -= avail_dsds;
+		dsd_list_len = (avail_dsds + 1) * QLA_DSD_SIZE;
+
+		dsd_ptr = list_first_entry(&qpair->dsd_list, struct dsd_dma,
+					   list);
+		next_dsd = dsd_ptr->dsd_addr;
+		list_del(&dsd_ptr->list);
+		qpair->dsd_avail--;
+		list_add_tail(&dsd_ptr->list, &ctx->dsd_list);
+		ctx->dsd_use_cnt++;
+		qpair->dsd_inuse++;
+
+		if (first_iocb) {
+			first_iocb = 0;
+			put_unaligned_le64(dsd_ptr->dsd_list_dma,
+					   &cmd_pkt->dsd[0].address);
+			cmd_pkt->dsd[0].length = cpu_to_le32(dsd_list_len);
+		} else {
+			put_unaligned_le64(dsd_ptr->dsd_list_dma,
+					   &cur_dsd->address);
+			cur_dsd->length = cpu_to_le32(dsd_list_len);
+			cur_dsd++;
+		}
+		cur_dsd = next_dsd;
+		while (avail_dsds) {
+			append_dsd64(&cur_dsd, cur_seg);
+			cur_seg = sg_next(cur_seg);
+			avail_dsds--;
+		}
+	}
+
+	/* Null termination */
+	if (cur_dsd) {
+		cur_dsd->address = 0;
+		cur_dsd->length = 0;
+		cur_dsd++;
+	}
+	cmd_pkt->control_flags |= CF_DATA_SEG_DESCR_ENABLE;
+function_end:
+	return;
+}
+
+/*
+ * Note: the 29xx extended path reuses qla24xx_calc_dsd_lists() -- the
+ * DSD-list-per-IOCB arithmetic (based on QLA_DSDS_PER_IOCB) is generation-
+ * agnostic.
+ */
+
+/**
+ * qla29xx_build_scsi_iocbs() - Build IOCB command utilizing Command Type 7
+ * IOCB types on the 29xx extended ring.
+ * @sp: SRB command to process
+ * @cmd_pkt: Command type 7 extended IOCB
+ * @tot_dsds: Total number of segments to transfer
+ * @req: pointer to request queue
+ */
+static void __maybe_unused
+qla29xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_ext *cmd_pkt,
+	uint16_t tot_dsds, struct req_que *req)
+{
+	uint8_t	avail_dsds;
+	struct dsd64 *cur_dsd;
+	scsi_qla_host_t	*vha;
+	struct scsi_cmnd *cmd;
+	struct scatterlist *sg;
+	int i;
+	struct qla_qpair *qpair = sp->qpair;
+
+	cmd = GET_CMD_SP(sp);
+
+	/* Update entry type to indicate Command Type 7 IOCB */
+	put_unaligned_le32(COMMAND_TYPE_7, &cmd_pkt->entry_type);
+
+	/* No data transfer */
+	if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
+		cmd_pkt->byte_count = cpu_to_le32(0);
+		return;
+	}
+
+	vha = sp->vha;
+
+	/* Set transfer direction */
+	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+		cmd_pkt->task_mgmt_flags = cpu_to_le16(TMF_WRITE_DATA);
+		qpair->counters.output_bytes += scsi_bufflen(cmd);
+		qpair->counters.output_requests++;
+	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
+		cmd_pkt->task_mgmt_flags = cpu_to_le16(TMF_READ_DATA);
+		qpair->counters.input_bytes += scsi_bufflen(cmd);
+		qpair->counters.input_requests++;
+	}
+
+	/* NUM_CMD67_DSDS DSDs available in the Command Type 7 ext IOCB */
+	avail_dsds = NUM_CMD67_DSDS;
+	cur_dsd = &cmd_pkt->dsd[0];
+
+	scsi_for_each_sg(cmd, sg, tot_dsds, i) {
+		struct cont_a64_entry_ext *cont_pkt;
+
+		/* Allocate additional continuation packets? */
+		if (avail_dsds == 0) {
+			/*
+			 * NUM_CONT1_DSDS DSDs are available in the Continuation
+			 * Type 1 extended IOCB.
+			 */
+			cont_pkt = qla2900_prep_cont_type1_iocb(vha, req);
+			cur_dsd = cont_pkt->dsd;
+			avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
+		}
+
+		append_dsd64(&cur_dsd, sg);
+		avail_dsds--;
+	}
+}
+
+/*
+ * Note: the 29xx extended path reuses qla24xx_set_t10dif_tags() (defined
+ * earlier in this file) -- the T10-DIF ref/app tag layout is identical
+ * between the 24xx and 29xx extended CRC_2 IOCBs (both share the same
+ * fw_dif_context layout inside struct crc_context).
+ */
+
+/*
+ * Note: the 29xx extended CRC_2 path reuses the 24xx SG walkers
+ * (qla24xx_get_one_block_sg, qla24xx_walk_and_build_sglist_no_difb,
+ * qla24xx_walk_and_build_sglist, qla24xx_walk_and_build_prot_sglist).
+ * The DSD-chain / CRC-context layout they produce is generation-agnostic;
+ * only the IOCB that points at the chain (Type-6/7/CRC_2 vs their _ext
+ * variants) differs between generations, and that is handled by the
+ * separate qla29xx_build_* builders.
+ *
+ * The walkers that take a struct qla_tc_param *tc are invoked with tc=NULL
+ * here because the 29xx fast-path does not use the tape/copy offload.
+ */
+
+/**
+ * qla29xx_build_scsi_crc_2_iocbs() - Build IOCB command utilizing Command
+ * Type CRC_2 IOCB types on the 29xx extended ring.
+ * @sp: SRB command to process
+ * @cmd_pkt: Command type CRC_2 extended IOCB
+ * @tot_dsds: Total number of segments to transfer
+ * @tot_prot_dsds: Total number of segments with protection information
+ * @fw_prot_opts: Protection options to be passed to firmware
+ * @bundling: Bundling flag
+ *
+ * Returns 0 if successful, 1 otherwise.
+ */
+static int
+qla29xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2_ext *cmd_pkt,
+	uint16_t tot_dsds, uint16_t tot_prot_dsds, uint16_t fw_prot_opts,
+	uint8_t bundling)
+{
+	struct dsd64		*cur_dsd;
+	__be32			*fcp_dl;
+	scsi_qla_host_t		*vha;
+	struct scsi_cmnd	*cmd;
+	uint32_t		total_bytes = 0;
+	uint32_t		data_bytes;
+	uint32_t		dif_bytes;
+	uint16_t		blk_size;
+	struct crc_context	*crc_ctx_pkt = NULL;
+	struct qla_hw_data	*ha;
+	uint8_t			additional_fcpcdb_len;
+	uint16_t		fcp_cmnd_len;
+	struct fcp_cmnd		*fcp_cmnd;
+	dma_addr_t		crc_ctx_dma;
+
+	cmd = GET_CMD_SP(sp);
+
+	/* Update entry type to indicate Command Type CRC_2 IOCB */
+	put_unaligned_le32(COMMAND_TYPE_CRC_2, &cmd_pkt->entry_type);
+
+	vha = sp->vha;
+	ha = vha->hw;
+
+	/* No data transfer */
+	data_bytes = scsi_bufflen(cmd);
+	if (!data_bytes || cmd->sc_data_direction == DMA_NONE) {
+		cmd_pkt->byte_count = cpu_to_le32(0);
+		return QLA_SUCCESS;
+	}
+
+	cmd_pkt->vp_index = cpu_to_le16(sp->vha->vp_idx);
+
+	/* Set transfer direction */
+	if (cmd->sc_data_direction == DMA_TO_DEVICE)
+		cmd_pkt->control_flags_1 = cpu_to_le16(CF_WRITE_DATA);
+	else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+		cmd_pkt->control_flags_1 = cpu_to_le16(CF_READ_DATA);
+	/* Allocate CRC context from global pool */
+	crc_ctx_pkt = sp->u.scmd.crc_ctx =
+	    dma_pool_zalloc(ha->dl_dma_pool, GFP_ATOMIC, &crc_ctx_dma);
+
+	if (!crc_ctx_pkt)
+		goto crc_queuing_error;
+
+	crc_ctx_pkt->crc_ctx_dma = crc_ctx_dma;
+
+	sp->flags |= SRB_CRC_CTX_DMA_VALID;
+
+	/* Set handle */
+	crc_ctx_pkt->handle = cmd_pkt->handle;
+
+	INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list);
+
+	qla24xx_set_t10dif_tags(sp, (struct fw_dif_context *)
+	    &crc_ctx_pkt->ref_tag, tot_prot_dsds);
+
+	/* Determine SCSI command length -- align to 4 byte boundary */
+	if (cmd->cmd_len > 16) {
+		additional_fcpcdb_len = cmd->cmd_len - 16;
+		if ((cmd->cmd_len % 4) != 0) {
+			/* SCSI cmd > 16 bytes must be multiple of 4 */
+			goto crc_queuing_error;
+		}
+		fcp_cmnd_len = 12 + cmd->cmd_len + 4;
+	} else {
+		additional_fcpcdb_len = 0;
+		fcp_cmnd_len = 12 + 16 + 4;
+	}
+
+	fcp_cmnd = &crc_ctx_pkt->fcp_cmnd;
+
+	fcp_cmnd->additional_cdb_len = additional_fcpcdb_len;
+	if (cmd->sc_data_direction == DMA_TO_DEVICE)
+		fcp_cmnd->additional_cdb_len |= 1;
+	else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+		fcp_cmnd->additional_cdb_len |= 2;
+
+	int_to_scsilun(cmd->device->lun, &fcp_cmnd->lun);
+	memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
+	cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len);
+	put_unaligned_le64(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF,
+			   &cmd_pkt->fcp_cmnd_dseg_address);
+	fcp_cmnd->task_management = 0;
+	fcp_cmnd->task_attribute = TSK_SIMPLE;
+
+	cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */
+
+	/* Compute dif len and adjust data len to include protection */
+	dif_bytes = 0;
+	blk_size = cmd->device->sector_size;
+	dif_bytes = (data_bytes / blk_size) * 8;
+
+	switch (scsi_get_prot_op(GET_CMD_SP(sp))) {
+	case SCSI_PROT_READ_INSERT:
+	case SCSI_PROT_WRITE_STRIP:
+		total_bytes = data_bytes;
+		data_bytes += dif_bytes;
+		break;
+
+	case SCSI_PROT_READ_STRIP:
+	case SCSI_PROT_WRITE_INSERT:
+	case SCSI_PROT_READ_PASS:
+	case SCSI_PROT_WRITE_PASS:
+		total_bytes = data_bytes + dif_bytes;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		return 1;
+	}
+
+	if (!qla2x00_hba_err_chk_enabled(sp))
+		fw_prot_opts |= 0x10; /* Disable Guard tag checking */
+	/* HBA error checking enabled */
+	else {
+		if ((scsi_get_prot_type(GET_CMD_SP(sp)) == SCSI_PROT_DIF_TYPE1)
+		    || (scsi_get_prot_type(GET_CMD_SP(sp)) ==
+			SCSI_PROT_DIF_TYPE2))
+			fw_prot_opts |= BIT_10;
+		else if (scsi_get_prot_type(GET_CMD_SP(sp)) ==
+		    SCSI_PROT_DIF_TYPE3)
+			fw_prot_opts |= BIT_11;
+	}
+
+	if (!bundling) {
+		cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd[0];
+	} else {
+		/*
+		 * Configure Bundling if we need to fetch interleaving
+		 * protection PCI accesses
+		 */
+		fw_prot_opts |= PO_ENABLE_DIF_BUNDLING;
+		crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes);
+		crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(tot_dsds -
+							tot_prot_dsds);
+		cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd[0];
+	}
+
+	/* Finish the common fields of CRC pkt */
+	crc_ctx_pkt->blk_size = cpu_to_le16(blk_size);
+	crc_ctx_pkt->prot_opts = cpu_to_le16(fw_prot_opts);
+	crc_ctx_pkt->byte_count = cpu_to_le32(data_bytes);
+	crc_ctx_pkt->guard_seed = cpu_to_le16(0);
+	/* Fibre channel byte count */
+	cmd_pkt->byte_count = cpu_to_le32(total_bytes);
+	fcp_dl = (__be32 *)(crc_ctx_pkt->fcp_cmnd.cdb + 16 +
+	    additional_fcpcdb_len);
+	*fcp_dl = htonl(total_bytes);
+
+	/* Walks data segments */
+
+	cmd_pkt->control_flags_1 |= cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE);
+
+	if (!bundling && tot_prot_dsds) {
+		if (qla24xx_walk_and_build_sglist_no_difb(ha, sp,
+			cur_dsd, tot_dsds, NULL))
+			goto crc_queuing_error;
+	} else if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd,
+			(tot_dsds - tot_prot_dsds), NULL))
+		goto crc_queuing_error;
+
+	if (bundling && tot_prot_dsds) {
+		/* Walks dif segments */
+		cmd_pkt->control_flags_1 |= cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE);
+		cur_dsd = &crc_ctx_pkt->u.bundling.dif_dsd;
+		if (qla24xx_walk_and_build_prot_sglist(ha, sp, cur_dsd,
+				tot_prot_dsds, NULL))
+			goto crc_queuing_error;
+	}
+	qla29xx_copy_dif_iocb_data(cmd_pkt, crc_ctx_pkt, bundling);
+
+	return QLA_SUCCESS;
+
+crc_queuing_error:
+	/* Cleanup will be performed by the caller */
+	return QLA_FUNCTION_FAILED;
+}
+
+/**
+ * qla29xx_copy_dif_iocb_data() - Populate the DIF-related fields of an
+ * extended CRC_2 command IOCB from a freshly populated crc_context.
+ * @cmd_pkt: Extended CRC_2 command IOCB
+ * @crc_ctx_pkt: Source CRC context
+ * @dif_bundling: DIF bundling flag
+ */
+static void
+qla29xx_copy_dif_iocb_data(struct cmd_type_crc_2_ext *cmd_pkt,
+	struct crc_context *crc_ctx_pkt, uint8_t dif_bundling)
+{
+	cmd_pkt->ref_tag = crc_ctx_pkt->ref_tag;
+	cmd_pkt->app_tag = crc_ctx_pkt->app_tag;
+	memcpy(cmd_pkt->ref_tag_mask, crc_ctx_pkt->ref_tag_mask,
+	       sizeof(cmd_pkt->ref_tag_mask));
+	memcpy(cmd_pkt->app_tag_mask, crc_ctx_pkt->app_tag_mask,
+	       sizeof(cmd_pkt->app_tag_mask));
+	cmd_pkt->blk_size = crc_ctx_pkt->blk_size;
+	cmd_pkt->prot_opts = crc_ctx_pkt->prot_opts;
+	cmd_pkt->tot_byte_count = crc_ctx_pkt->byte_count;
+	if (dif_bundling) {
+		cmd_pkt->u.bundling.guard_seed = crc_ctx_pkt->guard_seed;
+		cmd_pkt->u.bundling.dif_byte_count =
+			crc_ctx_pkt->u.bundling.dif_byte_count;
+		cmd_pkt->u.bundling.dseg_count =
+			crc_ctx_pkt->u.bundling.dseg_count;
+		memcpy(cmd_pkt->u.bundling.data_dsd,
+		       crc_ctx_pkt->u.bundling.data_dsd,
+		       sizeof(cmd_pkt->u.bundling.data_dsd));
+		memcpy(&cmd_pkt->u.bundling.dif_dsd,
+		       &crc_ctx_pkt->u.bundling.dif_dsd,
+		       sizeof(cmd_pkt->u.bundling.dif_dsd));
+	} else {
+		cmd_pkt->u.nobundling.guard_seed = crc_ctx_pkt->guard_seed;
+		memcpy(cmd_pkt->u.nobundling.data_dsd,
+		       crc_ctx_pkt->u.nobundling.data_dsd,
+		       sizeof(cmd_pkt->u.nobundling.data_dsd));
+	}
+}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index c47c38e099ff..b8397912cb04 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -209,13 +209,7 @@ void __qla_consume_iocb(struct scsi_qla_host *vha,
 		new_pkt = rsp_q->ring_ptr;
 		*pkt = new_pkt;
 
-		rsp_q->ring_index++;
-		if (rsp_q->ring_index == rsp_q->length) {
-			rsp_q->ring_index = 0;
-			rsp_q->ring_ptr = rsp_q->ring;
-		} else {
-			rsp_q->ring_ptr++;
-		}
+		qla_rsp_ring_advance(rsp_q);
 
 		new_pkt->signature = RESPONSE_PROCESSED;
 		/* flush signature */
@@ -287,13 +281,7 @@ int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
 				break;
 			}
 
-			rsp_q->ring_index++;
-			if (rsp_q->ring_index == rsp_q->length) {
-				rsp_q->ring_index = 0;
-				rsp_q->ring_ptr = rsp_q->ring;
-			} else {
-				rsp_q->ring_ptr++;
-			}
+			qla_rsp_ring_advance(rsp_q);
 			no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
 			    sizeof(new_pkt->data) : pending_bytes;
 			if ((buffer_copy_offset + no_bytes) <= total_bytes) {
@@ -1212,13 +1200,7 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
 				break;
 			}
 
-			rsp_q->ring_index++;
-			if (rsp_q->ring_index == rsp_q->length) {
-				rsp_q->ring_index = 0;
-				rsp_q->ring_ptr = rsp_q->ring;
-			} else {
-				rsp_q->ring_ptr++;
-			}
+			qla_rsp_ring_advance(rsp_q);
 			no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
 			    sizeof(new_pkt->data) : pending_bytes;
 			if ((buffer_copy_offset + no_bytes) <= total_bytes) {
@@ -2973,13 +2955,7 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
 	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
 		pkt = (sts_entry_t *)rsp->ring_ptr;
 
-		rsp->ring_index++;
-		if (rsp->ring_index == rsp->length) {
-			rsp->ring_index = 0;
-			rsp->ring_ptr = rsp->ring;
-		} else {
-			rsp->ring_ptr++;
-		}
+		qla_rsp_ring_advance(rsp);
 
 		if (pkt->entry_status != 0) {
 			qla2x00_error_entry(vha, rsp, pkt);
@@ -4003,13 +3979,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
 		cur_ring_index = rsp->ring_index;
 
-		rsp->ring_index++;
-		if (rsp->ring_index == rsp->length) {
-			rsp->ring_index = 0;
-			rsp->ring_ptr = rsp->ring;
-		} else {
-			rsp->ring_ptr++;
-		}
+		qla_rsp_ring_advance(rsp);
 
 		if (pkt->entry_status != 0) {
 			if (qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt))
@@ -4127,8 +4097,8 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 					 * interrupt with all IOCBs to arrive
 					 * and re-process.
 					 */
-					rsp->ring_ptr = (response_t *)pkt;
-					rsp->ring_index = cur_ring_index;
+					qla_rsp_ring_rewind_to(rsp,
+					    (response_t *)pkt, cur_ring_index);
 
 					ql_dbg(ql_dbg_init, vha, 0x5091,
 					    "Defer processing ELS opcode %#x...\n",
@@ -4150,8 +4120,8 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 		case PT_LS4_UNSOL:
 			p = (void *)pkt;
 			if (qla_chk_cont_iocb_avail(vha, rsp, (response_t *)pkt, rsp_in)) {
-				rsp->ring_ptr = (response_t *)pkt;
-				rsp->ring_index = cur_ring_index;
+				qla_rsp_ring_rewind_to(rsp, (response_t *)pkt,
+						       cur_ring_index);
 
 				ql_dbg(ql_dbg_init, vha, 0x2124,
 				       "Defer processing UNSOL LS req opcode %#x...\n",
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index e75b7ae22bc5..482275ca4f26 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -736,6 +736,10 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
 		    "Failed to allocate memory for request_ring.\n");
 		goto que_failed;
 	}
+	if (IS_QLA29XX(ha)) {
+		req->ring_ext = (struct request_ext *)req->ring;
+		req->ring_ext_ptr = req->ring_ext;
+	}
 
 	ret = qla2x00_alloc_outstanding_cmds(ha, req);
 	if (ret != QLA_SUCCESS)
@@ -781,7 +785,15 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
 		req->outstanding_cmds[cnt] = NULL;
 	req->current_outstanding_cmd = 1;
 
+	/*
+	 * Re-anchor both the 24xx (ring_ptr) and 29xx (ring_ext_ptr) views
+	 * at the start of the ring.  Keeping them reset together here
+	 * guarantees they stay in sync with ring_index=0 regardless of any
+	 * prior allocator/fast-path advances against this queue.
+	 */
 	req->ring_ptr = req->ring;
+	if (IS_QLA29XX(ha))
+		req->ring_ext_ptr = req->ring_ext;
 	req->ring_index = 0;
 	req->cnt = req->length;
 	req->id = que_id;
@@ -789,7 +801,15 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
 	req->req_q_in = &reg->isp25mq.req_q_in;
 	req->req_q_out = &reg->isp25mq.req_q_out;
 	req->max_q_depth = ha->req_q_map[0]->max_q_depth;
-	req->out_ptr = (uint16_t *)(req->ring + req->length);
+	/*
+	 * out_ptr sits in the scratch slot immediately after the ring.  Use
+	 * the 29xx-stride pointer when the ring is 128-byte-per-entry so the
+	 * pointer arithmetic resolves to the correct byte offset.
+	 */
+	if (IS_QLA29XX(ha))
+		req->out_ptr = (uint16_t *)(req->ring_ext + req->length);
+	else
+		req->out_ptr = (uint16_t *)(req->ring + req->length);
 	mutex_unlock(&ha->mq_lock);
 	ql_dbg(ql_dbg_multiq, base_vha, 0xc004,
 	    "ring_ptr=%p ring_index=%d, "
@@ -867,6 +887,10 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
 		    "Failed to allocate memory for response ring.\n");
 		goto que_failed;
 	}
+	if (IS_QLA29XX(ha)) {
+		rsp->ring_ext = (struct response_ext *)rsp->ring;
+		rsp->ring_ext_ptr = rsp->ring_ext;
+	}
 
 	mutex_lock(&ha->mq_lock);
 	que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_rsp_queues);
@@ -905,7 +929,10 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
 	reg = ISP_QUE_REG(ha, que_id);
 	rsp->rsp_q_in = &reg->isp25mq.rsp_q_in;
 	rsp->rsp_q_out = &reg->isp25mq.rsp_q_out;
-	rsp->in_ptr = (uint16_t *)(rsp->ring + rsp->length);
+	if (IS_QLA29XX(ha))
+		rsp->in_ptr = (uint16_t *)(rsp->ring_ext + rsp->length);
+	else
+		rsp->in_ptr = (uint16_t *)(rsp->ring + rsp->length);
 	mutex_unlock(&ha->mq_lock);
 	ql_dbg(ql_dbg_multiq, base_vha, 0xc00b,
 	    "options=%x id=%d rsp_q_in=%p rsp_q_out=%p\n",
diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index 2531e71c39dc..6ca300f8cc26 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -555,6 +555,7 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
 	uint32_t        *clr_ptr;
 	uint32_t        handle;
 	struct cmd_nvme *cmd_pkt;
+	struct cmd_nvme_ext *cmd_pkt_ext;
 	uint16_t        cnt, i;
 	uint16_t        req_cnt;
 	uint16_t        tot_dsds;
@@ -584,7 +585,10 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
 		rval = -EBUSY;
 		goto queuing_error;
 	}
-	req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
+	if (IS_QLA29XX(ha))
+		req_cnt = qla29xx_calc_iocbs(vha, tot_dsds, NUM_NVME_DSDS);
+	else
+		req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
 
 	sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
 	sp->iores.exch_cnt = 1;
@@ -629,12 +633,26 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
 	sp->handle = handle;
 	req->cnt -= req_cnt;
 
-	cmd_pkt = (struct cmd_nvme *)req->ring_ptr;
+	/*
+	 * 29xx operates on the 128-byte extended IOCB ring via ring_ext_ptr;
+	 * the header layout of struct cmd_nvme is identical to the head of
+	 * struct cmd_nvme_ext through 'byte_count', so common field writes
+	 * below go through 'cmd_pkt'.  Divergent tail fields
+	 * (port_id/vp_index, DSD array) are handled via IS_QLA29XX() branches.
+	 */
+	if (IS_QLA29XX(ha))
+		cmd_pkt = (struct cmd_nvme *)req->ring_ext_ptr;
+	else
+		cmd_pkt = (struct cmd_nvme *)req->ring_ptr;
+	cmd_pkt_ext = (struct cmd_nvme_ext *)cmd_pkt;
 	cmd_pkt->handle = make_handle(req->id, handle);
 
 	/* Zero out remaining portion of packet. */
 	clr_ptr = (uint32_t *)cmd_pkt + 2;
-	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
+	if (IS_QLA29XX(ha))
+		memset(clr_ptr, 0, REQUEST_ENTRY_SIZE_EXT - 8);
+	else
+		memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
 
 	cmd_pkt->entry_status = 0;
 
@@ -674,10 +692,18 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
 
 	/* Set NPORT-ID */
 	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
-	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
-	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
-	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
-	cmd_pkt->vp_index = sp->fcport->vha->vp_idx;
+	if (IS_QLA29XX(ha)) {
+		/*
+		 * 29xx extended NVMe IOCB has no port_id[] field; vp_index is a
+		 * 9-bit __le16 (see CMD_EXT_VP_INDEX_MASK).
+		 */
+		cmd_pkt_ext->vp_index = cpu_to_le16(sp->fcport->vha->vp_idx);
+	} else {
+		cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
+		cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
+		cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
+		cmd_pkt->vp_index = sp->fcport->vha->vp_idx;
+	}
 
 	/* NVME RSP IU */
 	cmd_pkt->nvme_rsp_dsd_len = cpu_to_le16(fd->rsplen);
@@ -690,36 +716,51 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
 	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
 	cmd_pkt->byte_count = cpu_to_le32(fd->payload_length);
 
-	/* One DSD is available in the Command Type NVME IOCB */
-	avail_dsds = 1;
-	cur_dsd = &cmd_pkt->nvme_dsd;
+	/*
+	 * 24xx carries a single inline DSD in the NVMe command IOCB; 29xx
+	 * carries NUM_NVME_DSDS inline DSDs in the extended IOCB.
+	 */
+	if (IS_QLA29XX(ha)) {
+		avail_dsds = NUM_NVME_DSDS;
+		cur_dsd = &cmd_pkt_ext->nvme_dsd[0];
+	} else {
+		avail_dsds = 1;
+		cur_dsd = &cmd_pkt->nvme_dsd;
+	}
 	sgl = fd->first_sgl;
 
 	/* Load data segments */
 	for_each_sg(sgl, sg, tot_dsds, i) {
-		cont_a64_entry_t *cont_pkt;
-
 		/* Allocate additional continuation packets? */
 		if (avail_dsds == 0) {
-			/*
-			 * Five DSDs are available in the Continuation
-			 * Type 1 IOCB.
-			 */
-
-			/* Adjust ring index */
-			req->ring_index++;
-			if (req->ring_index == req->length) {
-				req->ring_index = 0;
-				req->ring_ptr = req->ring;
+			if (IS_QLA29XX(ha)) {
+				struct cont_a64_entry_ext *cont_pkt;
+
+				cont_pkt = qla2900_prep_cont_type1_iocb(vha,
+									req);
+				cur_dsd = cont_pkt->dsd;
+				avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
 			} else {
-				req->ring_ptr++;
+				cont_a64_entry_t *cont_pkt;
+
+				/*
+				 * Five DSDs are available in the 24xx
+				 * Continuation Type 1 IOCB.
+				 */
+				req->ring_index++;
+				if (req->ring_index == req->length) {
+					req->ring_index = 0;
+					req->ring_ptr = req->ring;
+				} else {
+					req->ring_ptr++;
+				}
+				cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
+				put_unaligned_le32(CONTINUE_A64_TYPE,
+						   &cont_pkt->entry_type);
+
+				cur_dsd = cont_pkt->dsd;
+				avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
 			}
-			cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
-			put_unaligned_le32(CONTINUE_A64_TYPE,
-					   &cont_pkt->entry_type);
-
-			cur_dsd = cont_pkt->dsd;
-			avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
 		}
 
 		append_dsd64(&cur_dsd, sg);
@@ -732,11 +773,20 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
 
 	/* Adjust ring index. */
 	req->ring_index++;
-	if (req->ring_index == req->length) {
-		req->ring_index = 0;
-		req->ring_ptr = req->ring;
+	if (IS_QLA29XX(ha)) {
+		if (req->ring_index == req->length) {
+			req->ring_index = 0;
+			req->ring_ext_ptr = req->ring_ext;
+		} else {
+			req->ring_ext_ptr++;
+		}
 	} else {
-		req->ring_ptr++;
+		if (req->ring_index == req->length) {
+			req->ring_index = 0;
+			req->ring_ptr = req->ring;
+		} else {
+			req->ring_ptr++;
+		}
 	}
 
 	/* ignore nvme async cmd due to long timeout */
@@ -746,7 +796,12 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
 	/* Set chip new ring index. */
 	wrt_reg_dword(req->req_q_in, req->ring_index);
 
-	if (vha->flags.process_response_queue &&
+	/*
+	 * 29xx inline response drain would require the 128-byte response ring
+	 * view, which the 24xx qla24xx_process_response_queue() does not walk;
+	 * skip here and rely on the normal ISR path.
+	 */
+	if (!IS_QLA29XX(ha) && vha->flags.process_response_queue &&
 	    rsp->ring_ptr->signature != RESPONSE_PROCESSED)
 		qla24xx_process_response_queue(vha, rsp);
 
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 948242f0088e..c79c1cca0b7d 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -509,7 +509,9 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
 			    req->ring_fx00, req->dma_fx00);
 	} else if (req && req->ring)
 		dma_free_coherent(&ha->pdev->dev,
-		(req->length + 1) * sizeof(request_t),
+		(req->length + 1) *
+			(IS_QLA29XX(ha) ? sizeof(struct request_ext) :
+					  sizeof(request_t)),
 		req->ring, req->dma);
 
 	if (req)
@@ -527,8 +529,10 @@ static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
 			    rsp->ring_fx00, rsp->dma_fx00);
 	} else if (rsp && rsp->ring) {
 		dma_free_coherent(&ha->pdev->dev,
-		(rsp->length + 1) * sizeof(response_t),
-		rsp->ring, rsp->dma);
+		    (rsp->length + 1) *
+			(IS_QLA29XX(ha) ? sizeof(struct response_ext) :
+					  sizeof(response_t)),
+		    rsp->ring, rsp->dma);
 	}
 	kfree(rsp);
 }
@@ -2693,6 +2697,7 @@ static struct isp_operations qla29xx_isp_ops = {
 	.read_optrom_region	= qla29xx_read_optrom_data,
 	.write_optrom_region	= qla29xx_write_optrom_data,
 	.get_flash_version	= qla24xx_get_flash_version,
+	.start_scsi		= qla24xx_dif_start_scsi,
 	.start_scsi_mq		= qla2xxx_dif_start_scsi_mq,
 	.abort_isp		= qla2x00_abort_isp,
 	.iospace_config		= qla83xx_iospace_config,
@@ -4444,13 +4449,19 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	}
 	(*req)->length = req_len;
 	(*req)->ring = dma_alloc_coherent(&ha->pdev->dev,
-		((*req)->length + 1) * sizeof(request_t),
+		((*req)->length + 1) *
+			(IS_QLA29XX(ha) ? sizeof(struct request_ext) :
+					  sizeof(request_t)),
 		&(*req)->dma, GFP_KERNEL);
 	if (!(*req)->ring) {
 		ql_log_pci(ql_log_fatal, ha->pdev, 0x0029,
 		    "Failed to allocate memory for req_ring.\n");
 		goto fail_req_ring;
 	}
+	if (IS_QLA29XX(ha)) {
+		(*req)->ring_ext = (struct request_ext *)(*req)->ring;
+		(*req)->ring_ext_ptr = (*req)->ring_ext;
+	}
 	/* Allocate memory for response ring */
 	*rsp = kzalloc_obj(struct rsp_que);
 	if (!*rsp) {
@@ -4461,13 +4472,19 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	(*rsp)->hw = ha;
 	(*rsp)->length = rsp_len;
 	(*rsp)->ring = dma_alloc_coherent(&ha->pdev->dev,
-		((*rsp)->length + 1) * sizeof(response_t),
+		((*rsp)->length + 1) *
+			(IS_QLA29XX(ha) ? sizeof(struct response_ext) :
+					  sizeof(response_t)),
 		&(*rsp)->dma, GFP_KERNEL);
 	if (!(*rsp)->ring) {
 		ql_log_pci(ql_log_fatal, ha->pdev, 0x002b,
 		    "Failed to allocate memory for rsp_ring.\n");
 		goto fail_rsp_ring;
 	}
+	if (IS_QLA29XX(ha)) {
+		(*rsp)->ring_ext = (struct response_ext *)(*rsp)->ring;
+		(*rsp)->ring_ext_ptr = (*rsp)->ring_ext;
+	}
 	(*req)->rsp = *rsp;
 	(*rsp)->req = *req;
 	ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002c,
@@ -4618,7 +4635,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	kfree(ha->npiv_info);
 fail_npiv_info:
 	dma_free_coherent(&ha->pdev->dev, ((*rsp)->length + 1) *
-		sizeof(response_t), (*rsp)->ring, (*rsp)->dma);
+		(IS_QLA29XX(ha) ? sizeof(struct response_ext) : sizeof(response_t)),
+		(*rsp)->ring, (*rsp)->dma);
 	(*rsp)->ring = NULL;
 	(*rsp)->dma = 0;
 fail_rsp_ring:
@@ -4626,7 +4644,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	*rsp = NULL;
 fail_rsp:
 	dma_free_coherent(&ha->pdev->dev, ((*req)->length + 1) *
-		sizeof(request_t), (*req)->ring, (*req)->dma);
+		(IS_QLA29XX(ha) ? sizeof(struct request_ext) : sizeof(request_t)),
+		(*req)->ring, (*req)->dma);
 	(*req)->ring = NULL;
 	(*req)->dma = 0;
 fail_req_ring:
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index e47da45e93a0..fd8abdc36a56 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -2490,17 +2490,13 @@ static int qlt_check_reserve_free_req(struct qla_qpair *qpair,
 /*
  * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire
  */
-static inline void *qlt_get_req_pkt(struct req_que *req)
+static inline void *qlt_get_req_pkt(struct qla_hw_data *ha,
+				     struct req_que *req)
 {
 	/* Adjust ring index. */
-	req->ring_index++;
-	if (req->ring_index == req->length) {
-		req->ring_index = 0;
-		req->ring_ptr = req->ring;
-	} else {
-		req->ring_ptr++;
-	}
-	return (cont_entry_t *)req->ring_ptr;
+	qla_req_ring_advance(ha, req);
+
+	return qla_req_ring_slot(ha, req);
 }
 
 /* ha->hardware_lock supposed to be held on entry */
@@ -2605,6 +2601,7 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm)
 	while (prm->seg_cnt > 0) {
 		cont_a64_entry_t *cont_pkt64 =
 			(cont_a64_entry_t *)qlt_get_req_pkt(
+			   prm->cmd->qpair->vha->hw,
 			   prm->cmd->qpair->req);
 
 		/*
@@ -3306,7 +3303,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
 			 */
 			struct ctio7_to_24xx *ctio =
 				(struct ctio7_to_24xx *)qlt_get_req_pkt(
-				    qpair->req);
+				    vha->hw, qpair->req);
 
 			ql_dbg_qp(ql_dbg_tgt, qpair, 0x305e,
 			    "Building additional status packet 0x%p.\n",
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 13/60] scsi: qla2xxx: Replace IS_QLA29XX() size checks with entry-size helpers
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (11 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 12/60] scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 11:14   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 14/60] scsi: qla2xxx: Skip image-set-valid attribute for 29xx Nilesh Javali
                   ` (46 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Anil Gurumurthy <agurumurthy@marvell.com>

Replace scattered IS_QLA29XX() ternary expressions for request and
response ring IOCB sizes with calls to qla_req_entry_size() and
qla_rsp_entry_size() inline helpers and pre-computed local variables.

This consolidates the size selection in eight functions across
qla_init.c (qla2x00_alloc_fw_dump), qla_mid.c (qla25xx_free_req_que,
qla25xx_free_rsp_que, qla25xx_create_req_que, qla25xx_create_rsp_que),
and qla_os.c (qla2x00_free_req_que, qla2x00_free_rsp_que,
qla2x00_mem_alloc), improving readability and avoiding repeated
conditionals in every allocation, free, and dump-size calculation.

Also extend the IS_QLA29XX() guard to the ring-index write path in
qla2x00_start_iocbs() and the IOCB allocation read path in
__qla2x00_alloc_iocbs().

No functional change.

Signed-off-by: Anil Gurumurthy <agurumurthy@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_init.c | 18 ++++++-----------
 drivers/scsi/qla2xxx/qla_iocb.c |  5 +++--
 drivers/scsi/qla2xxx/qla_mid.c  | 34 ++++++++++++---------------------
 drivers/scsi/qla2xxx/qla_os.c   | 32 +++++++++++++++----------------
 4 files changed, 36 insertions(+), 53 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 292ffabcba99..20eb67096b0b 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3814,6 +3814,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
 	struct req_que *req = ha->req_q_map[0];
 	struct rsp_que *rsp = ha->rsp_q_map[0];
 	struct qla2xxx_fw_dump *fw_dump;
+	size_t req_entry_size = qla_req_entry_size(ha);
+	size_t rsp_entry_size = qla_rsp_entry_size(ha);
 
 	if (ha->fw_dump) {
 		ql_dbg(ql_dbg_init, vha, 0x00bd,
@@ -3852,13 +3854,9 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
 			 * Resizing must be done at end-of-dump processing.
 			 */
 			mq_size += (ha->max_req_queues - 1) *
-			    (req->length *
-			     (IS_QLA29XX(ha) ? sizeof(struct request_ext) :
-					       sizeof(request_t)));
+			    (req->length * req_entry_size);
 			mq_size += (ha->max_rsp_queues - 1) *
-			    (rsp->length *
-			     (IS_QLA29XX(ha) ? sizeof(struct response_ext) :
-					       sizeof(response_t)));
+			    (rsp->length * rsp_entry_size);
 		}
 		if (ha->tgt.atio_ring)
 			mq_size += ha->tgt.atio_q_length * sizeof(request_t);
@@ -3894,12 +3892,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
 		/* Add space for spare MPI fw dump. */
 		dump_size += ha->fwdt[1].dump_size;
 	} else {
-		req_q_size = req->length *
-		    (IS_QLA29XX(ha) ? sizeof(struct request_ext) :
-				      sizeof(request_t));
-		rsp_q_size = rsp->length *
-		    (IS_QLA29XX(ha) ? sizeof(struct response_ext) :
-				      sizeof(response_t));
+		req_q_size = req->length * req_entry_size;
+		rsp_q_size = rsp->length * rsp_entry_size;
 		dump_size = offsetof(struct qla2xxx_fw_dump, isp);
 		dump_size += fixed_size + mem_size + req_q_size + rsp_q_size
 			+ eft_size;
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 6b8be182cdb8..4d22e059015f 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -481,7 +481,8 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
 		qla_req_ring_advance(ha, req);
 
 		/* Set chip new ring index. */
-		if (ha->mqenable || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+		if (ha->mqenable || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
+		    IS_QLA29XX(ha)) {
 			wrt_reg_dword(req->req_q_in, req->ring_index);
 		} else if (IS_QLA83XX(ha)) {
 			wrt_reg_dword(req->req_q_in, req->ring_index);
@@ -2421,7 +2422,7 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp)
 		if (qpair->use_shadow_reg)
 			cnt = *req->out_ptr;
 		else if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
-		    IS_QLA28XX(ha))
+		    IS_QLA28XX(ha) || IS_QLA29XX(ha))
 			cnt = rd_reg_dword(&reg->isp25mq.req_q_out);
 		else if (IS_P3P_TYPE(ha))
 			cnt = rd_reg_dword(reg->isp82.req_q_out);
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 482275ca4f26..bb2521c052bf 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -574,13 +574,11 @@ qla25xx_free_req_que(struct scsi_qla_host *vha, struct req_que *req)
 {
 	struct qla_hw_data *ha = vha->hw;
 	uint16_t que_id = req->id;
-	uint16_t reqsz;
+	size_t req_entry_size = qla_req_entry_size(ha);
 
-	reqsz = IS_QLA29XX(ha) ? sizeof(struct request_ext) :
-				 sizeof(request_t);
-
-	dma_free_coherent(&ha->pdev->dev, (req->length + 1) *
-			  reqsz, req->ring, req->dma);
+	dma_free_coherent(&ha->pdev->dev,
+			  (req->length + 1) * req_entry_size,
+			  req->ring, req->dma);
 	req->ring = NULL;
 	req->dma = 0;
 	if (que_id) {
@@ -598,10 +596,7 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
 {
 	struct qla_hw_data *ha = vha->hw;
 	uint16_t que_id = rsp->id;
-	uint16_t rspsz;
-
-	rspsz = IS_QLA29XX(ha) ? sizeof(struct response_ext) :
-				 sizeof(response_t);
+	size_t rsp_entry_size = qla_rsp_entry_size(ha);
 
 	if (rsp->msix && rsp->msix->have_irq) {
 		free_irq(rsp->msix->vector, rsp->msix->handle);
@@ -610,8 +605,9 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
 		rsp->msix->handle = NULL;
 	}
 
-	dma_free_coherent(&ha->pdev->dev, (rsp->length + 1) *
-			  rspsz, rsp->ring, rsp->dma);
+	dma_free_coherent(&ha->pdev->dev,
+			  (rsp->length + 1) * rsp_entry_size,
+			  rsp->ring, rsp->dma);
 	rsp->ring = NULL;
 	rsp->dma = 0;
 	if (que_id) {
@@ -715,7 +711,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
 	uint16_t que_id = 0;
 	device_reg_t *reg;
 	uint32_t cnt;
-	uint16_t reqsz;
+	size_t req_entry_size = qla_req_entry_size(ha);
 
 	req = kzalloc_obj(struct req_que);
 	if (req == NULL) {
@@ -724,12 +720,9 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
 		goto failed;
 	}
 
-	reqsz = IS_QLA29XX(ha) ? sizeof(struct request_ext) :
-				 sizeof(request_t);
-
 	req->length = REQUEST_ENTRY_CNT_24XX;
 	req->ring = dma_alloc_coherent(&ha->pdev->dev,
-			(req->length + 1) * reqsz,
+			(req->length + 1) * req_entry_size,
 			&req->dma, GFP_KERNEL);
 	if (req->ring == NULL) {
 		ql_log(ql_log_fatal, base_vha, 0x00da,
@@ -866,7 +859,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
 	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
 	uint16_t que_id = 0;
 	device_reg_t *reg;
-	uint16_t rspsz;
+	size_t rsp_entry_size = qla_rsp_entry_size(ha);
 
 	rsp = kzalloc_obj(struct rsp_que);
 	if (rsp == NULL) {
@@ -875,12 +868,9 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
 		goto failed;
 	}
 
-	rspsz = IS_QLA29XX(ha) ? sizeof(struct response_ext) :
-				 sizeof(response_t);
-
 	rsp->length = RESPONSE_ENTRY_CNT_MQ;
 	rsp->ring = dma_alloc_coherent(&ha->pdev->dev,
-			(rsp->length + 1) * rspsz,
+			(rsp->length + 1) * rsp_entry_size,
 			&rsp->dma, GFP_KERNEL);
 	if (rsp->ring == NULL) {
 		ql_log(ql_log_warn, base_vha, 0x00e1,
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index c79c1cca0b7d..ef105ae6af41 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -502,6 +502,8 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req,
 
 static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
 {
+	size_t req_entry_size = qla_req_entry_size(ha);
+
 	if (IS_QLAFX00(ha)) {
 		if (req && req->ring_fx00)
 			dma_free_coherent(&ha->pdev->dev,
@@ -509,10 +511,8 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
 			    req->ring_fx00, req->dma_fx00);
 	} else if (req && req->ring)
 		dma_free_coherent(&ha->pdev->dev,
-		(req->length + 1) *
-			(IS_QLA29XX(ha) ? sizeof(struct request_ext) :
-					  sizeof(request_t)),
-		req->ring, req->dma);
+		    (req->length + 1) * req_entry_size,
+		    req->ring, req->dma);
 
 	if (req)
 		kfree(req->outstanding_cmds);
@@ -522,6 +522,8 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
 
 static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
 {
+	size_t rsp_entry_size = qla_rsp_entry_size(ha);
+
 	if (IS_QLAFX00(ha)) {
 		if (rsp && rsp->ring_fx00)
 			dma_free_coherent(&ha->pdev->dev,
@@ -529,9 +531,7 @@ static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
 			    rsp->ring_fx00, rsp->dma_fx00);
 	} else if (rsp && rsp->ring) {
 		dma_free_coherent(&ha->pdev->dev,
-		    (rsp->length + 1) *
-			(IS_QLA29XX(ha) ? sizeof(struct response_ext) :
-					  sizeof(response_t)),
+		    (rsp->length + 1) * rsp_entry_size,
 		    rsp->ring, rsp->dma);
 	}
 	kfree(rsp);
@@ -4254,6 +4254,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 {
 	char	name[16];
 	int rc;
+	size_t req_entry_size = qla_req_entry_size(ha);
+	size_t rsp_entry_size = qla_rsp_entry_size(ha);
 
 	if (QLA_TGT_MODE_ENABLED() || EDIF_CAP(ha)) {
 		ha->vp_map = kzalloc_objs(struct qla_vp_map,
@@ -4449,9 +4451,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	}
 	(*req)->length = req_len;
 	(*req)->ring = dma_alloc_coherent(&ha->pdev->dev,
-		((*req)->length + 1) *
-			(IS_QLA29XX(ha) ? sizeof(struct request_ext) :
-					  sizeof(request_t)),
+		((*req)->length + 1) * req_entry_size,
 		&(*req)->dma, GFP_KERNEL);
 	if (!(*req)->ring) {
 		ql_log_pci(ql_log_fatal, ha->pdev, 0x0029,
@@ -4472,9 +4472,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	(*rsp)->hw = ha;
 	(*rsp)->length = rsp_len;
 	(*rsp)->ring = dma_alloc_coherent(&ha->pdev->dev,
-		((*rsp)->length + 1) *
-			(IS_QLA29XX(ha) ? sizeof(struct response_ext) :
-					  sizeof(response_t)),
+		((*rsp)->length + 1) * rsp_entry_size,
 		&(*rsp)->dma, GFP_KERNEL);
 	if (!(*rsp)->ring) {
 		ql_log_pci(ql_log_fatal, ha->pdev, 0x002b,
@@ -4634,8 +4632,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 fail_ex_init_cb:
 	kfree(ha->npiv_info);
 fail_npiv_info:
-	dma_free_coherent(&ha->pdev->dev, ((*rsp)->length + 1) *
-		(IS_QLA29XX(ha) ? sizeof(struct response_ext) : sizeof(response_t)),
+	dma_free_coherent(&ha->pdev->dev,
+		((*rsp)->length + 1) * rsp_entry_size,
 		(*rsp)->ring, (*rsp)->dma);
 	(*rsp)->ring = NULL;
 	(*rsp)->dma = 0;
@@ -4643,8 +4641,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	kfree(*rsp);
 	*rsp = NULL;
 fail_rsp:
-	dma_free_coherent(&ha->pdev->dev, ((*req)->length + 1) *
-		(IS_QLA29XX(ha) ? sizeof(struct request_ext) : sizeof(request_t)),
+	dma_free_coherent(&ha->pdev->dev,
+		((*req)->length + 1) * req_entry_size,
 		(*req)->ring, (*req)->dma);
 	(*req)->ring = NULL;
 	(*req)->dma = 0;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 14/60] scsi: qla2xxx: Skip image-set-valid attribute for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (12 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 13/60] scsi: qla2xxx: Replace IS_QLA29XX() size checks with entry-size helpers Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 11:14   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 15/60] scsi: qla2xxx: Skip unsupported sysfs attributes " Nilesh Javali
                   ` (45 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

The 29xx adapter does not support the QLA_IMG_SET_VALID_SUPPORT
driver attribute.  Gate the attribute behind an IS_QLA29XX()
check so that userspace applications querying driver capabilities
via BSG receive accurate information.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_bsg.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 92a0bc6dc7bc..00e980f0cd78 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -2904,11 +2904,14 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job)
 static int
 qla2x00_get_drv_attr(struct bsg_job *bsg_job)
 {
+	scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
 	struct qla_drv_attr drv_attr;
 	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+	struct qla_hw_data *ha = vha->hw;
 
 	memset(&drv_attr, 0, sizeof(struct qla_drv_attr));
-	drv_attr.ext_attributes |= QLA_IMG_SET_VALID_SUPPORT;
+	if (!IS_QLA29XX(ha))
+		drv_attr.ext_attributes |= QLA_IMG_SET_VALID_SUPPORT;
 
 
 	sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 15/60] scsi: qla2xxx: Skip unsupported sysfs attributes for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (13 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 14/60] scsi: qla2xxx: Skip image-set-valid attribute for 29xx Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:28   ` sashiko-bot
  2026-06-12 11:15   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 16/60] scsi: qla2xxx: Enable get_fw_version mailbox " Nilesh Javali
                   ` (44 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Not all sysfs attributes are applicable to the 29xx adapter.
Return -EPERM for attributes that are meaningless on 29xx (gold
firmware version, 84xx firmware version, flash block size, VLAN
ID, VN-port MAC address, and CNA firmware dump toggle) so that
userspace tools do not see stale or undefined values.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_attr.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 800751ab562a..e8755ab86b6a 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1471,6 +1471,9 @@ qla2x00_optrom_gold_fw_version_show(struct device *dev,
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 	struct qla_hw_data *ha = vha->hw;
 
+	if (IS_QLA29XX(ha))
+		return -EPERM;
+
 	if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
 	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
 		return scnprintf(buf, PAGE_SIZE, "\n");
@@ -1499,6 +1502,9 @@ qla24xx_84xx_fw_version_show(struct device *dev,
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 	struct qla_hw_data *ha = vha->hw;
 
+	if (IS_QLA29XX(ha))
+		return -EPERM;
+
 	if (!IS_QLA84XX(ha))
 		return scnprintf(buf, PAGE_SIZE, "\n");
 
@@ -1565,6 +1571,9 @@ qla2x00_flash_block_size_show(struct device *dev,
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 	struct qla_hw_data *ha = vha->hw;
 
+	if (IS_QLA29XX(ha))
+		return -EPERM;
+
 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", ha->fdt_block_size);
 }
 
@@ -1573,6 +1582,10 @@ qla2x00_vlan_id_show(struct device *dev, struct device_attribute *attr,
     char *buf)
 {
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+	struct qla_hw_data *ha = vha->hw;
+
+	if (IS_QLA29XX(ha))
+		return -EPERM;
 
 	if (!IS_CNA_CAPABLE(vha->hw))
 		return scnprintf(buf, PAGE_SIZE, "\n");
@@ -1585,6 +1598,10 @@ qla2x00_vn_port_mac_address_show(struct device *dev,
     struct device_attribute *attr, char *buf)
 {
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+	struct qla_hw_data *ha = vha->hw;
+
+	if (IS_QLA29XX(ha))
+		return -EPERM;
 
 	if (!IS_CNA_CAPABLE(vha->hw))
 		return scnprintf(buf, PAGE_SIZE, "\n");
@@ -1716,6 +1733,10 @@ qla2x00_allow_cna_fw_dump_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+	struct qla_hw_data *ha = vha->hw;
+
+	if (IS_QLA29XX(ha))
+		return -EPERM;
 
 	if (!IS_P3P_TYPE(vha->hw))
 		return scnprintf(buf, PAGE_SIZE, "\n");
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 16/60] scsi: qla2xxx: Enable get_fw_version mailbox for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (14 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 15/60] scsi: qla2xxx: Skip unsupported sysfs attributes " Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:31   ` sashiko-bot
  2026-06-12 11:16   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 17/60] scsi: qla2xxx: Extend execute_fw mailbox to include 29xx Nilesh Javali
                   ` (43 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

The serdes_version and several firmware capability fields were not
populated for 29xx because the get_fw_version mailbox path
excluded it from the 27xx/28xx checks.  Add IS_QLA29XX() to
the relevant conditionals so that firmware version, EDIF, and
serdes information are correctly retrieved on 29xx adapters.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_attr.c | 2 +-
 drivers/scsi/qla2xxx/qla_mbx.c  | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index e8755ab86b6a..3bf7123fe057 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1526,7 +1526,7 @@ qla2x00_serdes_version_show(struct device *dev, struct device_attribute *attr,
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
 		return scnprintf(buf, PAGE_SIZE, "\n");
 
 	return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 9c2633ca5036..0feb98b83293 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -1136,7 +1136,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
 		mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8;
 	if (IS_FWI2_CAPABLE(ha))
 		mcp->in_mb |= MBX_17|MBX_16|MBX_15;
-	if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+	if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
 		mcp->in_mb |=
 		    MBX_25|MBX_24|MBX_23|MBX_22|MBX_21|MBX_20|MBX_19|MBX_18|
 		    MBX_14|MBX_13|MBX_11|MBX_10|MBX_9|MBX_8|MBX_7;
@@ -1212,7 +1212,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
 			vha->flags.nvme2_enabled = 1;
 		}
 
-		if (IS_QLA28XX(ha) && ha->flags.edif_hw && ql2xsecenable &&
+		if ((IS_QLA28XX(ha) || IS_QLA29XX(ha)) && ha->flags.edif_hw && ql2xsecenable &&
 		    (ha->fw_attributes_ext[0] & FW_ATTR_EXT0_EDIF)) {
 			ha->flags.edif_enabled = 1;
 			ql_log(ql_log_info, vha, 0xffff,
@@ -1220,7 +1220,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
 		}
 	}
 
-	if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+	if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 		ha->serdes_version[0] = mcp->mb[7] & 0xff;
 		ha->serdes_version[1] = mcp->mb[8] >> 8;
 		ha->serdes_version[2] = mcp->mb[8] & 0xff;
@@ -1234,7 +1234,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
 		ha->fw_shared_ram_end = (mcp->mb[21] << 16) | mcp->mb[20];
 		ha->fw_ddr_ram_start = (mcp->mb[23] << 16) | mcp->mb[22];
 		ha->fw_ddr_ram_end = (mcp->mb[25] << 16) | mcp->mb[24];
-		if (IS_QLA28XX(ha)) {
+		if (IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 			if (mcp->mb[16] & BIT_10)
 				ha->flags.secure_fw = 1;
 
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 17/60] scsi: qla2xxx: Extend execute_fw mailbox to include 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (15 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 16/60] scsi: qla2xxx: Enable get_fw_version mailbox " Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:25   ` sashiko-bot
  2026-06-12 11:17   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 18/60] scsi: qla2xxx: Enable get_adapter_id mailbox for 29xx Nilesh Javali
                   ` (42 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Add IS_QLA29XX() to the BPM capability macros and to the
execute-firmware mailbox command so that NVMe enable, minimum
speed negotiation, 128 Gbps speed reporting, EDIF hardware
detection, and FW-semaphore retry logic all apply to 29xx
adapters.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_attr.c | 12 ++++++++++--
 drivers/scsi/qla2xxx/qla_def.h  |  5 +++--
 drivers/scsi/qla2xxx/qla_gs.c   | 14 +++++++++++---
 drivers/scsi/qla2xxx/qla_mbx.c  | 23 +++++++++++++----------
 4 files changed, 37 insertions(+), 17 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 3bf7123fe057..742becc0dadf 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1784,10 +1784,11 @@ qla2x00_min_supported_speed_show(struct device *dev,
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
 		return scnprintf(buf, PAGE_SIZE, "\n");
 
 	return scnprintf(buf, PAGE_SIZE, "%s\n",
+	    ha->min_supported_speed == 7 ? "128Gps" :
 	    ha->min_supported_speed == 6 ? "64Gps" :
 	    ha->min_supported_speed == 5 ? "32Gps" :
 	    ha->min_supported_speed == 4 ? "16Gps" :
@@ -1803,10 +1804,11 @@ qla2x00_max_supported_speed_show(struct device *dev,
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
 		return scnprintf(buf, PAGE_SIZE, "\n");
 
 	return scnprintf(buf, PAGE_SIZE, "%s\n",
+	    ha->max_supported_speed  == 3 ? "128Gps" :
 	    ha->max_supported_speed  == 2 ? "64Gps" :
 	    ha->max_supported_speed  == 1 ? "32Gps" :
 	    ha->max_supported_speed  == 0 ? "16Gps" : "unknown");
@@ -1887,6 +1889,7 @@ static const struct {
 	{ PORT_SPEED_16GB, "16" },
 	{ PORT_SPEED_32GB, "32" },
 	{ PORT_SPEED_64GB, "64" },
+	{ PORT_SPEED_128GB, "128" },
 	{ PORT_SPEED_10GB, "10" },
 };
 
@@ -2668,6 +2671,9 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
 	case PORT_SPEED_64GB:
 		speed = FC_PORTSPEED_64GBIT;
 		break;
+	case PORT_SPEED_128GB:
+		speed = FC_PORTSPEED_128GBIT;
+		break;
 	default:
 		speed = FC_PORTSPEED_UNKNOWN;
 		break;
@@ -3429,6 +3435,8 @@ qla2x00_get_host_supported_speeds(scsi_qla_host_t *vha, uint speeds)
 {
 	uint supported_speeds = FC_PORTSPEED_UNKNOWN;
 
+	if (speeds & FDMI_PORT_SPEED_128GB)
+		supported_speeds |= FC_PORTSPEED_128GBIT;
 	if (speeds & FDMI_PORT_SPEED_64GB)
 		supported_speeds |= FC_PORTSPEED_64GBIT;
 	if (speeds & FDMI_PORT_SPEED_32GB)
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 2b57782b3cd3..e93766e81480 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -4333,6 +4333,7 @@ struct qla_hw_data {
 #define PORT_SPEED_16GB 0x05
 #define PORT_SPEED_32GB 0x06
 #define PORT_SPEED_64GB 0x07
+#define PORT_SPEED_128GB 0x08
 #define PORT_SPEED_10GB	0x13
 	uint16_t	link_data_rate;         /* F/W operating speed */
 	uint16_t	set_data_rate;		/* Set by user */
@@ -5581,9 +5582,9 @@ struct sff_8247_a0 {
 /* BPM -- Buffer Plus Management support. */
 #define IS_BPM_CAPABLE(ha) \
 	(IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
-	 IS_QLA27XX(ha) || IS_QLA28XX(ha))
+	 IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
 #define IS_BPM_RANGE_CAPABLE(ha) \
-	(IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
+	(IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
 #define IS_BPM_ENABLED(vha) \
 	(ql2xautodetectsfp && !vha->vp_idx && IS_BPM_CAPABLE(vha->hw))
 
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 880cd73feaca..b69a001fd4da 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1508,12 +1508,18 @@ qla25xx_fdmi_port_speed_capability(struct qla_hw_data *ha)
 
 	if (IS_CNA_CAPABLE(ha))
 		return FDMI_PORT_SPEED_10GB;
-	if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) {
-		if (ha->max_supported_speed == 2) {
+	if (IS_QLA28XX(ha) || IS_QLA27XX(ha) || IS_QLA29XX(ha)) {
+		if (ha->max_supported_speed == 3) {
+			if (ha->min_supported_speed <= 7)
+				speeds |= FDMI_PORT_SPEED_128GB;
+		}
+		if (ha->max_supported_speed == 3 ||
+		    ha->max_supported_speed == 2) {
 			if (ha->min_supported_speed <= 6)
 				speeds |= FDMI_PORT_SPEED_64GB;
 		}
-		if (ha->max_supported_speed == 2 ||
+		if (ha->max_supported_speed == 3 ||
+		    ha->max_supported_speed == 2 ||
 		    ha->max_supported_speed == 1) {
 			if (ha->min_supported_speed <= 5)
 				speeds |= FDMI_PORT_SPEED_32GB;
@@ -1577,6 +1583,8 @@ qla25xx_fdmi_port_speed_currently(struct qla_hw_data *ha)
 		return FDMI_PORT_SPEED_32GB;
 	case PORT_SPEED_64GB:
 		return FDMI_PORT_SPEED_64GB;
+	case PORT_SPEED_128GB:
+		return FDMI_PORT_SPEED_128GB;
 	default:
 		return FDMI_PORT_SPEED_UNKNOWN;
 	}
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 0feb98b83293..52d70b61654c 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -699,6 +699,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
 {
 	int rval;
 	struct qla_hw_data *ha = vha->hw;
+	struct nvram_81xx *nv = ha->nvram;
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 	u8 semaphore = 0;
@@ -727,14 +728,13 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
 				    ha->lr_distance << LR_DIST_FW_POS;
 		}
 
-		if (ql2xnvmeenable && (IS_QLA27XX(ha) || IS_QLA28XX(ha)))
+		if (ql2xnvmeenable && (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)))
 			mcp->mb[4] |= NVME_ENABLE_FLAG;
 
-		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
-			struct nvram_81xx *nv = ha->nvram;
+		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 			/* set minimum speed if specified in nvram */
 			if (nv->min_supported_speed >= 2 &&
-			    nv->min_supported_speed <= 5) {
+			    nv->min_supported_speed <= 7) {
 				mcp->mb[4] |= BIT_4;
 				mcp->mb[11] |= nv->min_supported_speed & 0xF;
 				mcp->out_mb |= MBX_11;
@@ -772,7 +772,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
 	rval = qla2x00_mailbox_command(vha, mcp);
 
 	if (rval != QLA_SUCCESS) {
-		if (IS_QLA28XX(ha) && rval == QLA_COMMAND_ERROR &&
+		if ((IS_QLA28XX(ha) || IS_QLA29XX(ha)) && rval == QLA_COMMAND_ERROR &&
 		    mcp->mb[1] == 0x27 && retry) {
 			semaphore = 1;
 			retry--;
@@ -800,17 +800,20 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
 	ql_dbg(ql_dbg_mbx, vha, 0x119a,
 	    "fw_ability_mask=%x.\n", ha->fw_ability_mask);
 	ql_dbg(ql_dbg_mbx, vha, 0x1027, "exchanges=%x.\n", mcp->mb[1]);
-	if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
-		ha->max_supported_speed = mcp->mb[2] & (BIT_0|BIT_1);
+
+	if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
+		ha->max_supported_speed = mcp->mb[2] & (BIT_0|BIT_1|BIT_2|BIT_3);
 		ql_dbg(ql_dbg_mbx, vha, 0x119b, "max_supported_speed=%s.\n",
 		    ha->max_supported_speed == 0 ? "16Gps" :
 		    ha->max_supported_speed == 1 ? "32Gps" :
-		    ha->max_supported_speed == 2 ? "64Gps" : "unknown");
+		    ha->max_supported_speed == 2 ? "64Gps" :
+		    ha->max_supported_speed == 3 ? "128Gps" : "unknown");
 		if (vha->min_supported_speed) {
 			ha->min_supported_speed = mcp->mb[5] &
-			    (BIT_0 | BIT_1 | BIT_2);
+			    (BIT_0 | BIT_1 | BIT_2 | BIT_3);
 			ql_dbg(ql_dbg_mbx, vha, 0x119c,
 			    "min_supported_speed=%s.\n",
+			    ha->min_supported_speed == 7 ? "128Gps" :
 			    ha->min_supported_speed == 6 ? "64Gps" :
 			    ha->min_supported_speed == 5 ? "32Gps" :
 			    ha->min_supported_speed == 4 ? "16Gps" :
@@ -819,7 +822,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
 		}
 	}
 
-	if (IS_QLA28XX(ha) && (mcp->mb[5] & EDIF_HW_SUPPORT)) {
+	if ((IS_QLA28XX(ha) || IS_QLA29XX(ha)) && (mcp->mb[5] & EDIF_HW_SUPPORT)) {
 		ha->flags.edif_hw = 1;
 		ql_log(ql_log_info, vha, 0xffff,
 		    "%s: edif HW\n", __func__);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 18/60] scsi: qla2xxx: Enable get_adapter_id mailbox for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (16 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 17/60] scsi: qla2xxx: Extend execute_fw mailbox to include 29xx Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 11:18   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 19/60] scsi: qla2xxx: Enable init_firmware " Nilesh Javali
                   ` (41 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Add IS_QLA29XX() alongside the existing 27xx/28xx checks in
qla2x00_get_adapter_id() so that the additional mailbox
registers (buffer-to-buffer credit, SCM/EDC status) are read
on 29xx adapters.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_mbx.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 52d70b61654c..3fc08120fdf1 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -1772,7 +1772,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
 		mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
 	if (IS_FWI2_CAPABLE(vha->hw))
 		mcp->in_mb |= MBX_19|MBX_18|MBX_17|MBX_16;
-	if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw))
+	if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw) || IS_QLA29XX(vha->hw))
 		mcp->in_mb |= MBX_15|MBX_21|MBX_22|MBX_23;
 
 	mcp->tov = MBX_TOV_SECONDS;
@@ -1827,7 +1827,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
 			}
 		}
 
-		if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw)) {
+		if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw) || IS_QLA29XX(vha->hw)) {
 			vha->bbcr = mcp->mb[15];
 			if (mcp->mb[7] & SCM_EDC_ACC_RECEIVED) {
 				ql_log(ql_log_info, vha, 0x11a4,
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 19/60] scsi: qla2xxx: Enable init_firmware mailbox for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (17 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 18/60] scsi: qla2xxx: Enable get_adapter_id mailbox for 29xx Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 11:18   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 20/60] scsi: qla2xxx: Enable get_firmware_state " Nilesh Javali
                   ` (40 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

The init_firmware mailbox command needs 29xx adapter support for reading
back SFP information via mb3 and for validating SFP status on successful
firmware initialization. Add IS_QLA29XX() checks alongside the existing
27xx/28xx checks.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_mbx.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 3fc08120fdf1..9c78aa66e12b 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -1968,7 +1968,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
 
 	/* 1 and 2 should normally be captured. */
 	mcp->in_mb = MBX_2|MBX_1|MBX_0;
-	if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
+	if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
 		/* mb3 is additional info about the installed SFP. */
 		mcp->in_mb  |= MBX_3;
 	mcp->buf_size = size;
@@ -1992,7 +1992,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
 			    0x0104d, ha->ex_init_cb, sizeof(*ha->ex_init_cb));
 		}
 	} else {
-		if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+		if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 			if (mcp->mb[2] == 6 || mcp->mb[3] == 2)
 				ql_dbg(ql_dbg_mbx, vha, 0x119d,
 				    "Invalid SFP/Validation Failed\n");
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 20/60] scsi: qla2xxx: Enable get_firmware_state for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (18 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 19/60] scsi: qla2xxx: Enable init_firmware " Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 11:19   ` Hannes Reinecke
  2026-06-12 11:22   ` sashiko-bot
  2026-06-12  9:52 ` [PATCH v2 21/60] scsi: qla2xxx: Enable serdes, resource count and FCE trace " Nilesh Javali
                   ` (39 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Enable get_firmware_state mailbox command for 29xx adapters by adding
IS_QLA29XX() checks alongside existing IS_QLA27XX/IS_QLA28XX checks.
This ensures MBX_12 (MPI state) is properly set up and reported for
29xx adapters.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_attr.c | 2 +-
 drivers/scsi/qla2xxx/qla_mbx.c  | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 742becc0dadf..ee6bf8302991 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -2436,7 +2436,7 @@ qla2x00_mpi_fw_state_show(struct device *dev, struct device_attribute *attr,
 	u16 mpi_state;
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!(IS_QLA27XX(ha) || IS_QLA28XX(ha)))
+	if (!(IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)))
 		return scnprintf(buf, PAGE_SIZE,
 				"MPI state reporting is not supported for this HBA.\n");
 
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 9c78aa66e12b..a91ac59dd9c0 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -2283,7 +2283,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
 	else
 		mcp->in_mb = MBX_1|MBX_0;
 
-	if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+	if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 		mcp->mb[12] = 0;
 		mcp->out_mb |= MBX_12;
 		mcp->in_mb |= MBX_12;
@@ -2301,7 +2301,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
 		states[3] = mcp->mb[4];
 		states[4] = mcp->mb[5];
 		states[5] = mcp->mb[6];  /* DPORT status */
-		if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+		if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
 			states[11] = mcp->mb[12]; /* MPI state. */
 	}
 
@@ -2309,7 +2309,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
 		/*EMPTY*/
 		ql_dbg(ql_dbg_mbx, vha, 0x1055, "Failed=%x.\n", rval);
 	} else {
-		if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+		if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 			if (mcp->mb[2] == 6 || mcp->mb[3] == 2)
 				ql_dbg(ql_dbg_mbx, vha, 0x119e,
 				    "Invalid SFP/Validation Failed\n");
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 21/60] scsi: qla2xxx: Enable serdes, resource count and FCE trace for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (19 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 20/60] scsi: qla2xxx: Enable get_firmware_state " Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:38   ` sashiko-bot
  2026-06-12 11:19   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 22/60] scsi: qla2xxx: Enable set_els_cmds and echo_test " Nilesh Javali
                   ` (38 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

The 29xx adapters share the diagnostic and management interfaces
already supported on ISP27xx/28xx, but several family capability
gates still omitted IS_QLA29XX(), leaving these paths unreachable
on 29xx.

Add IS_QLA29XX() to the relevant checks so the following work on
29xx adapters:

  - read/write SerDes word mailbox commands for PHY register access.
  - get_resource_cnts requests MBX_12 to report the extended
    firmware resource counts.
  - FCE trace: the enable-FCE mailbox command, the "fce" and
    "fw_resource_count" debugfs nodes in qla2x00_dfs_setup(), the
    debugfs enable write in qla2x00_dfs_fce_write(), and the FCE DMA
    buffer allocation in qla2x00_alloc_fce_trace().

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_dfs.c  |  4 ++--
 drivers/scsi/qla2xxx/qla_init.c |  2 +-
 drivers/scsi/qla2xxx/qla_mbx.c  | 11 +++++++----
 3 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 43970caca7b3..177d47e92e49 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -497,7 +497,7 @@ qla2x00_dfs_fce_write(struct file *file, const char __user *buffer,
 	unsigned long enable;
 
 	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
-	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) {
+	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha)) {
 		ql_dbg(ql_dbg_user, vha, 0xd034,
 		       "this adapter does not support FCE.");
 		return -EINVAL;
@@ -698,7 +698,7 @@ qla2x00_dfs_setup(scsi_qla_host_t *vha)
 	struct qla_hw_data *ha = vha->hw;
 
 	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
-	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
 		goto out;
 
 	if (qla2x00_dfs_root)
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 20eb67096b0b..ae9cd5665469 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3733,7 +3733,7 @@ int qla2x00_alloc_fce_trace(scsi_qla_host_t *vha)
 		return -EINVAL;
 
 	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
-	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
 		return -EINVAL;
 
 	if (ha->fce) {
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index a91ac59dd9c0..d195723fc06b 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -3093,7 +3093,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha)
 	mcp->out_mb = MBX_0;
 	mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
 	if (IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
-	    IS_QLA27XX(ha) || IS_QLA28XX(ha))
+	    IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
+	    IS_QLA29XX(ha))
 		mcp->in_mb |= MBX_12;
 	mcp->tov = MBX_TOV_SECONDS;
 	mcp->flags = 0;
@@ -3565,7 +3566,8 @@ qla2x00_write_serdes_word(scsi_qla_host_t *vha, uint16_t addr, uint16_t data)
 	mbx_cmd_t *mcp = &mc;
 
 	if (!IS_QLA25XX(vha->hw) && !IS_QLA2031(vha->hw) &&
-	    !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw))
+	    !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw) &&
+	    !IS_QLA29XX(vha->hw))
 		return QLA_FUNCTION_FAILED;
 
 	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1182,
@@ -3604,7 +3606,8 @@ qla2x00_read_serdes_word(scsi_qla_host_t *vha, uint16_t addr, uint16_t *data)
 	mbx_cmd_t *mcp = &mc;
 
 	if (!IS_QLA25XX(vha->hw) && !IS_QLA2031(vha->hw) &&
-	    !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw))
+	    !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw) &&
+	    !IS_QLA29XX(vha->hw))
 		return QLA_FUNCTION_FAILED;
 
 	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1185,
@@ -3874,7 +3877,7 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma,
 
 	if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw) &&
 	    !IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
-	    !IS_QLA28XX(vha->hw))
+	    !IS_QLA28XX(vha->hw) && !IS_QLA29XX(vha->hw))
 		return QLA_FUNCTION_FAILED;
 
 	if (unlikely(pci_channel_offline(vha->hw->pdev)))
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 22/60] scsi: qla2xxx: Enable set_els_cmds and echo_test for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (20 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 21/60] scsi: qla2xxx: Enable serdes, resource count and FCE trace " Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 11:20   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 23/60] scsi: qla2xxx: Add support for QLA29XX in data rate functions Nilesh Javali
                   ` (37 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Add IS_QLA29XX() checks to qla25xx_set_els_cmds_supported() and
qla2x00_echo_test() so that ELS command support and echo test
diagnostics are available on 29xx series adapters.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_mbx.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index d195723fc06b..a8dd01cb9a9a 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -5087,7 +5087,8 @@ qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha)
 	struct qla_hw_data *ha = vha->hw;
 
 	if (!IS_QLA25XX(ha) && !IS_QLA2031(ha) &&
-	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha) &&
+	    !IS_QLA29XX(ha))
 		return QLA_SUCCESS;
 
 	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1197,
@@ -5492,10 +5493,10 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
 
 	mcp->in_mb = MBX_0;
 	if (IS_CNA_CAPABLE(ha) || IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
-	    IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
+	    IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
 		mcp->in_mb |= MBX_1;
 	if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
-	    IS_QLA28XX(ha))
+	    IS_QLA28XX(ha) || IS_QLA29XX(ha))
 		mcp->in_mb |= MBX_3;
 
 	mcp->tov = MBX_TOV_SECONDS;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 23/60] scsi: qla2xxx: Add support for QLA29XX in data rate functions
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (21 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 22/60] scsi: qla2xxx: Enable set_els_cmds and echo_test " Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 11:20   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 24/60] scsi: qla2xxx: Enable qla2x00_shutdown for 29xx Nilesh Javali
                   ` (36 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Enhance the qla2x00_set_data_rate and qla2x00_get_data_rate
functions to include checks for the QLA29XX series adapters.
This modification ensures that the mailbox commands are correctly
configured for the 29xx series, improving functionality and
compatibility.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_attr.c | 2 +-
 drivers/scsi/qla2xxx/qla_mbx.c  | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index ee6bf8302991..37478af9cdec 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1824,7 +1824,7 @@ qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
 	int mode = QLA_SET_DATA_RATE_LR;
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) {
+	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha)) {
 		ql_log(ql_log_warn, vha, 0x70d8,
 		    "Speed setting not supported \n");
 		return -EINVAL;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index a8dd01cb9a9a..c073dc35ef8e 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -5683,7 +5683,7 @@ qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode)
 
 	mcp->out_mb = MBX_2|MBX_1|MBX_0;
 	mcp->in_mb = MBX_2|MBX_1|MBX_0;
-	if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
+	if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
 		mcp->in_mb |= MBX_4|MBX_3;
 	mcp->tov = MBX_TOV_SECONDS;
 	mcp->flags = 0;
@@ -5721,7 +5721,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
 	mcp->mb[1] = QLA_GET_DATA_RATE;
 	mcp->out_mb = MBX_1|MBX_0;
 	mcp->in_mb = MBX_2|MBX_1|MBX_0;
-	if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
+	if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
 		mcp->in_mb |= MBX_4|MBX_3;
 	mcp->tov = MBX_TOV_SECONDS;
 	mcp->flags = 0;
@@ -5733,7 +5733,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
 		if (mcp->mb[1] != 0x7)
 			ha->link_data_rate = mcp->mb[1];
 
-		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 			if (mcp->mb[4] & BIT_0)
 				ql_log(ql_log_info, vha, 0x11a2,
 				    "FEC=enabled (data rate).\n");
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 24/60] scsi: qla2xxx: Enable qla2x00_shutdown for 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (22 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 23/60] scsi: qla2xxx: Add support for QLA29XX in data rate functions Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 11:21   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 25/60] scsi: qla2xxx: Use ring-slot helpers in __qla2x00_alloc_iocbs Nilesh Javali
                   ` (35 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Enable qla2x00_shutdown for 29xx adapter by adding IS_QLA29XX check
to the shutdown path that performs firmware abort cleanup.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_os.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index ef105ae6af41..a3e2c0a95a99 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -3840,7 +3840,7 @@ qla2x00_shutdown(struct pci_dev *pdev)
 		qla2x00_disable_eft_trace(vha);
 
 	if (IS_QLA25XX(ha) ||  IS_QLA2031(ha) || IS_QLA27XX(ha) ||
-	    IS_QLA28XX(ha)) {
+	    IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
 		if (ha->flags.fw_started)
 			qla2x00_abort_isp_cleanup(vha);
 	} else {
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 25/60] scsi: qla2xxx: Use ring-slot helpers in __qla2x00_alloc_iocbs
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (23 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 24/60] scsi: qla2xxx: Enable qla2x00_shutdown for 29xx Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:41   ` sashiko-bot
  2026-06-12 11:21   ` Hannes Reinecke
  2026-06-12  9:52 ` [PATCH v2 26/60] scsi: qla2xxx: Add support for QLA29XX in memory allocation Nilesh Javali
                   ` (34 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

__qla2x00_alloc_iocbs() open-codes ring pointer selection and entry
size based on IS_QLA29XX(ha): 29xx reaches the slot via ring_ext_ptr
and zeroes REQUEST_ENTRY_SIZE_EXT bytes, while other adapters use
ring_ptr with REQUEST_ENTRY_SIZE bytes.

Replace the two branches with the qla_req_ring_slot() and
qla_req_entry_size() helpers, and initialise pkt at declaration.
The IS_QLAFX00 register-mapped writes remain guarded because
IS_QLAFX00 and IS_QLA29XX cannot be true simultaneously.

No functional change: the bytes written to the firmware-visible IOCB
are identical.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_iocb.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 4d22e059015f..c219cafe4f28 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2405,10 +2405,9 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp)
 	struct req_que *req = qpair->req;
 	device_reg_t *reg = ISP_QUE_REG(ha, req->id);
 	uint32_t handle;
-	request_t *pkt;
 	uint16_t cnt, req_cnt;
+	request_t *pkt = NULL;
 
-	pkt = NULL;
 	req_cnt = 1;
 	handle = 0;
 
@@ -2469,13 +2468,8 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp)
 	 * layout-compatible once we return the pkt as request_t *.
 	 */
 	req->cnt -= req_cnt;
-	if (IS_QLA29XX(ha)) {
-		pkt = (request_t *)req->ring_ext_ptr;
-		memset(pkt, 0, REQUEST_ENTRY_SIZE_EXT);
-	} else {
-		pkt = req->ring_ptr;
-		memset(pkt, 0, REQUEST_ENTRY_SIZE);
-	}
+	pkt = qla_req_ring_slot(ha, req);
+	memset(pkt, 0, qla_req_entry_size(ha));
 	if (IS_QLAFX00(ha)) {
 		wrt_reg_byte((u8 __force __iomem *)&pkt->entry_count, req_cnt);
 		wrt_reg_dword((__le32 __force __iomem *)&pkt->handle, handle);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 26/60] scsi: qla2xxx: Add support for QLA29XX in memory allocation
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (24 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 25/60] scsi: qla2xxx: Use ring-slot helpers in __qla2x00_alloc_iocbs Nilesh Javali
@ 2026-06-12  9:52 ` Nilesh Javali
  2026-06-12 10:40   ` sashiko-bot
  2026-06-12 11:22   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 27/60] scsi: qla2xxx: Refactor marker IOCB handling for 29xx series Nilesh Javali
                   ` (33 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:52 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Enhance the qla2x00_mem_alloc function to include checks for
QLA29XX adapters.  This modification updates the conditions for
memory allocation and cleanup, ensuring proper handling of the
new adapter series alongside existing QLA27XX and QLA28XX checks.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_os.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index a3e2c0a95a99..3ac48eeb9f69 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -4285,7 +4285,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	if (!ha->srb_mempool)
 		goto fail_free_gid_list;
 
-	if (IS_P3P_TYPE(ha) || IS_QLA27XX(ha) || (ql2xsecenable && IS_QLA28XX(ha))) {
+	if (IS_P3P_TYPE(ha) || IS_QLA27XX(ha) ||
+	    (ql2xsecenable && (IS_QLA28XX(ha) || IS_QLA29XX(ha)))) {
 		/* Allocate cache for CT6 Ctx. */
 		if (!ctx_cachep) {
 			ctx_cachep = kmem_cache_create("qla2xxx_ctx",
@@ -4319,7 +4320,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	    "init_cb=%p gid_list=%p, srb_mempool=%p s_dma_pool=%p.\n",
 	    ha->init_cb, ha->gid_list, ha->srb_mempool, ha->s_dma_pool);
 
-	if (IS_P3P_TYPE(ha) || ql2xenabledif || (IS_QLA28XX(ha) && ql2xsecenable)) {
+	if (IS_P3P_TYPE(ha) || ql2xenabledif ||
+	    ((IS_QLA28XX(ha) || IS_QLA29XX(ha)) && ql2xsecenable)) {
 		ha->dl_dma_pool = dma_pool_create(name, &ha->pdev->dev,
 			DSD_LIST_DMA_POOL_SIZE, 8, 0);
 		if (!ha->dl_dma_pool) {
@@ -4681,12 +4683,12 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
 	}
 
 fail_dif_bundl_dma_pool:
-	if (IS_QLA82XX(ha) || ql2xenabledif) {
+	if (IS_QLA82XX(ha) || IS_QLA29XX(ha) || ql2xenabledif) {
 		dma_pool_destroy(ha->fcp_cmnd_dma_pool);
 		ha->fcp_cmnd_dma_pool = NULL;
 	}
 fail_dl_dma_pool:
-	if (IS_QLA82XX(ha) || ql2xenabledif) {
+	if (IS_QLA82XX(ha) || IS_QLA29XX(ha) || ql2xenabledif) {
 		dma_pool_destroy(ha->dl_dma_pool);
 		ha->dl_dma_pool = NULL;
 	}
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 27/60] scsi: qla2xxx: Refactor marker IOCB handling for 29xx series
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (25 preceding siblings ...)
  2026-06-12  9:52 ` [PATCH v2 26/60] scsi: qla2xxx: Add support for QLA29XX in memory allocation Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:36   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 28/60] scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters Nilesh Javali
                   ` (32 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Rework __qla2x00_marker() and qla_marker_iocb() for QLA29XX extended
marker IOCB (128-byte) support.  The extended layout (mrk_entry_24xx_ext)
overlays mrk_entry_24xx through 'lun', so the common header fields
(entry_type, modifier, nport_handle, lun, handle) are written through a
single struct mrk_entry_24xx pointer; only vp_index, which differs in
width (u8 in 24xx vs __le16 in the ext layout), needs a stride-aware
IS_QLA29XX() branch.

 - Allocate the IOCB once via __qla2x00_alloc_iocbs() and cast to
   struct mrk_entry_24xx, eliminating duplicated alloc/error paths.
 - Branch only on vp_index assignment where layout diverges.
 - Update qla_marker_iocb_entry() in qla_isr.c to accept void *pkt
   so it handles both 64-byte and 128-byte marker completions.
 - Add BUILD_BUG_ON size checks for mrk_entry_ext_t (128) and
   struct mrk_entry_24xx_ext (128).

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_def.h  |  2 +-
 drivers/scsi/qla2xxx/qla_iocb.c | 84 ++++++++++++++++-----------------
 drivers/scsi/qla2xxx/qla_isr.c  |  7 +--
 drivers/scsi/qla2xxx/qla_os.c   |  1 +
 4 files changed, 48 insertions(+), 46 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index e93766e81480..0bbe2bae7101 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -577,7 +577,7 @@ struct srb_iocb {
 			__le16 comp_status;
 
 			uint8_t modifier;
-			uint8_t vp_index;
+			uint16_t vp_index;
 			uint16_t loop_id;
 		} tmf;
 		struct {
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c219cafe4f28..595fe78920ae 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -518,64 +518,49 @@ static int
 __qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair,
     uint16_t loop_id, uint64_t lun, uint8_t type)
 {
-	mrk_entry_t *mrk;
-	struct mrk_entry_24xx *mrk24 = NULL;
-	struct req_que *req = qpair->req;
 	struct qla_hw_data *ha = vha->hw;
+	struct mrk_entry_24xx *mrk24;
+	struct req_que *req = qpair->req;
 	scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
 
-	mrk = (mrk_entry_t *)__qla2x00_alloc_iocbs(qpair, NULL);
-	if (mrk == NULL) {
-		ql_log(ql_log_warn, base_vha, 0x3026,
-		    "Failed to allocate Marker IOCB.\n");
-
-		return (QLA_FUNCTION_FAILED);
-	}
-
 	/*
-	 * 29xx uses the extended marker IOCB (128 bytes) with a __le16
-	 * vp_index field.  The first 64 bytes of mrk_entry_24xx_ext are
-	 * layout-compatible with mrk_entry_24xx except for the vp_index
-	 * storage, which differs in width and offset, so handle it via
-	 * a dedicated branch.
+	 * FWI2-capable adapters use the 24xx marker layout; 29xx uses the
+	 * extended marker IOCB (128 bytes) whose first 64 bytes overlay
+	 * mrk_entry_24xx through 'lun', so the common header is written
+	 * through a struct mrk_entry_24xx * view and only vp_index (u8 vs
+	 * __le16) needs a stride-aware branch.  Pre-FWI2 adapters
+	 * (ISP21xx/22xx/23xx) use the legacy mrk_entry_t layout with a
+	 * 2-byte target ID and a 16-bit LUN.
 	 */
-	if (IS_QLA29XX(ha)) {
-		struct mrk_entry_24xx_ext *mrk29 =
-			(struct mrk_entry_24xx_ext *)mrk;
-
-		mrk29->entry_type = MARKER_TYPE;
-		mrk29->modifier = type;
-		if (type != MK_SYNC_ALL) {
-			mrk29->nport_handle = cpu_to_le16(loop_id);
-			int_to_scsilun(lun, (struct scsi_lun *)&mrk29->lun);
-			host_to_fcp_swap(mrk29->lun, sizeof(mrk29->lun));
-			mrk29->vp_index = cpu_to_le16(vha->vp_idx);
-		}
-		mrk29->handle = QLA_SKIP_HANDLE;
-		goto post;
+	mrk24 = __qla2x00_alloc_iocbs(qpair, NULL);
+	if (!mrk24) {
+		ql_log(ql_log_warn, base_vha, 0x3026,
+		    "Failed to allocate Marker IOCB.\n");
+		return QLA_FUNCTION_FAILED;
 	}
 
-	mrk24 = (struct mrk_entry_24xx *)mrk;
-
-	mrk->entry_type = MARKER_TYPE;
-	mrk->modifier = type;
+	mrk24->entry_type = MARKER_TYPE;
+	mrk24->modifier = type;
 	if (type != MK_SYNC_ALL) {
 		if (IS_FWI2_CAPABLE(ha)) {
 			mrk24->nport_handle = cpu_to_le16(loop_id);
 			int_to_scsilun(lun, (struct scsi_lun *)&mrk24->lun);
 			host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
-			mrk24->vp_index = vha->vp_idx;
+			if (IS_QLA29XX(ha))
+				((struct mrk_entry_24xx_ext *)mrk24)->vp_index =
+				    cpu_to_le16(vha->vp_idx);
+			else
+				mrk24->vp_index = vha->vp_idx;
 		} else {
+			mrk_entry_t *mrk = (mrk_entry_t *)mrk24;
+
 			SET_TARGET_ID(ha, mrk->target, loop_id);
 			mrk->lun = cpu_to_le16((uint16_t)lun);
 		}
 	}
-
 	if (IS_FWI2_CAPABLE(ha))
 		mrk24->handle = QLA_SKIP_HANDLE;
 
-post:
-
 	wmb();
 
 	qla2x00_start_iocbs(vha, req);
@@ -4046,16 +4031,31 @@ static int qla_get_iocbs_resource(struct srb *sp)
 }
 
 static void
-qla_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk)
+qla_marker_iocb(srb_t *sp, void *pkt)
 {
+	struct qla_hw_data *ha = sp->vha->hw;
+	struct mrk_entry_24xx *mrk = pkt;
+
+	/*
+	 * mrk_entry_24xx_ext overlays mrk_entry_24xx through 'lun', so
+	 * the common-header writes go through the 24xx-typed pointer;
+	 * only vp_index (u8 in 24xx, __le16 in the ext layout) needs a
+	 * stride-aware branch.
+	 */
 	mrk->entry_type = MARKER_TYPE;
 	mrk->modifier = sp->u.iocb_cmd.u.tmf.modifier;
 	mrk->handle = make_handle(sp->qpair->req->id, sp->handle);
 	if (sp->u.iocb_cmd.u.tmf.modifier != MK_SYNC_ALL) {
-		mrk->nport_handle = cpu_to_le16(sp->u.iocb_cmd.u.tmf.loop_id);
-		int_to_scsilun(sp->u.iocb_cmd.u.tmf.lun, (struct scsi_lun *)&mrk->lun);
+		mrk->nport_handle =
+		    cpu_to_le16(sp->u.iocb_cmd.u.tmf.loop_id);
+		int_to_scsilun(sp->u.iocb_cmd.u.tmf.lun,
+		    (struct scsi_lun *)&mrk->lun);
 		host_to_fcp_swap(mrk->lun, sizeof(mrk->lun));
-		mrk->vp_index = sp->u.iocb_cmd.u.tmf.vp_index;
+		if (IS_QLA29XX(ha))
+			((struct mrk_entry_24xx_ext *)pkt)->vp_index =
+			    cpu_to_le16(sp->u.iocb_cmd.u.tmf.vp_index);
+		else
+			mrk->vp_index = sp->u.iocb_cmd.u.tmf.vp_index;
 	}
 }
 
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index b8397912cb04..e95fb0e59f38 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -3917,9 +3917,10 @@ static int qla_chk_cont_iocb_avail(struct scsi_qla_host *vha,
 }
 
 static void qla_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
-	struct mrk_entry_24xx *pkt)
+	void *pkt)
 {
 	const char func[] = "MRK-IOCB";
+	struct mrk_entry_24xx *mrk = pkt;
 	srb_t *sp;
 	int res = QLA_SUCCESS;
 
@@ -3930,7 +3931,7 @@ static void qla_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
 	if (!sp)
 		return;
 
-	if (pkt->entry_status) {
+	if (mrk->entry_status) {
 		ql_dbg(ql_dbg_taskm, vha, 0x8025, "marker failure.\n");
 		res = QLA_COMMAND_ERROR;
 	}
@@ -4049,7 +4050,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 					(struct nack_to_isp *)pkt);
 			break;
 		case MARKER_TYPE:
-			qla_marker_iocb_entry(vha, rsp->req, (struct mrk_entry_24xx *)pkt);
+			qla_marker_iocb_entry(vha, rsp->req, pkt);
 			break;
 		case ABORT_IOCB_TYPE:
 			qla24xx_abort_iocb_entry(vha, rsp->req,
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 3ac48eeb9f69..9dd181feeb87 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8370,6 +8370,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct mbx_entry) != 64);
 	BUILD_BUG_ON(sizeof(struct mid_init_cb_24xx) != 5252);
 	BUILD_BUG_ON(sizeof(struct mrk_entry_24xx) != 64);
+	BUILD_BUG_ON(sizeof(struct mrk_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct nvram_24xx) != 512);
 	BUILD_BUG_ON(sizeof(struct nvram_81xx) != 512);
 	BUILD_BUG_ON(sizeof(struct pt_ls4_request) != 64);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 28/60] scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (26 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 27/60] scsi: qla2xxx: Refactor marker IOCB handling for 29xx series Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 10:54   ` sashiko-bot
  2026-06-12 11:47   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 29/60] scsi: qla2xxx: Update handling of status entries for 29xx series Nilesh Javali
                   ` (31 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

29xx adapters use 128-byte response queue entries
(sts_cont_entry_ext_t) instead of 64-byte (sts_cont_entry_t).  Update
all status continuation IOCB processing paths to branch on
IS_QLA29XX() and use the correct entry type and data payload size.

The affected functions are __qla_copy_purex_to_buffer(),
qla27xx_copy_multiple_pkt(), qla2x00_status_cont_entry(), and their
call sites in qla2x00_process_response_entry() and
qla24xx_process_response_queue().

Change qla2x00_status_cont_entry() to accept void * so callers no
longer need an explicit cast and the function can internally select the
right structure based on the adapter type.

Add BUILD_BUG_ON for sts_cont_entry_ext_t size (128 bytes).

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_isr.c | 192 +++++++++++++++++++++++----------
 drivers/scsi/qla2xxx/qla_os.c  |   1 +
 2 files changed, 139 insertions(+), 54 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index e95fb0e59f38..c18ee2459f5b 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -19,7 +19,7 @@
 
 static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
 static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
-static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
+static void qla2x00_status_cont_entry(struct rsp_que *, void *);
 static int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
 	sts_entry_t *);
 static void qla27xx_process_purex_fpin(struct scsi_qla_host *vha,
@@ -231,8 +231,15 @@ int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
 	void **pkt, struct rsp_que **rsp, u8 *buf, u32 buf_len)
 {
 	struct purex_entry_24xx *purex = *pkt;
+	struct qla_hw_data *ha = vha->hw;
 	struct rsp_que *rsp_q = *rsp;
 	sts_cont_entry_t *new_pkt;
+	struct sts_cont_entry_ext *new_pkt29;
+	size_t payload_size = IS_QLA29XX(ha) ?
+		sizeof_field(struct purex_entry_24xx_ext, els_frame_payload) :
+		sizeof_field(struct purex_entry_24xx, els_frame_payload);
+	u8 *data;
+	u32 data_sz;
 	uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0;
 	uint16_t buffer_copy_offset = 0;
 	uint16_t entry_count_remaining;
@@ -271,21 +278,37 @@ int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
 
 	do {
 		while ((total_bytes > 0) && (entry_count_remaining > 0)) {
-			new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
-			*pkt = new_pkt;
+			if (IS_QLA29XX(ha)) {
+				new_pkt29 = (struct sts_cont_entry_ext *)rsp_q->ring_ptr;
+				*pkt = new_pkt29;
+
+				if (new_pkt29->entry_type != STATUS_CONT_TYPE) {
+					ql_log(ql_log_warn, vha, 0x507a,
+					    "Unexpected IOCB type, partial data 0x%x\n",
+					    buffer_copy_offset);
+					break;
+				}
+				data = new_pkt29->data;
+				data_sz = sizeof(new_pkt29->data);
+			} else {
+				new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
+				*pkt = new_pkt;
 
-			if (new_pkt->entry_type != STATUS_CONT_TYPE) {
-				ql_log(ql_log_warn, vha, 0x507a,
-				    "Unexpected IOCB type, partial data 0x%x\n",
-				    buffer_copy_offset);
-				break;
+				if (new_pkt->entry_type != STATUS_CONT_TYPE) {
+					ql_log(ql_log_warn, vha, 0x507a,
+					    "Unexpected IOCB type, partial data 0x%x\n",
+					    buffer_copy_offset);
+					break;
+				}
+				data = new_pkt->data;
+				data_sz = sizeof(new_pkt->data);
 			}
 
 			qla_rsp_ring_advance(rsp_q);
-			no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
-			    sizeof(new_pkt->data) : pending_bytes;
+			no_bytes = (pending_bytes > data_sz) ?
+			    data_sz : pending_bytes;
 			if ((buffer_copy_offset + no_bytes) <= total_bytes) {
-				memcpy((buf + buffer_copy_offset), new_pkt->data,
+				memcpy((buf + buffer_copy_offset), data,
 				    no_bytes);
 				buffer_copy_offset += no_bytes;
 				pending_bytes -= no_bytes;
@@ -294,11 +317,16 @@ int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
 				ql_log(ql_log_warn, vha, 0x5044,
 				    "Attempt to copy more that we got, optimizing..%x\n",
 				    buffer_copy_offset);
-				memcpy((buf + buffer_copy_offset), new_pkt->data,
+				memcpy((buf + buffer_copy_offset), data,
 				    total_bytes - buffer_copy_offset);
 			}
 
-			((response_t *)new_pkt)->signature = RESPONSE_PROCESSED;
+			if (IS_QLA29XX(ha))
+				((struct response_ext *)new_pkt29)->signature =
+				    RESPONSE_PROCESSED;
+			else
+				((response_t *)new_pkt)->signature =
+				    RESPONSE_PROCESSED;
 			/* flush signature */
 			wmb();
 		}
@@ -844,13 +872,15 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
 {
 	struct purex_entry_24xx *purex = NULL;
 	struct pt_ls4_rx_unsol *purls = NULL;
+	struct qla_hw_data *ha = vha->hw;
 	struct rsp_que *rsp_q = *rsp;
-	sts_cont_entry_t *new_pkt;
 	uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0;
 	uint16_t buffer_copy_offset = 0, payload_size = 0;
 	uint16_t entry_count, entry_count_remaining;
 	struct purex_item *item;
 	void *iocb_pkt = NULL;
+	u8 *data;
+	u32 data_sz;
 
 	if (is_purls) {
 		purls = *pkt;
@@ -906,28 +936,33 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
 				continue;
 			}
 
-			new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
-			*pkt = new_pkt;
+			*pkt = rsp_q->ring_ptr;
+			if (IS_QLA29XX(ha)) {
+				struct sts_cont_entry_ext *p = *pkt;
+
+				data = p->data;
+				data_sz = sizeof(p->data);
+			} else {
+				sts_cont_entry_t *p = *pkt;
+
+				data = p->data;
+				data_sz = sizeof(p->data);
+			}
 
-			if (new_pkt->entry_type != STATUS_CONT_TYPE) {
+			if (((sts_cont_entry_t *)*pkt)->entry_type !=
+			    STATUS_CONT_TYPE) {
 				ql_log(ql_log_warn, vha, 0x507a,
 				       "Unexpected IOCB type, partial data 0x%x\n",
 				       buffer_copy_offset);
 				break;
 			}
 
-			rsp_q->ring_index++;
-			if (rsp_q->ring_index == rsp_q->length) {
-				rsp_q->ring_index = 0;
-				rsp_q->ring_ptr = rsp_q->ring;
-			} else {
-				rsp_q->ring_ptr++;
-			}
-			no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
-				sizeof(new_pkt->data) : pending_bytes;
+			qla_rsp_ring_advance(rsp_q);
+			no_bytes = (pending_bytes > data_sz) ?
+				   data_sz : pending_bytes;
 			if ((buffer_copy_offset + no_bytes) <= total_bytes) {
-				memcpy(((uint8_t *)iocb_pkt + buffer_copy_offset),
-				       new_pkt->data, no_bytes);
+				memcpy(((uint8_t *)iocb_pkt +
+					buffer_copy_offset), data, no_bytes);
 				buffer_copy_offset += no_bytes;
 				pending_bytes -= no_bytes;
 				--entry_count_remaining;
@@ -935,12 +970,12 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
 				ql_log(ql_log_warn, vha, 0x5044,
 				       "Attempt to copy more that we got, optimizing..%x\n",
 				       buffer_copy_offset);
-				memcpy(((uint8_t *)iocb_pkt + buffer_copy_offset),
-				       new_pkt->data,
-				       total_bytes - buffer_copy_offset);
+				memcpy(((uint8_t *)iocb_pkt +
+					buffer_copy_offset), data,
+					total_bytes - buffer_copy_offset);
 			}
 
-			((response_t *)new_pkt)->signature = RESPONSE_PROCESSED;
+			((response_t *)*pkt)->signature = RESPONSE_PROCESSED;
 			wmb();
 		}
 
@@ -1144,8 +1179,15 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
 		      struct rsp_que **rsp)
 {
 	struct purex_entry_24xx *purex = *pkt;
+	struct qla_hw_data *ha = vha->hw;
 	struct rsp_que *rsp_q = *rsp;
 	sts_cont_entry_t *new_pkt;
+	struct sts_cont_entry_ext *new_pkt29;
+	size_t payload_size = IS_QLA29XX(ha) ?
+		sizeof_field(struct purex_entry_24xx_ext, els_frame_payload) :
+		sizeof_field(struct purex_entry_24xx, els_frame_payload);
+	u8 *data;
+	u32 data_sz;
 	uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0;
 	uint16_t buffer_copy_offset = 0;
 	uint16_t entry_count, entry_count_remaining;
@@ -1160,8 +1202,8 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
 
 	pending_bytes = total_bytes;
 	entry_count = entry_count_remaining = purex->entry_count;
-	no_bytes = (pending_bytes > sizeof(purex->els_frame_payload))  ?
-		   sizeof(purex->els_frame_payload) : pending_bytes;
+	no_bytes = (pending_bytes > payload_size) ?
+		   payload_size : pending_bytes;
 	ql_log(ql_log_info, vha, 0x509a,
 	       "FPIN ELS, frame_size 0x%x, entry count %d\n",
 	       total_bytes, entry_count);
@@ -1172,7 +1214,13 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
 
 	fpin_pkt = &item->iocb;
 
-	memcpy(fpin_pkt, &purex->els_frame_payload[0], no_bytes);
+	if (IS_QLA29XX(ha)) {
+		struct purex_entry_24xx_ext *purex_ext = *pkt;
+
+		memcpy(fpin_pkt, &purex_ext->els_frame_payload[0], no_bytes);
+	} else {
+		memcpy(fpin_pkt, &purex->els_frame_payload[0], no_bytes);
+	}
 	buffer_copy_offset += no_bytes;
 	pending_bytes -= no_bytes;
 	--entry_count_remaining;
@@ -1190,22 +1238,39 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
 				continue;
 			}
 
-			new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
-			*pkt = new_pkt;
+			if (IS_QLA29XX(ha)) {
+				new_pkt29 =
+				    (struct sts_cont_entry_ext *)rsp_q->ring_ptr;
+				*pkt = new_pkt29;
 
-			if (new_pkt->entry_type != STATUS_CONT_TYPE) {
-				ql_log(ql_log_warn, vha, 0x507a,
-				       "Unexpected IOCB type, partial data 0x%x\n",
-				       buffer_copy_offset);
-				break;
+				if (new_pkt29->entry_type != STATUS_CONT_TYPE) {
+					ql_log(ql_log_warn, vha, 0x507a,
+					       "Unexpected IOCB type, partial data 0x%x\n",
+					       buffer_copy_offset);
+					break;
+				}
+				data = new_pkt29->data;
+				data_sz = sizeof(new_pkt29->data);
+			} else {
+				new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
+				*pkt = new_pkt;
+
+				if (new_pkt->entry_type != STATUS_CONT_TYPE) {
+					ql_log(ql_log_warn, vha, 0x507a,
+					       "Unexpected IOCB type, partial data 0x%x\n",
+					       buffer_copy_offset);
+					break;
+				}
+				data = new_pkt->data;
+				data_sz = sizeof(new_pkt->data);
 			}
 
 			qla_rsp_ring_advance(rsp_q);
-			no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
-			    sizeof(new_pkt->data) : pending_bytes;
+			no_bytes = (pending_bytes > data_sz) ?
+			    data_sz : pending_bytes;
 			if ((buffer_copy_offset + no_bytes) <= total_bytes) {
 				memcpy(((uint8_t *)fpin_pkt +
-				    buffer_copy_offset), new_pkt->data,
+				    buffer_copy_offset), data,
 				    no_bytes);
 				buffer_copy_offset += no_bytes;
 				pending_bytes -= no_bytes;
@@ -1215,11 +1280,16 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
 				       "Attempt to copy more that we got, optimizing..%x\n",
 				       buffer_copy_offset);
 				memcpy(((uint8_t *)fpin_pkt +
-				    buffer_copy_offset), new_pkt->data,
+				    buffer_copy_offset), data,
 				    total_bytes - buffer_copy_offset);
 			}
 
-			((response_t *)new_pkt)->signature = RESPONSE_PROCESSED;
+			if (IS_QLA29XX(ha))
+				((struct response_ext *)new_pkt29)->signature =
+				    RESPONSE_PROCESSED;
+			else
+				((response_t *)new_pkt)->signature =
+				    RESPONSE_PROCESSED;
 			wmb();
 		}
 
@@ -2918,7 +2988,7 @@ static void qla2x00_process_response_entry(struct scsi_qla_host *vha,
 						sts22_entry->handle[cnt]);
 		break;
 	case STATUS_CONT_TYPE:
-		qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
+		qla2x00_status_cont_entry(rsp, pkt);
 		break;
 	case MBX_IOCB_TYPE:
 		qla2x00_mbx_iocb_entry(vha, rsp->req, (struct mbx_entry *)pkt);
@@ -3682,7 +3752,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
  * Extended sense data.
  */
 static void
-qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
+qla2x00_status_cont_entry(struct rsp_que *rsp, void *pkt)
 {
 	uint8_t	sense_sz = 0;
 	struct qla_hw_data *ha = rsp->hw;
@@ -3691,6 +3761,8 @@ qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
 	struct scsi_cmnd *cp;
 	uint32_t sense_len;
 	uint8_t *sense_ptr;
+	u8 *data;
+	u32 data_sz;
 
 	if (!sp || !GET_CMD_SENSE_LEN(sp))
 		return;
@@ -3707,15 +3779,27 @@ qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
 		return;
 	}
 
-	if (sense_len > sizeof(pkt->data))
-		sense_sz = sizeof(pkt->data);
+	if (IS_QLA29XX(ha)) {
+		struct sts_cont_entry_ext *pkt29 = pkt;
+
+		data = pkt29->data;
+		data_sz = sizeof(pkt29->data);
+	} else {
+		sts_cont_entry_t *sts_pkt = pkt;
+
+		data = sts_pkt->data;
+		data_sz = sizeof(sts_pkt->data);
+	}
+
+	if (sense_len > data_sz)
+		sense_sz = data_sz;
 	else
 		sense_sz = sense_len;
 
 	/* Move sense data. */
 	if (IS_FWI2_CAPABLE(ha))
-		host_to_fcp_swap(pkt->data, sizeof(pkt->data));
-	memcpy(sense_ptr, pkt->data, sense_sz);
+		host_to_fcp_swap(data, data_sz);
+	memcpy(sense_ptr, data, sense_sz);
 	ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302c,
 		sense_ptr, sense_sz);
 
@@ -3997,7 +4081,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 			qla2x00_status_entry(vha, rsp, pkt);
 			break;
 		case STATUS_CONT_TYPE:
-			qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
+			qla2x00_status_cont_entry(rsp, pkt);
 			break;
 		case VP_RPT_ID_IOCB_TYPE:
 			qla24xx_report_id_acquisition(vha,
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 9dd181feeb87..fc94eb62fc49 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8410,6 +8410,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(sts21_entry_t) != 64);
 	BUILD_BUG_ON(sizeof(sts22_entry_t) != 64);
 	BUILD_BUG_ON(sizeof(sts_cont_entry_t) != 64);
+	BUILD_BUG_ON(sizeof(struct sts_cont_entry_ext) != 128);
 	BUILD_BUG_ON(sizeof(sts_entry_t) != 64);
 	BUILD_BUG_ON(sizeof(sw_info_t) != 32);
 	BUILD_BUG_ON(sizeof(target_id_t) != 2);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 29/60] scsi: qla2xxx: Update handling of status entries for 29xx series
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (27 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 28/60] scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 10:44   ` sashiko-bot
  2026-06-12 12:12   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 30/60] scsi: qla2xxx: Enhance ct_entry_24xx_ext iocb handling " Nilesh Javali
                   ` (30 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Modify the handling of status entries in the qla2xxx driver to
accommodate the extended structure for the 29xx series. Changes include
updating function signatures to accept a generic pointer for status
packets, and adjusting the logic to differentiate between the standard
and extended status entries. This ensures proper processing of
completion statuses and error handling for the new hardware
capabilities.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_edif.c   |  15 ++--
 drivers/scsi/qla2xxx/qla_gbl.h    |   2 +-
 drivers/scsi/qla2xxx/qla_inline.h |  45 ++++++++++++
 drivers/scsi/qla2xxx/qla_isr.c    | 111 +++++++++++++++++++-----------
 drivers/scsi/qla2xxx/qla_mbx.c    |  28 ++++----
 drivers/scsi/qla2xxx/qla_os.c     |   1 +
 6 files changed, 143 insertions(+), 59 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
index 4416197a35b0..b05f8e0b705e 100644
--- a/drivers/scsi/qla2xxx/qla_edif.c
+++ b/drivers/scsi/qla2xxx/qla_edif.c
@@ -3501,12 +3501,15 @@ static void __chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
 }
 
 void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
-		srb_t *sp, struct sts_entry_24xx *sts24)
+		srb_t *sp, void *pkt)
 {
+	struct sts_entry_24xx *sts24 = pkt;
+	struct sts_entry_24xx_ext *stsext = pkt;
+	struct qla_hw_data *ha = vha->hw;
 	fc_port_t *fcport = sp->fcport;
-	/* sa_index used by this iocb */
 	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
 	uint32_t handle;
+	uint16_t sa_index;
 
 	handle = (uint32_t)LSW(sts24->handle);
 
@@ -3514,8 +3517,12 @@ void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
 	if (cmd->sc_data_direction != DMA_FROM_DEVICE)
 		return;
 
-	return __chk_edif_rx_sa_delete_pending(vha, fcport, handle,
-	   le16_to_cpu(sts24->edif_sa_index));
+	if (IS_QLA29XX(ha))
+		sa_index = le16_to_cpu(stsext->read_sa_index);
+	else
+		sa_index = le16_to_cpu(sts24->edif_sa_index);
+
+	return __chk_edif_rx_sa_delete_pending(vha, fcport, handle, sa_index);
 }
 
 void qlt_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha, fc_port_t *fcport,
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 04f4cfadc510..2b66c59e9a6d 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -136,7 +136,7 @@ void qla_edif_sadb_release(struct qla_hw_data *ha);
 int qla_edif_sadb_build_free_pool(struct qla_hw_data *ha);
 void qla_edif_sadb_release_free_pool(struct qla_hw_data *ha);
 void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
-		srb_t *sp, struct sts_entry_24xx *sts24);
+		srb_t *sp, void *pkt);
 void qlt_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha, fc_port_t *fcport,
 		struct ctio7_from_24xx *ctio);
 void qla2x00_release_all_sadb(struct scsi_qla_host *vha, struct fc_port *fcport);
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index cdbc3c5abf75..7e353ac8e66c 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -802,3 +802,48 @@ static inline bool val_is_in_range(u32 val, u32 start, u32 end)
 	else
 		return false;
 }
+
+/*
+ * Common fields extracted from FWI2 status IOCBs.  Populated once so
+ * callers avoid duplicated IS_QLA29XX() branches for every field access.
+ */
+struct qla_sts_fwi2 {
+	u8  *data;
+	u32 data_sz;
+	u16 scsi_status;
+	u16 sts_qual;
+	u32 sense_len;
+	u32 rsp_data_len;
+	u32 rsp_residual_count;
+};
+
+static inline void
+qla_sts_fwi2_extract(struct qla_hw_data *ha, void *pkt,
+		      struct qla_sts_fwi2 *sf)
+{
+	if (IS_QLA29XX(ha)) {
+		struct sts_entry_24xx_ext *s = pkt;
+
+		sf->scsi_status = le16_to_cpu(s->u2.scsi_status);
+		sf->sts_qual = le16_to_cpu(s->u2.retry_delay_timer);
+		sf->sense_len = le32_to_cpu(s->u2.sense_len);
+		sf->rsp_data_len = le32_to_cpu(s->u2.rsp_data_len_ndma);
+		sf->rsp_residual_count = le32_to_cpu(s->u2.rsp_residual_count);
+		sf->data = s->u2.data;
+		sf->data_sz = sizeof(s->u2.data);
+		host_to_fcp_swap(s->u2.data, sizeof(s->u2.data));
+		host_to_fcp_swap(s->act_dif, sizeof(s->act_dif));
+		host_to_fcp_swap(s->exp_dif, sizeof(s->exp_dif));
+	} else {
+		struct sts_entry_24xx *s = pkt;
+
+		sf->scsi_status = le16_to_cpu(s->scsi_status);
+		sf->sts_qual = le16_to_cpu(s->status_qualifier);
+		sf->sense_len = le32_to_cpu(s->sense_len);
+		sf->rsp_data_len = le32_to_cpu(s->rsp_data_len);
+		sf->rsp_residual_count = le32_to_cpu(s->rsp_residual_count);
+		sf->data = s->data;
+		sf->data_sz = sizeof(s->data);
+		host_to_fcp_swap(s->data, sizeof(s->data));
+	}
+}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index c18ee2459f5b..f81cf70a0542 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -2359,8 +2359,9 @@ qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
 
 static void
 qla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
-    struct sts_entry_24xx *pkt, int iocb_type)
+		     void *pkt, int iocb_type)
 {
+	struct sts_entry_24xx *sts24 = pkt;
 	struct els_sts_entry_24xx *ese = (struct els_sts_entry_24xx *)pkt;
 	const char func[] = "ELS_CT_IOCB";
 	const char *type;
@@ -2383,9 +2384,9 @@ qla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
 
 	type = NULL;
 
-	comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status);
-	fw_status[1] = le32_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_1);
-	fw_status[2] = le32_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_2);
+	comp_status = fw_status[0] = le16_to_cpu(sts24->comp_status);
+	fw_status[1] = le32_to_cpu(ese->error_subcode_1);
+	fw_status[2] = le32_to_cpu(ese->error_subcode_2);
 
 	switch (sp->type) {
 	case SRB_ELS_CMD_RPT:
@@ -2721,7 +2722,9 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
 	srb_t *sp;
 	struct srb_iocb *iocb;
 	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
+	struct qla_hw_data *ha = vha->hw;
 	u16 comp_status;
+	struct qla_sts_fwi2 sf;
 
 	sp = qla2x00_get_sp_from_handle(vha, func, req, tsk);
 	if (!sp)
@@ -2743,18 +2746,19 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
 		    "Async-%s error - hdl=%x completion status(%x).\n",
 		    type, sp->handle, comp_status);
 		iocb->u.tmf.data = QLA_FUNCTION_FAILED;
-	} else if ((le16_to_cpu(sts->scsi_status) &
-	    SS_RESPONSE_INFO_LEN_VALID)) {
-		host_to_fcp_swap(sts->data, sizeof(sts->data));
-		if (le32_to_cpu(sts->rsp_data_len) < 4) {
-			ql_log(ql_log_warn, fcport->vha, 0x503b,
-			    "Async-%s error - hdl=%x not enough response(%d).\n",
-			    type, sp->handle, sts->rsp_data_len);
-		} else if (sts->data[3]) {
-			ql_log(ql_log_warn, fcport->vha, 0x503c,
-			    "Async-%s error - hdl=%x response(%x).\n",
-			    type, sp->handle, sts->data[3]);
-			iocb->u.tmf.data = QLA_FUNCTION_FAILED;
+	} else {
+		qla_sts_fwi2_extract(ha, tsk, &sf);
+		if (sf.scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
+			if (sf.rsp_data_len < 4) {
+				ql_log(ql_log_warn, fcport->vha, 0x503b,
+				    "Async-%s error - hdl=%x not enough response(%d).\n",
+				    type, sp->handle, sf.rsp_data_len);
+			} else if (sf.data[3]) {
+				ql_log(ql_log_warn, fcport->vha, 0x503c,
+				    "Async-%s error - hdl=%x response(%x).\n",
+				    type, sp->handle, sf.data[3]);
+				iocb->u.tmf.data = QLA_FUNCTION_FAILED;
+			}
 		}
 	}
 
@@ -2783,7 +2787,8 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
 
 	if (iocb->u.tmf.data != QLA_SUCCESS)
 		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, sp->vha, 0x5055,
-		    sts, sizeof(*sts));
+		    tsk, IS_QLA29XX(ha) ?
+		    sizeof(struct sts_entry_24xx_ext) : sizeof(*sts));
 
 	sp->done(sp, 0);
 }
@@ -2794,6 +2799,8 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
 	fc_port_t *fcport;
 	struct srb_iocb *iocb;
 	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
+	struct sts_entry_24xx_ext *stsext = (struct sts_entry_24xx_ext *)tsk;
+	struct qla_hw_data *ha = vha->hw;
 	uint16_t        state_flags;
 	struct nvmefc_fcp_req *fd;
 	uint16_t        ret = QLA_SUCCESS;
@@ -2845,7 +2852,10 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
 		uint32_t *inbuf, *outbuf;
 		uint16_t iter;
 
-		inbuf = (uint32_t *)&sts->nvme_ersp_data;
+		if (IS_QLA29XX(ha))
+			inbuf = (uint32_t *)stsext->u2.nvme_ersp_data;
+		else
+			inbuf = (uint32_t *)&sts->nvme_ersp_data;
 		outbuf = (uint32_t *)fd->rspaddr;
 		iocb->u.nvme.rsp_pyld_len = sts->nvme_rsp_pyld_len;
 		if (unlikely(le16_to_cpu(iocb->u.nvme.rsp_pyld_len) >
@@ -3089,16 +3099,26 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
  * to indicate to the kernel that the HBA detected error.
  */
 static inline int
-qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
+qla2x00_handle_dif_error(srb_t *sp, void *pkt)
 {
 	struct scsi_qla_host *vha = sp->vha;
+	struct qla_hw_data *ha = vha->hw;
 	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
-	uint8_t		*ap = &sts24->data[12];
-	uint8_t		*ep = &sts24->data[20];
+	struct sts_entry_24xx *sts24 = pkt;
+	struct sts_entry_24xx_ext *stsext = pkt;
+	uint8_t		*ap, *ep;
 	uint32_t	e_ref_tag, a_ref_tag;
 	uint16_t	e_app_tag, a_app_tag;
 	uint16_t	e_guard, a_guard;
 
+	if (IS_QLA29XX(ha)) {
+		ap = stsext->act_dif;
+		ep = stsext->exp_dif;
+	} else {
+		ap = &sts24->data[12];
+		ep = &sts24->data[20];
+	}
+
 	/*
 	 * swab32 of the "data" field in the beginning of qla2x00_status_entry()
 	 * would make guard field appear at offset 2
@@ -3111,7 +3131,7 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
 	e_ref_tag = get_unaligned_le32(ep + 4);
 
 	ql_dbg(ql_dbg_io, vha, 0x3023,
-	    "iocb(s) %p Returned STATUS.\n", sts24);
+	    "iocb(s) %px Returned STATUS.\n", pkt);
 
 	ql_dbg(ql_dbg_io, vha, 0x3024,
 	    "DIF ERROR in cmd 0x%x lba 0x%llx act ref"
@@ -3243,7 +3263,9 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
 
 	if (IS_FWI2_CAPABLE(ha)) {
 		comp_status = le16_to_cpu(sts24->comp_status);
-		scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
+		scsi_status = IS_QLA29XX(ha) ?
+		    le16_to_cpu(((struct sts_entry_24xx_ext *)pkt)->u2.scsi_status) & SS_MASK :
+		    le16_to_cpu(sts24->scsi_status) & SS_MASK;
 	} else {
 		comp_status = le16_to_cpu(sts->comp_status);
 		scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
@@ -3379,10 +3401,13 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 	int res = 0;
 	uint16_t state_flags = 0;
 	uint16_t sts_qual = 0;
+	struct qla_sts_fwi2 sf;
 
 	if (IS_FWI2_CAPABLE(ha)) {
 		comp_status = le16_to_cpu(sts24->comp_status);
-		scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
+		scsi_status = IS_QLA29XX(ha) ?
+		    le16_to_cpu(((struct sts_entry_24xx_ext *)pkt)->u2.scsi_status) & SS_MASK :
+		    le16_to_cpu(sts24->scsi_status) & SS_MASK;
 		state_flags = le16_to_cpu(sts24->state_flags);
 	} else {
 		comp_status = le16_to_cpu(sts->comp_status);
@@ -3453,7 +3478,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 	}
 
 	/* Fast path completion. */
-	qla_chk_edif_rx_sa_delete_pending(vha, sp, sts24);
+	qla_chk_edif_rx_sa_delete_pending(vha, sp, pkt);
 	sp->qpair->cmd_completion_cnt++;
 
 	if (comp_status == CS_COMPLETE && scsi_status == 0) {
@@ -3480,20 +3505,20 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 	sense_len = par_sense_len = rsp_info_len = resid_len =
 	    fw_resid_len = 0;
 	if (IS_FWI2_CAPABLE(ha)) {
+		qla_sts_fwi2_extract(ha, pkt, &sf);
 		if (scsi_status & SS_SENSE_LEN_VALID)
-			sense_len = le32_to_cpu(sts24->sense_len);
+			sense_len = sf.sense_len;
 		if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
-			rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
+			rsp_info_len = sf.rsp_data_len;
 		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
-			resid_len = le32_to_cpu(sts24->rsp_residual_count);
+			resid_len = sf.rsp_residual_count;
 		if (comp_status == CS_DATA_UNDERRUN)
 			fw_resid_len = le32_to_cpu(sts24->residual_len);
-		rsp_info = sts24->data;
-		sense_data = sts24->data;
-		host_to_fcp_swap(sts24->data, sizeof(sts24->data));
+		rsp_info = sf.data;
+		sense_data = sf.data;
+		par_sense_len = sf.data_sz;
+		sts_qual = sf.sts_qual;
 		ox_id = le16_to_cpu(sts24->ox_id);
-		par_sense_len = sizeof(sts24->data);
-		sts_qual = le16_to_cpu(sts24->status_qualifier);
 	} else {
 		if (scsi_status & SS_SENSE_LEN_VALID)
 			sense_len = le16_to_cpu(sts->req_sense_length);
@@ -3693,7 +3718,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 		break;
 
 	case CS_DIF_ERROR:
-		logit = qla2x00_handle_dif_error(sp, sts24);
+		logit = qla2x00_handle_dif_error(sp, pkt);
 		res = cp->result;
 		break;
 
@@ -3718,7 +3743,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 		    ox_id, cp->cmnd, scsi_bufflen(cp), rsp_info_len,
 		    resid_len, fw_resid_len, sp, cp);
 		ql_dump_buffer(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe0ee,
-		    pkt, sizeof(*sts24));
+		    pkt, IS_QLA29XX(ha) ?
+		    sizeof(struct sts_entry_24xx_ext) : sizeof(*sts24));
 		res = DID_ERROR << 16;
 		vha->hw_err_cnt++;
 		break;
@@ -4031,7 +4057,7 @@ static void qla_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
 void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 	struct rsp_que *rsp)
 {
-	struct sts_entry_24xx *pkt;
+	void *pkt;
 	struct qla_hw_data *ha = vha->hw;
 	struct purex_entry_24xx *purex_entry;
 	struct purex_item *pure_item;
@@ -4061,13 +4087,13 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 
 	while (rsp->ring_index != rsp_in &&
 		       rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
-		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
+		pkt = (void *)rsp->ring_ptr;
 		cur_ring_index = rsp->ring_index;
 
 		qla_rsp_ring_advance(rsp);
 
-		if (pkt->entry_status != 0) {
-			if (qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt))
+		if (((response_t *)pkt)->entry_status != 0) {
+			if (qla2x00_error_entry(vha, rsp, (sts_entry_t *)pkt))
 				goto process_err;
 
 			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
@@ -4076,7 +4102,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 		}
 process_err:
 
-		switch (pkt->entry_type) {
+		switch (((response_t *)pkt)->entry_type) {
 		case STATUS_TYPE:
 			qla2x00_status_entry(vha, rsp, pkt);
 			break;
@@ -4126,7 +4152,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 			    rsp->req);
 			break;
 		case NOTIFY_ACK_TYPE:
-			if (pkt->handle == QLA_TGT_SKIP_HANDLE)
+			if (((response_t *)pkt)->handle == QLA_TGT_SKIP_HANDLE)
 				qlt_response_pkt_all_vps(vha, rsp,
 				    (response_t *)pkt);
 			else
@@ -4219,7 +4245,8 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 			/* Type Not Supported. */
 			ql_dbg(ql_dbg_async, vha, 0x5042,
 			       "Received unknown response pkt type 0x%x entry status=%x.\n",
-			       pkt->entry_type, pkt->entry_status);
+			       ((response_t *)pkt)->entry_type,
+			       ((response_t *)pkt)->entry_status);
 			break;
 		}
 		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index c073dc35ef8e..f9b326c02055 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -3407,6 +3407,7 @@ struct tsk_mgmt_cmd {
 	union {
 		struct tsk_mgmt_entry tsk;
 		struct sts_entry_24xx sts;
+		struct sts_entry_24xx_ext sts_ext;
 	} p;
 };
 
@@ -3417,6 +3418,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
 	int		rval, rval2;
 	struct tsk_mgmt_cmd *tsk;
 	struct sts_entry_24xx *sts;
+	struct qla_sts_fwi2 sf;
 	dma_addr_t	tsk_dma;
 	scsi_qla_host_t *vha;
 	struct qla_hw_data *ha;
@@ -3474,18 +3476,20 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
 		    "Failed to complete IOCB -- completion status (%x).\n",
 		    le16_to_cpu(sts->comp_status));
 		rval = QLA_FUNCTION_FAILED;
-	} else if (le16_to_cpu(sts->scsi_status) &
-	    SS_RESPONSE_INFO_LEN_VALID) {
-		if (le32_to_cpu(sts->rsp_data_len) < 4) {
-			ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1097,
-			    "Ignoring inconsistent data length -- not enough "
-			    "response info (%d).\n",
-			    le32_to_cpu(sts->rsp_data_len));
-		} else if (sts->data[3]) {
-			ql_dbg(ql_dbg_mbx, vha, 0x1098,
-			    "Failed to complete IOCB -- response (%x).\n",
-			    sts->data[3]);
-			rval = QLA_FUNCTION_FAILED;
+	} else {
+		qla_sts_fwi2_extract(ha, sts, &sf);
+		if (sf.scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
+			if (sf.rsp_data_len < 4) {
+				ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha,
+				    0x1097,
+				    "Ignoring inconsistent data length -- not enough response info (%d).\n",
+				    sf.rsp_data_len);
+			} else if (sf.data[3]) {
+				ql_dbg(ql_dbg_mbx, vha, 0x1098,
+				    "Failed to complete IOCB -- response (%x).\n",
+				    sf.data[3]);
+				rval = QLA_FUNCTION_FAILED;
+			}
 		}
 	}
 
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index fc94eb62fc49..ab9d2ccd41d6 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8399,6 +8399,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct rdp_rsp_payload) != 336);
 	BUILD_BUG_ON(sizeof(struct sns_cmd_pkt) != 2064);
 	BUILD_BUG_ON(sizeof(struct sts_entry_24xx) != 64);
+	BUILD_BUG_ON(sizeof(struct sts_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct tsk_mgmt_entry) != 64);
 	BUILD_BUG_ON(sizeof(struct tsk_mgmt_entry_fx00) != 64);
 	BUILD_BUG_ON(sizeof(struct verify_chip_entry_84xx) != 64);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 30/60] scsi: qla2xxx: Enhance ct_entry_24xx_ext iocb handling for 29xx series
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (28 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 29/60] scsi: qla2xxx: Update handling of status entries for 29xx series Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 12:14   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 31/60] scsi: qla2xxx: Enhance purex_entry " Nilesh Javali
                   ` (29 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Refine the handling of I/O control blocks (IOCBs) for the 29xx series
by introducing support for the extended structure ct_entry_24xx_ext.
Update function signatures to accept a generic pointer for IOCB packets,
differentiating between standard and extended structures, and ensuring
proper initialization and processing of command and response data.
Additionally, the size check for the extended structure is added to
maintain integrity.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_gs.c   | 156 ++++++++++++++++++++++++--------
 drivers/scsi/qla2xxx/qla_iocb.c |  78 ++++++++++------
 drivers/scsi/qla2xxx/qla_os.c   |   1 +
 3 files changed, 168 insertions(+), 67 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index b69a001fd4da..eefd1440d197 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -68,30 +68,62 @@ void *
 qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg)
 {
 	struct qla_hw_data *ha = vha->hw;
-	struct ct_entry_24xx *ct_pkt;
 
-	ct_pkt = (struct ct_entry_24xx *)arg->iocb;
-	memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
+	if (IS_QLA29XX(ha)) {
+		struct ct_entry_24xx_ext *ct_pkt;
 
-	ct_pkt->entry_type = CT_IOCB_TYPE;
-	ct_pkt->entry_count = 1;
-	ct_pkt->nport_handle = cpu_to_le16(arg->nport_handle);
-	ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
-	ct_pkt->cmd_dsd_count = cpu_to_le16(1);
-	ct_pkt->rsp_dsd_count = cpu_to_le16(1);
-	ct_pkt->rsp_byte_count = cpu_to_le32(arg->rsp_size);
-	ct_pkt->cmd_byte_count = cpu_to_le32(arg->req_size);
+		ct_pkt = (struct ct_entry_24xx_ext *)arg->iocb;
+		memset(ct_pkt, 0, sizeof(struct ct_entry_24xx_ext));
 
-	put_unaligned_le64(arg->req_dma, &ct_pkt->dsd[0].address);
-	ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
+		ct_pkt->entry_type = CT_IOCB_TYPE;
+		ct_pkt->entry_count = 1;
+		ct_pkt->nport_handle = cpu_to_le16(arg->nport_handle);
+		ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
+		ct_pkt->cmd_dsd_count = cpu_to_le16(1);
+		ct_pkt->rsp_dsd_count = cpu_to_le16(1);
+		ct_pkt->rsp_byte_count = cpu_to_le32(arg->rsp_size);
+		ct_pkt->cmd_byte_count = cpu_to_le32(arg->req_size);
 
-	put_unaligned_le64(arg->rsp_dma, &ct_pkt->dsd[1].address);
-	ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
-	ct_pkt->vp_index = vha->vp_idx;
+		put_unaligned_le64(arg->req_dma,
+				   &ct_pkt->dsd[0].address);
+		ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
 
-	vha->qla_stats.control_requests++;
+		put_unaligned_le64(arg->rsp_dma,
+				   &ct_pkt->dsd[1].address);
+		ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
+		ct_pkt->vp_index = cpu_to_le16(vha->vp_idx);
+
+		vha->qla_stats.control_requests++;
+
+		return ct_pkt;
+	} else {
+		struct ct_entry_24xx *ct_pkt;
+
+		ct_pkt = (struct ct_entry_24xx *)arg->iocb;
+		memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
+
+		ct_pkt->entry_type = CT_IOCB_TYPE;
+		ct_pkt->entry_count = 1;
+		ct_pkt->nport_handle = cpu_to_le16(arg->nport_handle);
+		ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
+		ct_pkt->cmd_dsd_count = cpu_to_le16(1);
+		ct_pkt->rsp_dsd_count = cpu_to_le16(1);
+		ct_pkt->rsp_byte_count = cpu_to_le32(arg->rsp_size);
+		ct_pkt->cmd_byte_count = cpu_to_le32(arg->req_size);
+
+		put_unaligned_le64(arg->req_dma,
+				   &ct_pkt->dsd[0].address);
+		ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
 
-	return (ct_pkt);
+		put_unaligned_le64(arg->rsp_dma,
+				   &ct_pkt->dsd[1].address);
+		ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
+		ct_pkt->vp_index = vha->vp_idx;
+
+		vha->qla_stats.control_requests++;
+
+		return ct_pkt;
+	}
 }
 
 /**
@@ -132,7 +164,10 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
 		    routine, ms_pkt->entry_status, vha->d_id.b.domain,
 		    vha->d_id.b.area, vha->d_id.b.al_pa);
 	} else {
-		if (IS_FWI2_CAPABLE(ha))
+		if (IS_QLA29XX(ha))
+			comp_status = le16_to_cpu(
+			    ((struct ct_entry_24xx_ext *)ms_pkt)->comp_status);
+		else if (IS_FWI2_CAPABLE(ha))
 			comp_status = le16_to_cpu(
 			    ((struct ct_entry_24xx *)ms_pkt)->comp_status);
 		else
@@ -1437,42 +1472,85 @@ void *
 qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size,
     uint32_t rsp_size)
 {
-	struct ct_entry_24xx *ct_pkt;
 	struct qla_hw_data *ha = vha->hw;
 
-	ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
-	memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
+	if (IS_QLA29XX(ha)) {
+		struct ct_entry_24xx_ext *ct_pkt;
+
+		ct_pkt = (struct ct_entry_24xx_ext *)ha->ms_iocb;
+		memset(ct_pkt, 0, sizeof(struct ct_entry_24xx_ext));
+
+		ct_pkt->entry_type = CT_IOCB_TYPE;
+		ct_pkt->entry_count = 1;
+		ct_pkt->nport_handle =
+		    cpu_to_le16(vha->mgmt_svr_loop_id);
+		ct_pkt->timeout =
+		    cpu_to_le16(ha->r_a_tov / 10 * 2);
+		ct_pkt->cmd_dsd_count = cpu_to_le16(1);
+		ct_pkt->rsp_dsd_count = cpu_to_le16(1);
+		ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
+		ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
+
+		put_unaligned_le64(ha->ct_sns_dma,
+				   &ct_pkt->dsd[0].address);
+		ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
+
+		put_unaligned_le64(ha->ct_sns_dma,
+				   &ct_pkt->dsd[1].address);
+		ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
+		ct_pkt->vp_index = cpu_to_le16(vha->vp_idx);
 
-	ct_pkt->entry_type = CT_IOCB_TYPE;
-	ct_pkt->entry_count = 1;
-	ct_pkt->nport_handle = cpu_to_le16(vha->mgmt_svr_loop_id);
-	ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
-	ct_pkt->cmd_dsd_count = cpu_to_le16(1);
-	ct_pkt->rsp_dsd_count = cpu_to_le16(1);
-	ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
-	ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
+		return ct_pkt;
+	} else {
+		struct ct_entry_24xx *ct_pkt;
+
+		ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
+		memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
+
+		ct_pkt->entry_type = CT_IOCB_TYPE;
+		ct_pkt->entry_count = 1;
+		ct_pkt->nport_handle =
+		    cpu_to_le16(vha->mgmt_svr_loop_id);
+		ct_pkt->timeout =
+		    cpu_to_le16(ha->r_a_tov / 10 * 2);
+		ct_pkt->cmd_dsd_count = cpu_to_le16(1);
+		ct_pkt->rsp_dsd_count = cpu_to_le16(1);
+		ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
+		ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
 
-	put_unaligned_le64(ha->ct_sns_dma, &ct_pkt->dsd[0].address);
-	ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
+		put_unaligned_le64(ha->ct_sns_dma,
+				   &ct_pkt->dsd[0].address);
+		ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
 
-	put_unaligned_le64(ha->ct_sns_dma, &ct_pkt->dsd[1].address);
-	ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
-	ct_pkt->vp_index = vha->vp_idx;
+		put_unaligned_le64(ha->ct_sns_dma,
+				   &ct_pkt->dsd[1].address);
+		ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
+		ct_pkt->vp_index = vha->vp_idx;
 
-	return ct_pkt;
+		return ct_pkt;
+	}
 }
 
 static void
 qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size)
 {
 	struct qla_hw_data *ha = vha->hw;
-	ms_iocb_entry_t *ms_pkt = ha->ms_iocb;
-	struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
 
-	if (IS_FWI2_CAPABLE(ha)) {
+	if (IS_QLA29XX(ha)) {
+		struct ct_entry_24xx_ext *ct_pkt =
+		    (struct ct_entry_24xx_ext *)ha->ms_iocb;
+
+		ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
+		ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
+	} else if (IS_FWI2_CAPABLE(ha)) {
+		struct ct_entry_24xx *ct_pkt =
+		    (struct ct_entry_24xx *)ha->ms_iocb;
+
 		ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
 		ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
 	} else {
+		ms_iocb_entry_t *ms_pkt = ha->ms_iocb;
+
 		ms_pkt->req_bytecount = cpu_to_le32(req_size);
 		ms_pkt->req_dsd.length = ms_pkt->req_bytecount;
 	}
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 595fe78920ae..c7814c51b324 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -3394,7 +3394,7 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb)
 }
 
 static void
-qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
+qla24xx_ct_iocb(srb_t *sp, void *pkt)
 {
 	uint16_t        avail_dsds;
 	struct dsd64	*cur_dsd;
@@ -3406,36 +3406,50 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
 	struct bsg_job *bsg_job = sp->u.bsg_job;
 	int entry_count = 1;
 
-	ct_iocb->entry_type = CT_IOCB_TYPE;
-        ct_iocb->entry_status = 0;
-        ct_iocb->sys_define = 0;
-        ct_iocb->handle = sp->handle;
-
-	ct_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
-	ct_iocb->vp_index = sp->vha->vp_idx;
-	ct_iocb->comp_status = cpu_to_le16(0);
-
 	cmd_dsds = bsg_job->request_payload.sg_cnt;
 	rsp_dsds = bsg_job->reply_payload.sg_cnt;
 
-	ct_iocb->cmd_dsd_count = cpu_to_le16(cmd_dsds);
-        ct_iocb->timeout = 0;
-	ct_iocb->rsp_dsd_count = cpu_to_le16(rsp_dsds);
-        ct_iocb->cmd_byte_count =
-            cpu_to_le32(bsg_job->request_payload.payload_len);
+	if (IS_QLA29XX(ha)) {
+		struct ct_entry_24xx_ext *ct_iocb = pkt;
+
+		ct_iocb->entry_type = CT_IOCB_TYPE;
+		ct_iocb->entry_status = 0;
+		ct_iocb->sys_define = 0;
+		ct_iocb->handle = sp->handle;
+		ct_iocb->nport_handle =
+		    cpu_to_le16(sp->fcport->loop_id);
+		ct_iocb->vp_index = cpu_to_le16(sp->vha->vp_idx);
+		ct_iocb->comp_status = cpu_to_le16(0);
+		ct_iocb->cmd_dsd_count = cpu_to_le16(cmd_dsds);
+		ct_iocb->timeout = 0;
+		ct_iocb->rsp_dsd_count = cpu_to_le16(rsp_dsds);
+		ct_iocb->cmd_byte_count =
+		    cpu_to_le32(bsg_job->request_payload.payload_len);
+		avail_dsds = NUM_CT_DSDS;
+		cur_dsd = ct_iocb->dsd;
+	} else {
+		struct ct_entry_24xx *ct_iocb = pkt;
+
+		ct_iocb->entry_type = CT_IOCB_TYPE;
+		ct_iocb->entry_status = 0;
+		ct_iocb->sys_define = 0;
+		ct_iocb->handle = sp->handle;
+		ct_iocb->nport_handle =
+		    cpu_to_le16(sp->fcport->loop_id);
+		ct_iocb->vp_index = sp->vha->vp_idx;
+		ct_iocb->comp_status = cpu_to_le16(0);
+		ct_iocb->cmd_dsd_count = cpu_to_le16(cmd_dsds);
+		ct_iocb->timeout = 0;
+		ct_iocb->rsp_dsd_count = cpu_to_le16(rsp_dsds);
+		ct_iocb->cmd_byte_count =
+		    cpu_to_le32(bsg_job->request_payload.payload_len);
+		avail_dsds = 2;
+		cur_dsd = ct_iocb->dsd;
+	}
 
-	avail_dsds = 2;
-	cur_dsd = ct_iocb->dsd;
 	index = 0;
 
 	for_each_sg(bsg_job->request_payload.sg_list, sg, cmd_dsds, index) {
-		/*
-		 * Allocate additional continuation packets.  24xx uses the
-		 * 64-byte cont_a64_entry_t (5 DSDs); 29xx uses the 128-byte
-		 * cont_a64_entry_ext_t (NUM_CONT1_DSDS) and advances through
-		 * the ring_ext_ptr stride so the CT head IOCB isn't
-		 * overlapped.
-		 */
 		if (avail_dsds == 0) {
 			if (IS_QLA29XX(ha)) {
 				struct cont_a64_entry_ext *cont_pkt;
@@ -3484,7 +3498,11 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
 		append_dsd64(&cur_dsd, sg);
 		avail_dsds--;
 	}
-        ct_iocb->entry_count = entry_count;
+
+	if (IS_QLA29XX(ha))
+		((struct ct_entry_24xx_ext *)pkt)->entry_count = entry_count;
+	else
+		((struct ct_entry_24xx *)pkt)->entry_count = entry_count;
 }
 
 /*
@@ -3857,11 +3875,15 @@ qla2x00_mb_iocb(srb_t *sp, struct mbx_24xx_entry *mbx)
 }
 
 static void
-qla2x00_ctpthru_cmd_iocb(srb_t *sp, struct ct_entry_24xx *ct_pkt)
+qla2x00_ctpthru_cmd_iocb(srb_t *sp, void *pkt)
 {
-	sp->u.iocb_cmd.u.ctarg.iocb = ct_pkt;
+	sp->u.iocb_cmd.u.ctarg.iocb = pkt;
 	qla24xx_prep_ms_iocb(sp->vha, &sp->u.iocb_cmd.u.ctarg);
-	ct_pkt->handle = sp->handle;
+
+	if (IS_QLA29XX(sp->vha->hw))
+		((struct ct_entry_24xx_ext *)pkt)->handle = sp->handle;
+	else
+		((struct ct_entry_24xx *)pkt)->handle = sp->handle;
 }
 
 static void qla2x00_send_notify_ack_iocb(srb_t *sp,
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index ab9d2ccd41d6..ea4363800e60 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8348,6 +8348,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct cmd_type_7_fx00) != 64);
 	BUILD_BUG_ON(sizeof(struct cmd_type_crc_2) != 64);
 	BUILD_BUG_ON(sizeof(struct ct_entry_24xx) != 64);
+	BUILD_BUG_ON(sizeof(struct ct_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct ct_fdmi1_hba_attributes) != 2604);
 	BUILD_BUG_ON(sizeof(struct ct_fdmi2_hba_attributes) != 4424);
 	BUILD_BUG_ON(sizeof(struct ct_fdmi2_port_attributes) != 4164);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 31/60] scsi: qla2xxx: Enhance purex_entry handling for 29xx series
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (29 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 30/60] scsi: qla2xxx: Enhance ct_entry_24xx_ext iocb handling " Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 10:54   ` sashiko-bot
  2026-06-12 12:16   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 32/60] scsi: qla2xxx: Update handling of ELS IOCBs " Nilesh Javali
                   ` (28 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Update function signatures and internal logic across qla_edif.c,
qla_isr.c, and qla_os.c to accept a generic pointer for packet data and
differentiate between standard purex_entry_24xx and the extended
purex_entry_24xx_ext structures based on IS_QLA29XX().

This ensures proper initialization and processing of command and response
data for both 64-byte and 128-byte PUREX IOCBs across all ELS paths
including auth_els, RDP, copy_std_pkt, copy_multiple_pkt, consume_iocb,
and copy_purex_to_buffer.

Where the two layouts overlap at byte-identical offsets (entry_count,
frame_size, nport_handle, rx_xchg_addr, ox_id, status_flags,
trunc_frame_size, s_id, d_id, els_frame_payload base, and
response_t::signature), use a single struct purex_entry_24xx * view to
avoid duplicating read paths.  Branch only where field encoding differs:
vp_idx (u8 at offset 6 in 24xx vs __le16 at offsets 6-7 in 29xx) and
els_frame_payload[] array length (20 vs 84 bytes, handled via a
sizeof_field()-based payload_size local).

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_def.h  |  3 +-
 drivers/scsi/qla2xxx/qla_edif.c | 68 +++++++++++++++++-------
 drivers/scsi/qla2xxx/qla_isr.c  | 94 ++++++++++++++++++++++++++-------
 drivers/scsi/qla2xxx/qla_os.c   | 24 +++++++--
 4 files changed, 145 insertions(+), 44 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 0bbe2bae7101..3e2f1d8ba904 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -5000,6 +5000,7 @@ struct active_regions {
 #define QLA_SET_DATA_RATE_LR	2 /* Set speed and initiate LR */
 
 #define QLA_DEFAULT_PAYLOAD_SIZE	64
+#define QLA_MAX_IOCB_SIZE		128
 /*
  * This item might be allocated with a size > sizeof(struct purex_item).
  * The "size" variable gives the size of the payload (which
@@ -5014,7 +5015,7 @@ struct purex_item {
 	atomic_t in_use;
 	uint16_t size;
 	struct {
-		uint8_t iocb[64];
+		u8 iocb[QLA_MAX_IOCB_SIZE];
 	} iocb;
 };
 
diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
index b05f8e0b705e..f8bc248e5d18 100644
--- a/drivers/scsi/qla2xxx/qla_edif.c
+++ b/drivers/scsi/qla2xxx/qla_edif.c
@@ -2534,7 +2534,7 @@ qla24xx_sa_replace_iocb(srb_t *sp, struct sa_update_28xx *sa_update_iocb)
 
 void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
 {
-	struct purex_entry_24xx *p = *pkt;
+	struct qla_hw_data *ha = vha->hw;
 	struct enode		*ptr;
 	int		sid;
 	u16 totlen;
@@ -2544,26 +2544,58 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
 	struct fc_port *fcport;
 	struct qla_els_pt_arg a;
 	be_id_t beid;
+	__le16 nport_handle;
+	__le32 rx_xchg_addr;
+	__le16 ox_id;
+	__le16 frame_size, status_flags, trunc_frame_size;
+	uint8_t s_id[3], d_id[3];
+	uint8_t vp_idx;
 
 	memset(&a, 0, sizeof(a));
 
+	/*
+	 * purex_entry_24xx_ext (29xx) overlays purex_entry_24xx for every
+	 * field touched here -- nport_handle, rx_xchg_addr, ox_id, frame_size,
+	 * status_flags, trunc_frame_size, s_id[3], d_id[3] -- with only
+	 * vp_idx differing in width (u8 at offset 6 vs __le16 at offsets 6-7,
+	 * with reserved2 at offset 7 in the 24xx layout). So all reads but
+	 * vp_idx go through a single struct purex_entry_24xx * view.
+	 */
+	{
+		struct purex_entry_24xx *p = *pkt;
+
+		nport_handle = p->nport_handle;
+		rx_xchg_addr = p->rx_xchg_addr;
+		ox_id = p->ox_id;
+		frame_size = p->frame_size;
+		status_flags = p->status_flags;
+		trunc_frame_size = p->trunc_frame_size;
+		memcpy(s_id, p->s_id, sizeof(s_id));
+		memcpy(d_id, p->d_id, sizeof(d_id));
+		if (IS_QLA29XX(ha))
+			vp_idx = le16_to_cpu(((struct purex_entry_24xx_ext *)
+					      *pkt)->vp_idx);
+		else
+			vp_idx = p->vp_idx;
+	}
+
 	a.els_opcode = ELS_AUTH_ELS;
-	a.nport_handle = p->nport_handle;
-	a.rx_xchg_address = p->rx_xchg_addr;
-	a.did.b.domain = p->s_id[2];
-	a.did.b.area   = p->s_id[1];
-	a.did.b.al_pa  = p->s_id[0];
+	a.nport_handle = nport_handle;
+	a.rx_xchg_address = rx_xchg_addr;
+	a.did.b.domain = s_id[2];
+	a.did.b.area   = s_id[1];
+	a.did.b.al_pa  = s_id[0];
 	a.tx_byte_count = a.tx_len = sizeof(struct fc_els_ls_rjt);
-	a.tx_addr = vha->hw->elsrej.cdma;
+	a.tx_addr = ha->elsrej.cdma;
 	a.vp_idx = vha->vp_idx;
 	a.control_flags = EPD_ELS_RJT;
-	a.ox_id = le16_to_cpu(p->ox_id);
+	a.ox_id = le16_to_cpu(ox_id);
 
-	sid = p->s_id[0] | (p->s_id[1] << 8) | (p->s_id[2] << 16);
+	sid = s_id[0] | (s_id[1] << 8) | (s_id[2] << 16);
 
-	totlen = (le16_to_cpu(p->frame_size) & 0x0fff) - PURX_ELS_HEADER_SIZE;
-	if (le16_to_cpu(p->status_flags) & 0x8000) {
-		totlen = le16_to_cpu(p->trunc_frame_size);
+	totlen = (le16_to_cpu(frame_size) & 0x0fff) - PURX_ELS_HEADER_SIZE;
+	if (le16_to_cpu(status_flags) & 0x8000) {
+		totlen = le16_to_cpu(trunc_frame_size);
 		qla_els_reject_iocb(vha, (*rsp)->qpair, &a);
 		__qla_consume_iocb(vha, pkt, rsp);
 		return;
@@ -2600,12 +2632,12 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
 	purex = &ptr->u.purexinfo;
 	purex->pur_info.pur_sid = a.did;
 	purex->pur_info.pur_bytes_rcvd = totlen;
-	purex->pur_info.pur_rx_xchg_address = le32_to_cpu(p->rx_xchg_addr);
-	purex->pur_info.pur_nphdl = le16_to_cpu(p->nport_handle);
-	purex->pur_info.pur_did.b.domain =  p->d_id[2];
-	purex->pur_info.pur_did.b.area =  p->d_id[1];
-	purex->pur_info.pur_did.b.al_pa =  p->d_id[0];
-	purex->pur_info.vp_idx = p->vp_idx;
+	purex->pur_info.pur_rx_xchg_address = le32_to_cpu(rx_xchg_addr);
+	purex->pur_info.pur_nphdl = le16_to_cpu(nport_handle);
+	purex->pur_info.pur_did.b.domain =  d_id[2];
+	purex->pur_info.pur_did.b.area =  d_id[1];
+	purex->pur_info.pur_did.b.al_pa =  d_id[0];
+	purex->pur_info.vp_idx = vp_idx;
 
 	a.sid = purex->pur_info.pur_did;
 
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index f81cf70a0542..76c66f060b7b 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -202,6 +202,11 @@ void __qla_consume_iocb(struct scsi_qla_host *vha,
 	struct rsp_que *rsp_q = *rsp;
 	response_t *new_pkt;
 	uint16_t entry_count_remaining;
+	/*
+	 * entry_count is u8 at offset 1 in both purex_entry_24xx and
+	 * purex_entry_24xx_ext, so the 24xx view is layout-compatible with
+	 * either stride.
+	 */
 	struct purex_entry_24xx *purex = *pkt;
 
 	entry_count_remaining = purex->entry_count;
@@ -230,6 +235,14 @@ void __qla_consume_iocb(struct scsi_qla_host *vha,
 int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
 	void **pkt, struct rsp_que **rsp, u8 *buf, u32 buf_len)
 {
+	/*
+	 * purex_entry_24xx_ext overlays purex_entry_24xx for entry_count
+	 * (offset 1), frame_size (offset 12) and els_frame_payload (offset
+	 * 44, base address only -- the array size grows from 20 to 84
+	 * bytes).  Header fields are read through the 24xx view; the
+	 * initial payload memcpy uses a purex_entry_24xx_ext pointer on
+	 * 29xx so that FORTIFY_SOURCE sees the correct 84-byte source.
+	 */
 	struct purex_entry_24xx *purex = *pkt;
 	struct qla_hw_data *ha = vha->hw;
 	struct rsp_que *rsp_q = *rsp;
@@ -246,8 +259,8 @@ int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
 	u16 tpad;
 
 	entry_count_remaining = purex->entry_count;
-	total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF)
-		- PURX_ELS_HEADER_SIZE;
+	total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF) -
+		PURX_ELS_HEADER_SIZE;
 
 	/*
 	 * end of payload may not end in 4bytes boundary.  Need to
@@ -264,14 +277,24 @@ int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
 	}
 
 	pending_bytes = total_bytes = tpad;
-	no_bytes = (pending_bytes > sizeof(purex->els_frame_payload))  ?
-	    sizeof(purex->els_frame_payload) : pending_bytes;
+	no_bytes = (pending_bytes > payload_size) ?
+		payload_size : pending_bytes;
+	if (IS_QLA29XX(ha)) {
+		struct purex_entry_24xx_ext *purex_ext = *pkt;
 
-	memcpy(buf, &purex->els_frame_payload[0], no_bytes);
+		memcpy(buf, &purex_ext->els_frame_payload[0], no_bytes);
+	} else {
+		memcpy(buf, &purex->els_frame_payload[0], no_bytes);
+	}
 	buffer_copy_offset += no_bytes;
 	pending_bytes -= no_bytes;
 	--entry_count_remaining;
 
+	/*
+	 * response_t::signature and struct response_ext::signature are both u32
+	 * at offset 60 (handle:4 + data[52]:60), so the 24xx view writes
+	 * the right slot regardless of stride.
+	 */
 	((response_t *)purex)->signature = RESPONSE_PROCESSED;
 	/* flush signature */
 	wmb();
@@ -870,6 +893,7 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
 			  struct rsp_que **rsp, bool is_purls,
 			  bool byte_order)
 {
+	struct purex_entry_24xx_ext *purex_ext = NULL;
 	struct purex_entry_24xx *purex = NULL;
 	struct pt_ls4_rx_unsol *purls = NULL;
 	struct qla_hw_data *ha = vha->hw;
@@ -888,6 +912,13 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
 			      PURX_ELS_HEADER_SIZE;
 		entry_count = entry_count_remaining = purls->entry_count;
 		payload_size = sizeof(purls->payload);
+	} else if (IS_QLA29XX(ha)) {
+		purex_ext = *pkt;
+		total_bytes = (le16_to_cpu(purex_ext->frame_size) & 0x0FFF) -
+			      PURX_ELS_HEADER_SIZE;
+		entry_count = entry_count_remaining =
+		    purex_ext->entry_count;
+		payload_size = sizeof(purex_ext->els_frame_payload);
 	} else {
 		purex = *pkt;
 		total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF) -
@@ -896,8 +927,8 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
 		payload_size = sizeof(purex->els_frame_payload);
 	}
 
-	if (total_bytes > sizeof(item->iocb.iocb))
-		total_bytes = sizeof(item->iocb.iocb);
+	if (total_bytes > QLA_MAX_IOCB_SIZE)
+		total_bytes = QLA_MAX_IOCB_SIZE;
 
 	pending_bytes = total_bytes;
 	no_bytes = (pending_bytes > payload_size) ? payload_size :
@@ -914,6 +945,8 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
 
 	if (is_purls)
 		memcpy(iocb_pkt, &purls->payload[0], no_bytes);
+	else if (IS_QLA29XX(ha))
+		memcpy(iocb_pkt, &purex_ext->els_frame_payload[0], no_bytes);
 	else
 		memcpy(iocb_pkt, &purex->els_frame_payload[0], no_bytes);
 	buffer_copy_offset += no_bytes;
@@ -922,6 +955,8 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
 
 	if (is_purls)
 		((response_t *)purls)->signature = RESPONSE_PROCESSED;
+	else if (IS_QLA29XX(ha))
+		((struct response_ext *)purex_ext)->signature = RESPONSE_PROCESSED;
 	else
 		((response_t *)purex)->signature = RESPONSE_PROCESSED;
 	wmb();
@@ -1105,9 +1140,9 @@ qla24xx_alloc_purex_item(scsi_qla_host_t *vha, uint16_t size)
 	struct purex_item *item = NULL;
 	uint8_t item_hdr_size = sizeof(*item);
 
-	if (size > QLA_DEFAULT_PAYLOAD_SIZE) {
+	if (size > QLA_MAX_IOCB_SIZE) {
 		item = kzalloc(item_hdr_size +
-		    (size - QLA_DEFAULT_PAYLOAD_SIZE), GFP_ATOMIC);
+		    (size - QLA_MAX_IOCB_SIZE), GFP_ATOMIC);
 	} else {
 		if (atomic_inc_return(&vha->default_item.in_use) == 1) {
 			item = &vha->default_item;
@@ -1156,14 +1191,20 @@ qla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt,
 static struct purex_item
 *qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt)
 {
+	struct qla_hw_data *ha = vha->hw;
 	struct purex_item *item;
+	u16 copy_sz;
 
-	item = qla24xx_alloc_purex_item(vha,
-					QLA_DEFAULT_PAYLOAD_SIZE);
+	if (IS_QLA29XX(ha))
+		copy_sz = sizeof(struct purex_entry_24xx_ext);
+	else
+		copy_sz = QLA_DEFAULT_PAYLOAD_SIZE;
+
+	item = qla24xx_alloc_purex_item(vha, copy_sz);
 	if (!item)
 		return item;
 
-	memcpy(&item->iocb, pkt, sizeof(item->iocb));
+	memcpy(&item->iocb, pkt, copy_sz);
 	return item;
 }
 
@@ -1197,8 +1238,8 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
 	total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF)
 	    - PURX_ELS_HEADER_SIZE;
 
-	if (total_bytes > sizeof(item->iocb.iocb))
-		total_bytes = sizeof(item->iocb.iocb);
+	if (total_bytes > QLA_MAX_IOCB_SIZE)
+		total_bytes = QLA_MAX_IOCB_SIZE;
 
 	pending_bytes = total_bytes;
 	entry_count = entry_count_remaining = purex->entry_count;
@@ -4059,6 +4100,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 {
 	void *pkt;
 	struct qla_hw_data *ha = vha->hw;
+	struct purex_entry_24xx_ext *purex_entry_ext;
 	struct purex_entry_24xx *purex_entry;
 	struct purex_item *pure_item;
 	struct pt_ls4_rx_unsol *p;
@@ -4175,8 +4217,16 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 			    (struct vp_ctrl_entry_24xx *)pkt);
 			break;
 		case PUREX_IOCB_TYPE:
-			purex_entry = (void *)pkt;
-			switch (purex_entry->els_frame_payload[3]) {
+			if (IS_QLA29XX(ha)) {
+				purex_entry_ext = (void *)pkt;
+				purex_entry = NULL;
+			} else {
+				purex_entry = (void *)pkt;
+				purex_entry_ext = NULL;
+			}
+			switch (IS_QLA29XX(ha) ?
+			    purex_entry_ext->els_frame_payload[3] :
+			    purex_entry->els_frame_payload[3]) {
 			case ELS_RDP:
 				pure_item = qla24xx_copy_std_pkt(vha, pkt);
 				if (!pure_item)
@@ -4211,16 +4261,20 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 					qla_rsp_ring_rewind_to(rsp,
 					    (response_t *)pkt, cur_ring_index);
 
-					ql_dbg(ql_dbg_init, vha, 0x5091,
-					    "Defer processing ELS opcode %#x...\n",
-					    purex_entry->els_frame_payload[3]);
+				ql_dbg(ql_dbg_init, vha, 0x5091,
+				    "Defer processing ELS opcode %#x...\n",
+				    IS_QLA29XX(ha) ?
+				    purex_entry_ext->els_frame_payload[3] :
+				    purex_entry->els_frame_payload[3]);
 					return;
 				}
 				qla24xx_auth_els(vha, (void **)&pkt, &rsp);
 				break;
 			default:
 				ql_log(ql_log_warn, vha, 0x509c,
-				       "Discarding ELS Request opcode 0x%x\n",
+				       "Discarding ELS Request opcode 0x%x...\n",
+				       IS_QLA29XX(ha) ?
+				       purex_entry_ext->els_frame_payload[3] :
 				       purex_entry->els_frame_payload[3]);
 			}
 			break;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index ea4363800e60..ad0531ffedab 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -6138,13 +6138,15 @@ qla83xx_idc_lock(scsi_qla_host_t *base_vha, uint16_t requester_id)
 }
 
 static bool
-qla25xx_rdp_rsp_reduce_size(struct scsi_qla_host *vha,
-	struct purex_entry_24xx *purex)
+qla25xx_rdp_rsp_reduce_size(struct scsi_qla_host *vha, void *pkt)
 {
+	struct purex_entry_24xx *purex = pkt;
 	char fwstr[16];
-	u32 sid = purex->s_id[2] << 16 | purex->s_id[1] << 8 | purex->s_id[0];
+	u32 sid;
 	struct port_database_24xx *pdb;
 
+	sid = purex->s_id[2] << 16 | purex->s_id[1] << 8 | purex->s_id[0];
+
 	/* Domain Controller is always logged-out. */
 	/* if RDP request is not from Domain Controller: */
 	if (sid != 0xfffc01)
@@ -6209,15 +6211,26 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
 	uint8_t *sfp = NULL;
 	uint16_t sfp_flags = 0;
 	uint rsp_payload_length = sizeof(*rsp_payload);
+	uint8_t vp_idx;
+	size_t purex_sz;
 	int rval;
 
 	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0180,
 	    "%s: Enter\n", __func__);
 
+	if (IS_QLA29XX(ha)) {
+		vp_idx = le16_to_cpu(
+		    ((struct purex_entry_24xx_ext *)purex)->vp_idx);
+		purex_sz = sizeof(struct purex_entry_24xx_ext);
+	} else {
+		vp_idx = purex->vp_idx;
+		purex_sz = sizeof(*purex);
+	}
+
 	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0181,
 	    "-------- ELS REQ -------\n");
 	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0182,
-	    purex, sizeof(*purex));
+	    purex, purex_sz);
 
 	if (qla25xx_rdp_rsp_reduce_size(vha, purex)) {
 		rsp_payload_length =
@@ -6257,7 +6270,7 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
 	rsp_els->handle = 0;
 	rsp_els->nport_handle = purex->nport_handle;
 	rsp_els->tx_dsd_count = cpu_to_le16(1);
-	rsp_els->vp_index = purex->vp_idx;
+	rsp_els->vp_index = vp_idx;
 	rsp_els->sof_type = EST_SOFI3;
 	rsp_els->rx_xchg_address = purex->rx_xchg_addr;
 	rsp_els->rx_dsd_count = 0;
@@ -8377,6 +8390,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct pt_ls4_request) != 64);
 	BUILD_BUG_ON(sizeof(struct pt_ls4_rx_unsol) != 64);
 	BUILD_BUG_ON(sizeof(struct purex_entry_24xx) != 64);
+	BUILD_BUG_ON(sizeof(struct purex_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct qla2100_fw_dump) != 123634);
 	BUILD_BUG_ON(sizeof(struct qla2300_fw_dump) != 136100);
 	BUILD_BUG_ON(sizeof(struct qla24xx_fw_dump) != 37976);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 32/60] scsi: qla2xxx: Update handling of ELS IOCBs for 29xx series
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (30 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 31/60] scsi: qla2xxx: Enhance purex_entry " Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 12:33   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 33/60] scsi: qla2xxx: Add size check for ELS status entry layout on 29xx Nilesh Javali
                   ` (27 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Update ELS IOCB handling to support the extended 128-byte
els_entry_24xx_ext structure used by 29xx series adapters.

Change the signatures of qla24xx_els_logo_iocb(), qla_els_pt_iocb(),
and qla24xx_els_iocb() to accept a generic void pointer, enabling
differentiation between standard and extended ELS structures at
runtime.

Introduce a static inline helper qla_els_set_vp_sof() in qla_inline.h
that centralises the 24xx-vs-29xx vp_index/sof_type encoding: the 24xx
layout uses separate u8 vp_index + u8 sof_type (EST_SOFI3), while
29xx uses a __le16 with bitfields (vp_index:9 / sof_type:4 /
ELS_EXT_EST_SOFI3).  All ELS issue paths now call this helper instead
of open-coding the branch, including the RDP response path in qla_os.c.

In qla2x00_start_sp(), collapse the IS_QLA29XX() branch for the
handle assignment in SRB_ELS_CMD_HST_NOLOGIN: els_entry_24xx::handle
and els_entry_24xx_ext::handle are both u32 at offset 4, so a single
24xx-view write is layout-compatible with both strides.

DMA allocations in qla24xx_process_abts() and
qla24xx_process_purex_rdp() are updated to use the correct size for
the adapter type.  A BUILD_BUG_ON is added to verify the extended
structure size.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_gbl.h    |  2 +-
 drivers/scsi/qla2xxx/qla_inline.h | 28 ++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_iocb.c   | 28 ++++++++++++++++++----------
 drivers/scsi/qla2xxx/qla_isr.c    | 26 ++++++++++++++++++--------
 drivers/scsi/qla2xxx/qla_os.c     | 31 ++++++++++++++++++++-----------
 5 files changed, 85 insertions(+), 30 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 2b66c59e9a6d..4ac3cb08fcc9 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -295,7 +295,7 @@ void qla_adjust_buf(struct scsi_qla_host *);
  * Global Function Prototypes in qla_iocb.c source file.
  */
 void qla_els_pt_iocb(struct scsi_qla_host *vha,
-	struct els_entry_24xx *pkt, struct qla_els_pt_arg *a);
+	void *pkt, struct qla_els_pt_arg *a);
 cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha,
 		struct qla_hw_data *ha, struct req_que *que);
 struct cont_a64_entry_ext *qla2900_prep_cont_type1_iocb(scsi_qla_host_t *vha,
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 7e353ac8e66c..3e6a5208d108 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -847,3 +847,31 @@ qla_sts_fwi2_extract(struct qla_hw_data *ha, void *pkt,
 		host_to_fcp_swap(s->data, sizeof(s->data));
 	}
 }
+
+/*
+ * qla_els_set_vp_sof() - write the vp_index / sof_type pair into an ELS
+ *    pass-through IOCB (els_entry_24xx{,_ext}).
+ *
+ * Both layouts have the same 16-bit slot at offset 14, but it is encoded
+ * differently:
+ *   - 24xx: separate u8 vp_index + u8 sof_type with EST_SOFI3 (1 << 4)
+ *   - 29xx: __le16 with bitfields { vp_index:9, reserved_1_sof:3,
+ *           sof_type:4 } and ELS_EXT_EST_SOFI3
+ * so this is the single point in the driver that knows about that
+ * encoding split.
+ */
+static inline void
+qla_els_set_vp_sof(struct scsi_qla_host *vha, void *pkt, u16 vp_idx)
+{
+	if (IS_QLA29XX(vha->hw)) {
+		struct els_entry_24xx_ext *ext = pkt;
+
+		ext->vp_index = vp_idx;
+		ext->sof_type = ELS_EXT_EST_SOFI3;
+	} else {
+		struct els_entry_24xx *e = pkt;
+
+		e->vp_index = vp_idx;
+		e->sof_type = EST_SOFI3;
+	}
+}
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c7814c51b324..45d6837100ad 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2901,8 +2901,9 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
 }
 
 static void
-qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
+qla24xx_els_logo_iocb(srb_t *sp, void *pkt)
 {
+	struct els_entry_24xx *els_iocb = pkt;
 	scsi_qla_host_t *vha = sp->vha;
 	struct srb_iocb *elsio = &sp->u.iocb_cmd;
 
@@ -2913,11 +2914,11 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
 	els_iocb->handle = sp->handle;
 	els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
 	els_iocb->tx_dsd_count = cpu_to_le16(1);
-	els_iocb->vp_index = vha->vp_idx;
-	els_iocb->sof_type = EST_SOFI3;
 	els_iocb->rx_dsd_count = 0;
 	els_iocb->opcode = elsio->u.els_logo.els_cmd;
 
+	qla_els_set_vp_sof(vha, pkt, vha->vp_idx);
+
 	els_iocb->d_id[0] = sp->fcport->d_id.b.al_pa;
 	els_iocb->d_id[1] = sp->fcport->d_id.b.area;
 	els_iocb->d_id[2] = sp->fcport->d_id.b.domain;
@@ -3248,9 +3249,10 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode,
 
 /* it is assume qpair lock is held */
 void qla_els_pt_iocb(struct scsi_qla_host *vha,
-	struct els_entry_24xx *els_iocb,
-	struct qla_els_pt_arg *a)
+	void *pkt, struct qla_els_pt_arg *a)
 {
+	struct els_entry_24xx *els_iocb = pkt;
+
 	els_iocb->entry_type = ELS_IOCB_TYPE;
 	els_iocb->entry_count = 1;
 	els_iocb->sys_define = 0;
@@ -3259,11 +3261,11 @@ void qla_els_pt_iocb(struct scsi_qla_host *vha,
 	els_iocb->nport_handle = a->nport_handle;
 	els_iocb->rx_xchg_address = a->rx_xchg_address;
 	els_iocb->tx_dsd_count = cpu_to_le16(1);
-	els_iocb->vp_index = a->vp_idx;
-	els_iocb->sof_type = EST_SOFI3;
 	els_iocb->rx_dsd_count = cpu_to_le16(0);
 	els_iocb->opcode = a->els_opcode;
 
+	qla_els_set_vp_sof(vha, pkt, a->vp_idx);
+
 	els_iocb->d_id[0] = a->did.b.al_pa;
 	els_iocb->d_id[1] = a->did.b.area;
 	els_iocb->d_id[2] = a->did.b.domain;
@@ -3284,8 +3286,9 @@ void qla_els_pt_iocb(struct scsi_qla_host *vha,
 }
 
 static void
-qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
+qla24xx_els_iocb(srb_t *sp, void *pkt)
 {
+	struct els_entry_24xx *els_iocb = pkt;
 	struct bsg_job *bsg_job = sp->u.bsg_job;
 	struct fc_bsg_request *bsg_request = bsg_job->request;
 
@@ -3296,8 +3299,8 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
         els_iocb->handle = sp->handle;
 	els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
 	els_iocb->tx_dsd_count = cpu_to_le16(bsg_job->request_payload.sg_cnt);
-	els_iocb->vp_index = sp->vha->vp_idx;
-        els_iocb->sof_type = EST_SOFI3;
+
+	qla_els_set_vp_sof(sp->vha, pkt, sp->vha->vp_idx);
 	els_iocb->rx_dsd_count = cpu_to_le16(bsg_job->reply_payload.sg_cnt);
 
 	els_iocb->opcode =
@@ -4129,6 +4132,11 @@ qla2x00_start_sp(srb_t *sp)
 		break;
 	case SRB_ELS_CMD_HST_NOLOGIN:
 		qla_els_pt_iocb(sp->vha, pkt,  &sp->u.bsg_cmd.u.els_arg);
+		/*
+		 * els_entry_24xx::handle and els_entry_24xx_ext::handle are
+		 * both u32 at offset 4, so a 24xx-view write is layout-
+		 * compatible with both strides.
+		 */
 		((struct els_entry_24xx *)pkt)->handle = sp->handle;
 		break;
 	case SRB_CT_CMD:
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 76c66f060b7b..6ee16ee644d4 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -83,6 +83,8 @@ qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
 	dma_addr_t dma;
 	uint32_t fctl;
 	int rval;
+	void *rsp_pkt;
+	size_t rsp_sz;
 
 	ql_dbg(ql_dbg_init, vha, 0x0286, "%s: entered.\n", __func__);
 
@@ -95,15 +97,22 @@ qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
 	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0287,
 	    (uint8_t *)abts, sizeof(*abts));
 
-	rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els), &dma,
+	if (IS_QLA29XX(ha))
+		rsp_sz = sizeof(struct els_entry_24xx_ext);
+	else
+		rsp_sz = sizeof(struct els_entry_24xx);
+
+	rsp_pkt = dma_alloc_coherent(&ha->pdev->dev, rsp_sz, &dma,
 	    GFP_KERNEL);
-	if (!rsp_els) {
+	if (!rsp_pkt) {
 		ql_log(ql_log_warn, vha, 0x0287,
 		    "Failed allocate dma buffer ABTS/ELS RSP.\n");
 		return;
 	}
+	rsp_els = rsp_pkt;
 
 	/* terminate exchange */
+	memset(rsp_pkt, 0, rsp_sz);
 	rsp_els->entry_type = ELS_IOCB_TYPE;
 	rsp_els->entry_count = 1;
 	rsp_els->nport_handle = cpu_to_le16(~0);
@@ -115,8 +124,8 @@ qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
 	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0283,
 	    "-------- ELS RSP -------\n");
 	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0283,
-	    (uint8_t *)rsp_els, sizeof(*rsp_els));
-	rval = qla2x00_issue_iocb(vha, rsp_els, dma, 0);
+	    (uint8_t *)rsp_pkt, rsp_sz);
+	rval = qla2x00_issue_iocb(vha, rsp_pkt, dma, 0);
 	if (rval) {
 		ql_log(ql_log_warn, vha, 0x0288,
 		    "%s: iocb failed to execute -> %x\n", __func__, rval);
@@ -131,7 +140,7 @@ qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
 	}
 
 	/* send ABTS response */
-	abts_rsp = (void *)rsp_els;
+	abts_rsp = rsp_pkt;
 	memset(abts_rsp, 0, sizeof(*abts_rsp));
 	abts_rsp->entry_type = ABTS_RSP_TYPE;
 	abts_rsp->entry_count = 1;
@@ -182,7 +191,7 @@ qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
 		    "%s: done.\n", __func__);
 	}
 
-	dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els), rsp_els, dma);
+	dma_free_coherent(&ha->pdev->dev, rsp_sz, rsp_pkt, dma);
 }
 
 /**
@@ -2437,7 +2446,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
 	case SRB_ELS_CMD_HST_NOLOGIN:
 		type = "els";
 		{
-			struct els_entry_24xx *els = (void *)pkt;
+			__le16 ctl_flags =
+				((struct els_entry_24xx *)pkt)->control_flags;
 			struct qla_bsg_auth_els_request *p =
 				(struct qla_bsg_auth_els_request *)bsg_job->request;
 
@@ -2447,7 +2457,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
 			     e->d_id[2], e->d_id[1], e->d_id[0],
 			     comp_status, p->e.extra_rx_xchg_address, bsg_job);
 
-			if (!(le16_to_cpu(els->control_flags) & ECF_PAYLOAD_DESCR_MASK)) {
+			if (!(le16_to_cpu(ctl_flags) & ECF_PAYLOAD_DESCR_MASK)) {
 				if (sp->remap.remapped) {
 					n = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
 						bsg_job->reply_payload.sg_cnt,
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index ad0531ffedab..d748be56c0be 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -6211,8 +6211,10 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
 	uint8_t *sfp = NULL;
 	uint16_t sfp_flags = 0;
 	uint rsp_payload_length = sizeof(*rsp_payload);
-	uint8_t vp_idx;
+	u16 vp_idx;
 	size_t purex_sz;
+	size_t rsp_els_sz;
+	void *rsp_els_pkt = NULL;
 	int rval;
 
 	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0180,
@@ -6240,13 +6242,19 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
 		    rsp_payload_length);
 	}
 
-	rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els),
+	if (IS_QLA29XX(ha))
+		rsp_els_sz = sizeof(struct els_entry_24xx_ext);
+	else
+		rsp_els_sz = sizeof(struct els_entry_24xx);
+
+	rsp_els_pkt = dma_alloc_coherent(&ha->pdev->dev, rsp_els_sz,
 	    &rsp_els_dma, GFP_KERNEL);
-	if (!rsp_els) {
+	if (!rsp_els_pkt) {
 		ql_log(ql_log_warn, vha, 0x0183,
-		    "Failed allocate dma buffer ELS RSP.\n");
+		    "Failed to allocate dma buffer ELS RSP.\n");
 		goto dealloc;
 	}
+	rsp_els = rsp_els_pkt;
 
 	rsp_payload = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_payload),
 	    &rsp_payload_dma, GFP_KERNEL);
@@ -6270,12 +6278,12 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
 	rsp_els->handle = 0;
 	rsp_els->nport_handle = purex->nport_handle;
 	rsp_els->tx_dsd_count = cpu_to_le16(1);
-	rsp_els->vp_index = vp_idx;
-	rsp_els->sof_type = EST_SOFI3;
 	rsp_els->rx_xchg_address = purex->rx_xchg_addr;
 	rsp_els->rx_dsd_count = 0;
 	rsp_els->opcode = purex->els_frame_payload[0];
 
+	qla_els_set_vp_sof(vha, rsp_els_pkt, vp_idx);
+
 	rsp_els->d_id[0] = purex->s_id[0];
 	rsp_els->d_id[1] = purex->s_id[1];
 	rsp_els->d_id[2] = purex->s_id[2];
@@ -6575,13 +6583,13 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
 	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0184,
 	    "-------- ELS RSP -------\n");
 	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0185,
-	    rsp_els, sizeof(*rsp_els));
+	    rsp_els_pkt, rsp_els_sz);
 	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0186,
 	    "-------- ELS RSP PAYLOAD -------\n");
 	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0187,
 	    rsp_payload, rsp_payload_length);
 
-	rval = qla2x00_issue_iocb(vha, rsp_els, rsp_els_dma, 0);
+	rval = qla2x00_issue_iocb(vha, rsp_els_pkt, rsp_els_dma, 0);
 
 	if (rval) {
 		ql_log(ql_log_warn, vha, 0x0188,
@@ -6605,9 +6613,9 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
 	if (rsp_payload)
 		dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_payload),
 		    rsp_payload, rsp_payload_dma);
-	if (rsp_els)
-		dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els),
-		    rsp_els, rsp_els_dma);
+	if (rsp_els_pkt)
+		dma_free_coherent(&ha->pdev->dev, rsp_els_sz,
+		    rsp_els_pkt, rsp_els_dma);
 }
 
 void
@@ -8375,6 +8383,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct device_reg_82xx) != 1288);
 	BUILD_BUG_ON(sizeof(struct device_reg_fx00) != 216);
 	BUILD_BUG_ON(sizeof(struct els_entry_24xx) != 64);
+	BUILD_BUG_ON(sizeof(struct els_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct els_sts_entry_24xx) != 64);
 	BUILD_BUG_ON(sizeof(struct fxdisc_entry_fx00) != 64);
 	BUILD_BUG_ON(sizeof(struct imm_ntfy_from_isp) != 64);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 33/60] scsi: qla2xxx: Add size check for ELS status entry layout on 29xx
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (31 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 32/60] scsi: qla2xxx: Update handling of ELS IOCBs " Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 12:34   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 34/60] scsi: qla2xxx: Add 29xx extended logio IOCB support Nilesh Javali
                   ` (26 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Add a BUILD_BUG_ON in qla2x00_module_init() to validate that struct
els_sts_entry_24xx_ext is 128 bytes, matching the 29xx firmware IOCB
size.

The extended layout (29xx) overlays the base els_sts_entry_24xx for
every field read in qla24xx_els_ct_entry(): comp_status,
total_byte_count, error_subcode_1/2, d_id[], s_id[], and
control_flags all sit at byte-identical offsets in both structs.  Only
vp_index/sof_type at offset 14-15 differs (bit-packed differently in
the ext variant), but that field is write-only on the issue path and
never read in this completion handler.

Add a docblock at the top of qla24xx_els_ct_entry() documenting this
layout property.  Improve a few log messages for clarity.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_isr.c | 31 +++++++++++++++++++++++--------
 drivers/scsi/qla2xxx/qla_os.c  |  1 +
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 6ee16ee644d4..173b37b03d61 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -2411,6 +2411,22 @@ static void
 qla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
 		     void *pkt, int iocb_type)
 {
+	/*
+	 * els_sts_entry_24xx_ext (29xx) overlays els_sts_entry_24xx for every
+	 * field touched in this completion handler: comp_status (offset 8),
+	 * total_byte_count (32), error_subcode_1 (36), error_subcode_2 (40),
+	 * d_id[]/s_id[] (24..29), control_flags (30) all sit at byte-identical
+	 * offsets in both layouts (only vp_index/sof_type at offset 14-15 are
+	 * bit-packed differently, and that field is write-only on the issue
+	 * path -- we never read it here). All reads in this function are
+	 * therefore stride-agnostic and go through a single struct
+	 * els_sts_entry_24xx * view; the trailing reserved_4[] of the extended
+	 * layout is irrelevant on completion.
+	 *
+	 * Likewise els_entry_24xx_ext overlays els_entry_24xx through
+	 * control_flags (offset 30), so the SRB_ELS_CMD_HST_NOLOGIN ctl_flags
+	 * read below also goes through the 24xx view.
+	 */
 	struct sts_entry_24xx *sts24 = pkt;
 	struct els_sts_entry_24xx *ese = (struct els_sts_entry_24xx *)pkt;
 	const char func[] = "ELS_CT_IOCB";
@@ -2452,7 +2468,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
 				(struct qla_bsg_auth_els_request *)bsg_job->request;
 
 			ql_dbg(ql_dbg_user, vha, 0x700f,
-			     "%s %s. portid=%02x%02x%02x status %x xchg %x bsg ptr %p\n",
+			     "%s %s complete portid=%02x%02x%02x status %x xchg %x bsg ptr %p\n",
 			     __func__, sc_to_str(p->e.sub_cmd),
 			     e->d_id[2], e->d_id[1], e->d_id[0],
 			     comp_status, p->e.extra_rx_xchg_address, bsg_job);
@@ -2513,14 +2529,15 @@ qla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
 		} else {
 			if (comp_status == CS_DATA_UNDERRUN) {
 				res =  DID_OK << 16;
-				els->u.els_plogi.len = cpu_to_le16(le32_to_cpu(
-					ese->total_byte_count));
+				els->u.els_plogi.len = cpu_to_le16(
+					le32_to_cpu(ese->total_byte_count));
 
 				if (sp->remap.remapped &&
 				    ((u8 *)sp->remap.rsp.buf)[0] == ELS_LS_ACC) {
 					ql_dbg(ql_dbg_user, vha, 0x503f,
 					    "%s IOCB Done LS_ACC %02x%02x%02x -> %02x%02x%02x",
-					    __func__, e->s_id[0], e->s_id[2], e->s_id[1],
+					    __func__,
+					    e->s_id[0], e->s_id[2], e->s_id[1],
 					    e->d_id[2], e->d_id[1], e->d_id[0]);
 					logit = 0;
 				}
@@ -2548,8 +2565,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
 					ql_dbg(ql_dbg_user, vha, 0x503f,
 					    "subcode 1=0x%x subcode 2=0x%x bytes=0x%x %02x%02x%02x -> %02x%02x%02x\n",
 					    fw_status[1], fw_status[2],
-					    le32_to_cpu(((struct els_sts_entry_24xx *)
-						pkt)->total_byte_count),
+					    le32_to_cpu(ese->total_byte_count),
 					    e->s_id[0], e->s_id[2], e->s_id[1],
 					    e->d_id[2], e->d_id[1], e->d_id[0]);
 				}
@@ -2566,8 +2582,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
 				ql_log(ql_log_info, vha, 0x503f,
 				    "subcode 1=0x%x subcode 2=0x%x bytes=0x%x %02x%02x%02x -> %02x%02x%02x\n",
 				    fw_status[1], fw_status[2],
-				    le32_to_cpu(((struct els_sts_entry_24xx *)
-				    pkt)->total_byte_count),
+				    le32_to_cpu(ese->total_byte_count),
 				    e->s_id[0], e->s_id[2], e->s_id[1],
 				    e->d_id[2], e->d_id[1], e->d_id[0]);
 			}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index d748be56c0be..6ce29157a72c 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8385,6 +8385,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct els_entry_24xx) != 64);
 	BUILD_BUG_ON(sizeof(struct els_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct els_sts_entry_24xx) != 64);
+	BUILD_BUG_ON(sizeof(struct els_sts_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct fxdisc_entry_fx00) != 64);
 	BUILD_BUG_ON(sizeof(struct imm_ntfy_from_isp) != 64);
 	BUILD_BUG_ON(sizeof(struct init_cb_24xx) != 128);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 34/60] scsi: qla2xxx: Add 29xx extended logio IOCB support
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (32 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 33/60] scsi: qla2xxx: Add size check for ELS status entry layout on 29xx Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 12:36   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 35/60] scsi: qla2xxx: Enhance task management IOCB handling for 29xx series Nilesh Javali
                   ` (25 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

The 29xx series uses a wider IOCB stride (128 bytes vs 64 bytes).
The logio_entry_24xx_ext layout extends logio_entry_24xx with a
wider vp_index field (__le16 vs u8) while keeping all other
read-side fields (comp_status, io_parameter[0..10], entry_status)
at identical offsets and widths.

Update the logio IOCB builder functions (qla24xx_login_iocb,
qla24xx_logout_iocb, qla24xx_prli_iocb, qla24xx_prlo_iocb,
qla24xx_adisc_iocb) to accept a void pointer and dispatch the
vp_index write through IS_QLA29XX(), using an inline cast to the
extended layout at the single write site.

In the completion handler qla24xx_logio_entry(), accept a void
pointer and read through a single logio_entry_24xx view since all
accessed fields sit at the same offsets in both layouts.  Use the
qla_req_entry_size() helper for the dump buffer size.

In qla24xx_login_fabric() and qla24xx_fabric_logout(), allocate
through a void pointer from the DMA pool and dispatch vp_index
via the same inline-cast pattern.

Add a BUILD_BUG_ON for logio_entry_24xx_ext to enforce the 128-byte
size invariant at compile time.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_iocb.c | 48 ++++++++++++++++++++++++++-------
 drivers/scsi/qla2xxx/qla_isr.c  | 41 ++++++++++++++++------------
 drivers/scsi/qla2xxx/qla_mbx.c  | 35 ++++++++++++++++--------
 drivers/scsi/qla2xxx/qla_os.c   |  1 +
 4 files changed, 87 insertions(+), 38 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 45d6837100ad..d0d3a56affdc 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2488,8 +2488,9 @@ qla2x00_alloc_iocbs(struct scsi_qla_host *vha, srb_t *sp)
 }
 
 static void
-qla24xx_prli_iocb(srb_t *sp, struct logio_entry_24xx *logio)
+qla24xx_prli_iocb(srb_t *sp, void *pkt)
 {
+	struct logio_entry_24xx *logio = pkt;
 	struct srb_iocb *lio = &sp->u.iocb_cmd;
 
 	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
@@ -2516,12 +2517,17 @@ qla24xx_prli_iocb(srb_t *sp, struct logio_entry_24xx *logio)
 	logio->port_id[0] = sp->fcport->d_id.b.al_pa;
 	logio->port_id[1] = sp->fcport->d_id.b.area;
 	logio->port_id[2] = sp->fcport->d_id.b.domain;
-	logio->vp_index = sp->vha->vp_idx;
+	if (IS_QLA29XX(sp->vha->hw))
+		((struct logio_entry_24xx_ext *)pkt)->vp_index =
+		    cpu_to_le16(sp->vha->vp_idx);
+	else
+		logio->vp_index = sp->vha->vp_idx;
 }
 
 static void
-qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio)
+qla24xx_login_iocb(srb_t *sp, void *pkt)
 {
+	struct logio_entry_24xx *logio = pkt;
 	struct srb_iocb *lio = &sp->u.iocb_cmd;
 
 	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
@@ -2546,7 +2552,11 @@ qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio)
 	logio->port_id[0] = sp->fcport->d_id.b.al_pa;
 	logio->port_id[1] = sp->fcport->d_id.b.area;
 	logio->port_id[2] = sp->fcport->d_id.b.domain;
-	logio->vp_index = sp->vha->vp_idx;
+	if (IS_QLA29XX(sp->vha->hw))
+		((struct logio_entry_24xx_ext *)pkt)->vp_index =
+		    cpu_to_le16(sp->vha->vp_idx);
+	else
+		logio->vp_index = sp->vha->vp_idx;
 }
 
 static void
@@ -2574,9 +2584,11 @@ qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx)
 }
 
 static void
-qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio)
+qla24xx_logout_iocb(srb_t *sp, void *pkt)
 {
+	struct logio_entry_24xx *logio = pkt;
 	u16 control_flags = LCF_COMMAND_LOGO;
+
 	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
 
 	if (sp->fcport->explicit_logout) {
@@ -2593,7 +2605,11 @@ qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio)
 	logio->port_id[0] = sp->fcport->d_id.b.al_pa;
 	logio->port_id[1] = sp->fcport->d_id.b.area;
 	logio->port_id[2] = sp->fcport->d_id.b.domain;
-	logio->vp_index = sp->vha->vp_idx;
+	if (IS_QLA29XX(sp->vha->hw))
+		((struct logio_entry_24xx_ext *)pkt)->vp_index =
+		    cpu_to_le16(sp->vha->vp_idx);
+	else
+		logio->vp_index = sp->vha->vp_idx;
 }
 
 static void
@@ -2615,12 +2631,18 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx)
 }
 
 static void
-qla24xx_adisc_iocb(srb_t *sp, struct logio_entry_24xx *logio)
+qla24xx_adisc_iocb(srb_t *sp, void *pkt)
 {
+	struct logio_entry_24xx *logio = pkt;
+
 	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
 	logio->control_flags = cpu_to_le16(LCF_COMMAND_ADISC);
 	logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
-	logio->vp_index = sp->vha->vp_idx;
+	if (IS_QLA29XX(sp->vha->hw))
+		((struct logio_entry_24xx_ext *)pkt)->vp_index =
+		    cpu_to_le16(sp->vha->vp_idx);
+	else
+		logio->vp_index = sp->vha->vp_idx;
 }
 
 static void
@@ -3983,8 +4005,10 @@ qla25xx_ctrlvp_iocb(srb_t *sp, struct vp_ctrl_entry_24xx *vce)
 }
 
 static void
-qla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio)
+qla24xx_prlo_iocb(srb_t *sp, void *pkt)
 {
+	struct logio_entry_24xx *logio = pkt;
+
 	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
 	logio->control_flags =
 	    cpu_to_le16(LCF_COMMAND_PRLO|LCF_IMPL_PRLO);
@@ -3993,7 +4017,11 @@ qla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio)
 	logio->port_id[0] = sp->fcport->d_id.b.al_pa;
 	logio->port_id[1] = sp->fcport->d_id.b.area;
 	logio->port_id[2] = sp->fcport->d_id.b.domain;
-	logio->vp_index = sp->fcport->vha->vp_idx;
+	if (IS_QLA29XX(sp->vha->hw))
+		((struct logio_entry_24xx_ext *)pkt)->vp_index =
+		    cpu_to_le16(sp->fcport->vha->vp_idx);
+	else
+		logio->vp_index = sp->fcport->vha->vp_idx;
 }
 
 static int qla_get_iocbs_resource(struct srb *sp)
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 173b37b03d61..d76f201d694a 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -2635,8 +2635,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
 }
 
 static void
-qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
-    struct logio_entry_24xx *logio)
+qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, void *pkt)
 {
 	const char func[] = "LOGIO-IOCB";
 	const char *type;
@@ -2646,8 +2645,20 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
 	uint16_t *data;
 	uint32_t iop[2];
 	int logit = 1;
+	struct qla_hw_data *ha = vha->hw;
+	/*
+	 * logio_entry_24xx_ext overlays logio_entry_24xx through
+	 * io_parameter[10]: comp_status, io_parameter[0..10] and
+	 * entry_status are at identical offsets and types in both layouts
+	 * (only vp_index width differs, and that field is write-only on
+	 * the issue path).  So all reads in this completion handler are
+	 * stride-agnostic and we read through a single struct
+	 * logio_entry_24xx * view; the trailing reserved_2[64] of the
+	 * extended layout is irrelevant here.
+	 */
+	struct logio_entry_24xx *logio = pkt;
 
-	sp = qla2x00_get_sp_from_handle(vha, func, req, logio);
+	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
 	if (!sp)
 		return;
 
@@ -2667,7 +2678,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
 		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
 		    logio->entry_status);
 		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x504d,
-		    logio, sizeof(*logio));
+		    pkt, qla_rsp_entry_size(ha));
 
 		goto logio_done;
 	}
@@ -2678,7 +2689,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
 		    type, sp->handle, fcport->d_id.b24, fcport->port_name,
 		    le32_to_cpu(logio->io_parameter[0]));
 
-		vha->hw->exch_starvation = 0;
+		ha->exch_starvation = 0;
 		data[0] = MBS_COMMAND_COMPLETE;
 
 		if (sp->type == SRB_PRLI_CMD) {
@@ -2717,6 +2728,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
 
 	iop[0] = le32_to_cpu(logio->io_parameter[0]);
 	iop[1] = le32_to_cpu(logio->io_parameter[1]);
+
 	lio->u.logio.iop[0] = iop[0];
 	lio->u.logio.iop[1] = iop[1];
 	switch (iop[0]) {
@@ -2741,14 +2753,14 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
 		data[0] = MBS_COMMAND_ERROR;
 		break;
 	case LSC_SCODE_NOXCB:
-		vha->hw->exch_starvation++;
-		if (vha->hw->exch_starvation > 5) {
+		ha->exch_starvation++;
+		if (ha->exch_starvation > 5) {
 			ql_log(ql_log_warn, vha, 0xd046,
 			    "Exchange starvation. Resetting RISC\n");
 
-			vha->hw->exch_starvation = 0;
+			ha->exch_starvation = 0;
 
-			if (IS_P3P_TYPE(vha->hw))
+			if (IS_P3P_TYPE(ha))
 				set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
 			else
 				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -2764,16 +2776,12 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
 		ql_log(ql_log_warn, sp->vha, 0x5037, "Async-%s failed: "
 		       "handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n",
 		       type, sp->handle, fcport->d_id.b24, fcport->port_name,
-		       le16_to_cpu(logio->comp_status),
-		       le32_to_cpu(logio->io_parameter[0]),
-		       le32_to_cpu(logio->io_parameter[1]));
+		       le16_to_cpu(logio->comp_status), iop[0], iop[1]);
 	else
 		ql_dbg(ql_dbg_disc, sp->vha, 0x5037, "Async-%s failed: "
 		       "handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n",
 		       type, sp->handle, fcport->d_id.b24, fcport->port_name,
-		       le16_to_cpu(logio->comp_status),
-		       le32_to_cpu(logio->io_parameter[0]),
-		       le32_to_cpu(logio->io_parameter[1]));
+		       le16_to_cpu(logio->comp_status), iop[0], iop[1]);
 
 logio_done:
 	sp->done(sp, 0);
@@ -4181,8 +4189,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 			    (struct vp_rpt_id_entry_24xx *)pkt);
 			break;
 		case LOGINOUT_PORT_IOCB_TYPE:
-			qla24xx_logio_entry(vha, rsp->req,
-			    (struct logio_entry_24xx *)pkt);
+			qla24xx_logio_entry(vha, rsp->req, pkt);
 			break;
 		case CT_IOCB_TYPE:
 			qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index f9b326c02055..461b11df2e7e 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -2573,7 +2573,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
     uint8_t area, uint8_t al_pa, uint16_t *mb, uint8_t opt)
 {
 	int		rval;
-
+	void		*lg_buf;
 	struct logio_entry_24xx *lg;
 	dma_addr_t	lg_dma;
 	uint32_t	iop[2];
@@ -2588,12 +2588,13 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
 	else
 		req = ha->req_q_map[0];
 
-	lg = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
-	if (lg == NULL) {
+	lg_buf = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
+	if (!lg_buf) {
 		ql_log(ql_log_warn, vha, 0x1062,
 		    "Failed to allocate login IOCB.\n");
 		return QLA_MEMORY_ALLOC_FAILED;
 	}
+	lg = lg_buf;
 
 	lg->entry_type = LOGINOUT_PORT_IOCB_TYPE;
 	lg->entry_count = 1;
@@ -2607,8 +2608,13 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
 	lg->port_id[0] = al_pa;
 	lg->port_id[1] = area;
 	lg->port_id[2] = domain;
-	lg->vp_index = vha->vp_idx;
-	rval = qla2x00_issue_iocb_timeout(vha, lg, lg_dma, 0,
+	if (IS_QLA29XX(ha))
+		((struct logio_entry_24xx_ext *)lg)->vp_index =
+		    cpu_to_le16(vha->vp_idx);
+	else
+		lg->vp_index = vha->vp_idx;
+
+	rval = qla2x00_issue_iocb_timeout(vha, lg_buf, lg_dma, 0,
 	    (ha->r_a_tov / 10 * 2) + 2);
 	if (rval != QLA_SUCCESS) {
 		ql_dbg(ql_dbg_mbx, vha, 0x1063,
@@ -2678,7 +2684,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
 						 */
 	}
 
-	dma_pool_free(ha->s_dma_pool, lg, lg_dma);
+	dma_pool_free(ha->s_dma_pool, lg_buf, lg_dma);
 
 	return rval;
 }
@@ -2849,6 +2855,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
     uint8_t area, uint8_t al_pa)
 {
 	int		rval;
+	void		*lg_buf;
 	struct logio_entry_24xx *lg;
 	dma_addr_t	lg_dma;
 	struct qla_hw_data *ha = vha->hw;
@@ -2857,12 +2864,13 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
 	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x106d,
 	    "Entered %s.\n", __func__);
 
-	lg = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
-	if (lg == NULL) {
+	lg_buf = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
+	if (!lg_buf) {
 		ql_log(ql_log_warn, vha, 0x106e,
 		    "Failed to allocate logout IOCB.\n");
 		return QLA_MEMORY_ALLOC_FAILED;
 	}
+	lg = lg_buf;
 
 	req = vha->req;
 	lg->entry_type = LOGINOUT_PORT_IOCB_TYPE;
@@ -2875,8 +2883,13 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
 	lg->port_id[0] = al_pa;
 	lg->port_id[1] = area;
 	lg->port_id[2] = domain;
-	lg->vp_index = vha->vp_idx;
-	rval = qla2x00_issue_iocb_timeout(vha, lg, lg_dma, 0,
+	if (IS_QLA29XX(ha))
+		((struct logio_entry_24xx_ext *)lg)->vp_index =
+		    cpu_to_le16(vha->vp_idx);
+	else
+		lg->vp_index = vha->vp_idx;
+
+	rval = qla2x00_issue_iocb_timeout(vha, lg_buf, lg_dma, 0,
 	    (ha->r_a_tov / 10 * 2) + 2);
 	if (rval != QLA_SUCCESS) {
 		ql_dbg(ql_dbg_mbx, vha, 0x106f,
@@ -2898,7 +2911,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
 		    "Done %s.\n", __func__);
 	}
 
-	dma_pool_free(ha->s_dma_pool, lg, lg_dma);
+	dma_pool_free(ha->s_dma_pool, lg_buf, lg_dma);
 
 	return rval;
 }
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 6ce29157a72c..3feaaed43857 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8391,6 +8391,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct init_cb_24xx) != 128);
 	BUILD_BUG_ON(sizeof(struct init_cb_81xx) != 128);
 	BUILD_BUG_ON(sizeof(struct logio_entry_24xx) != 64);
+	BUILD_BUG_ON(sizeof(struct logio_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct mbx_entry) != 64);
 	BUILD_BUG_ON(sizeof(struct mid_init_cb_24xx) != 5252);
 	BUILD_BUG_ON(sizeof(struct mrk_entry_24xx) != 64);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 35/60] scsi: qla2xxx: Enhance task management IOCB handling for 29xx series
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (33 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 34/60] scsi: qla2xxx: Add 29xx extended logio IOCB support Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:13   ` sashiko-bot
  2026-06-12 12:37   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 36/60] scsi: qla2xxx: Add abort command " Nilesh Javali
                   ` (24 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Update qla24xx_tm_iocb() and __qla24xx_issue_tmf() to support the
extended task management structure (tsk_mgmt_entry_ext) for 29xx
adapters.

tsk_mgmt_entry_ext overlays tsk_mgmt_entry through control_flags
(offsets 0-27 are byte-identical): entry_type, entry_count, handle,
nport_handle, timeout, lun and control_flags sit at the same offsets
and widths.  The layouts diverge only after that point:

  - the 24xx layout has port_id[3] + u8 vp_index;
  - the ext layout has __le16 vp_index and no port_id.

Factor the common IOCB header writes through a single tsk_mgmt_entry *
view and branch on IS_QLA29XX() only for the diverging port_id /
vp_index assignments.  Change qla24xx_tm_iocb() to accept void *pkt
to allow casting to either structure type.

Add tsk_ext member to the tsk_mgmt_cmd union and a BUILD_BUG_ON size
check for the 128-byte extended structure.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_iocb.c | 31 ++++++++++++++++++++++---------
 drivers/scsi/qla2xxx/qla_mbx.c  | 18 ++++++++++++++----
 drivers/scsi/qla2xxx/qla_os.c   |  1 +
 3 files changed, 37 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index d0d3a56affdc..c62fef2e7624 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2667,7 +2667,7 @@ qla2x00_adisc_iocb(srb_t *sp, struct mbx_entry *mbx)
 }
 
 static void
-qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
+qla24xx_tm_iocb(srb_t *sp, void *pkt)
 {
 	uint32_t flags;
 	uint64_t lun;
@@ -2676,26 +2676,39 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
 	struct qla_hw_data *ha = vha->hw;
 	struct srb_iocb *iocb = &sp->u.iocb_cmd;
 	struct req_que *req = sp->qpair->req;
+	struct tsk_mgmt_entry *tsk;
 
 	flags = iocb->u.tmf.flags;
 	lun = iocb->u.tmf.lun;
 
+	/*
+	 * tsk_mgmt_entry_ext overlays tsk_mgmt_entry through control_flags
+	 * (offsets 0-27 are byte-identical), so the common header writes
+	 * go through one struct tsk_mgmt_entry * view.  The ext layout
+	 * has no port_id and uses a wider __le16 vp_index at a different
+	 * offset, so port_id / vp_index assignments diverge per stride.
+	 */
+	tsk = pkt;
 	tsk->entry_type = TSK_MGMT_IOCB_TYPE;
 	tsk->entry_count = 1;
 	tsk->handle = make_handle(req->id, tsk->handle);
 	tsk->nport_handle = cpu_to_le16(fcport->loop_id);
 	tsk->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
 	tsk->control_flags = cpu_to_le32(flags);
-	tsk->port_id[0] = fcport->d_id.b.al_pa;
-	tsk->port_id[1] = fcport->d_id.b.area;
-	tsk->port_id[2] = fcport->d_id.b.domain;
-	tsk->vp_index = fcport->vha->vp_idx;
+	if (IS_QLA29XX(ha)) {
+		((struct tsk_mgmt_entry_ext *)pkt)->vp_index =
+		    cpu_to_le16(fcport->vha->vp_idx);
+	} else {
+		tsk->port_id[0] = fcport->d_id.b.al_pa;
+		tsk->port_id[1] = fcport->d_id.b.area;
+		tsk->port_id[2] = fcport->d_id.b.domain;
+		tsk->vp_index = fcport->vha->vp_idx;
+	}
 
-	if (flags & (TCF_LUN_RESET | TCF_ABORT_TASK_SET|
-	    TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
+	if (flags & (TCF_LUN_RESET | TCF_ABORT_TASK_SET |
+	    TCF_CLEAR_TASK_SET | TCF_CLEAR_ACA)) {
 		int_to_scsilun(lun, &tsk->lun);
-		host_to_fcp_swap((uint8_t *)&tsk->lun,
-			sizeof(tsk->lun));
+		host_to_fcp_swap((uint8_t *)&tsk->lun, sizeof(tsk->lun));
 	}
 }
 
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 461b11df2e7e..fbf4579c8594 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -3419,6 +3419,7 @@ qla24xx_abort_command(srb_t *sp)
 struct tsk_mgmt_cmd {
 	union {
 		struct tsk_mgmt_entry tsk;
+		struct tsk_mgmt_entry_ext tsk_ext;
 		struct sts_entry_24xx sts;
 		struct sts_entry_24xx_ext sts_ext;
 	} p;
@@ -3458,16 +3459,25 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
 		return QLA_MEMORY_ALLOC_FAILED;
 	}
 
+	/*
+	 * tsk_mgmt_entry_ext overlays tsk_mgmt_entry through control_flags;
+	 * the common-header writes go through tsk->p.tsk and only port_id
+	 * (24xx-only) and vp_index width / offset diverge.
+	 */
 	tsk->p.tsk.entry_type = TSK_MGMT_IOCB_TYPE;
 	tsk->p.tsk.entry_count = 1;
 	tsk->p.tsk.handle = make_handle(req->id, tsk->p.tsk.handle);
 	tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id);
 	tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
 	tsk->p.tsk.control_flags = cpu_to_le32(type);
-	tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa;
-	tsk->p.tsk.port_id[1] = fcport->d_id.b.area;
-	tsk->p.tsk.port_id[2] = fcport->d_id.b.domain;
-	tsk->p.tsk.vp_index = fcport->vha->vp_idx;
+	if (IS_QLA29XX(ha)) {
+		tsk->p.tsk_ext.vp_index = cpu_to_le16(fcport->vha->vp_idx);
+	} else {
+		tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa;
+		tsk->p.tsk.port_id[1] = fcport->d_id.b.area;
+		tsk->p.tsk.port_id[2] = fcport->d_id.b.domain;
+		tsk->p.tsk.vp_index = fcport->vha->vp_idx;
+	}
 	if (type == TCF_LUN_RESET) {
 		int_to_scsilun(l, &tsk->p.tsk.lun);
 		host_to_fcp_swap((uint8_t *)&tsk->p.tsk.lun,
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 3feaaed43857..19daa60953af 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8427,6 +8427,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct sts_entry_24xx) != 64);
 	BUILD_BUG_ON(sizeof(struct sts_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct tsk_mgmt_entry) != 64);
+	BUILD_BUG_ON(sizeof(struct tsk_mgmt_entry_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct tsk_mgmt_entry_fx00) != 64);
 	BUILD_BUG_ON(sizeof(struct verify_chip_entry_84xx) != 64);
 	BUILD_BUG_ON(sizeof(struct verify_chip_rsp_84xx) != 52);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 36/60] scsi: qla2xxx: Add abort command handling for 29xx series
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (34 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 35/60] scsi: qla2xxx: Enhance task management IOCB handling for 29xx series Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:15   ` sashiko-bot
  2026-06-12 12:38   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 37/60] scsi: qla2xxx: Enhance ABTS processing " Nilesh Javali
                   ` (23 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Extend the abort-IOCB code path to support the 29xx extended
abort_entry_24xx_ext structure alongside the existing
abort_entry_24xx.

The two layouts overlay byte-for-byte through req_que_no
(offsets 0-17): entry_status (offset 3), the
nport_handle/comp_status union (offset 8), and options (offset 10)
sit at identical positions in both.  After that they diverge: the
24xx variant carries reserved_1[30], port_id[3], and a u8 vp_index
at offsets 48-51, while the ext variant places a __le16 vp_index at
offset 18 and drops port_id.  The drv / fw unions live at offset 56
in the 24xx layout but offset 24 in ext.

Leverage this overlap by using a single struct abort_entry_24xx *
view for the common header writes (entry_type, count, handle,
nport_handle, handle_to_abort, req_que_no) and completion-status
reads (entry_status, comp_status), branching on IS_QLA29XX() only
where the layouts genuinely diverge:

  - port_id (24xx-only) and vp_index width on the issue path
    (qla24xx_abort_iocb in qla_iocb.c, qla24xx_abort_command in
    qla_mbx.c);
  - drv / fw union access in qla_nvme_abort_set_option /
    qla_nvme_abort_process_comp_status (qla_nvme.c);
  - completion comp_status read in qla24xx_abort_iocb_entry
    (qla_isr.c) is stride-agnostic -- no IS_QLA29XX dispatch
    needed.

Function signatures in qla_nvme_abort_set_option(),
qla_nvme_abort_process_comp_status(), qla24xx_abort_iocb(), and
qla24xx_abort_iocb_entry() are widened to accept void * so both
struct variants can be passed through.  memset() uses
qla_req_entry_size(ha) to match the ring-slot size.  Response
status checking now reads comp_status instead of nport_handle.  A
BUILD_BUG_ON verifies abort_entry_24xx_ext is 128 bytes.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_gbl.h  |  6 ++--
 drivers/scsi/qla2xxx/qla_iocb.c | 52 ++++++++++++++++++++-----------
 drivers/scsi/qla2xxx/qla_isr.c  | 14 ++++++---
 drivers/scsi/qla2xxx/qla_mbx.c  | 45 ++++++++++++++++++---------
 drivers/scsi/qla2xxx/qla_nvme.c | 54 +++++++++++++++++++++++++--------
 drivers/scsi/qla2xxx/qla_os.c   |  1 +
 6 files changed, 120 insertions(+), 52 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 4ac3cb08fcc9..bba324febf09 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -989,10 +989,8 @@ extern void qla24xx_process_purex_list(struct purex_list *);
 extern void qla2x00_dfs_create_rport(scsi_qla_host_t *vha, struct fc_port *fp);
 extern void qla2x00_dfs_remove_rport(scsi_qla_host_t *vha, struct fc_port *fp);
 extern void qla_wait_nvme_release_cmd_kref(srb_t *sp);
-extern void qla_nvme_abort_set_option
-		(struct abort_entry_24xx *abt, srb_t *sp);
-extern void qla_nvme_abort_process_comp_status
-		(struct abort_entry_24xx *abt, srb_t *sp);
+extern void qla_nvme_abort_set_option(void *pkt, srb_t *sp);
+extern void qla_nvme_abort_process_comp_status(void *pkt, srb_t *sp);
 struct scsi_qla_host *qla_find_host_by_vp_idx(struct scsi_qla_host *vha,
 	uint16_t vp_idx);
 
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c62fef2e7624..8e435b170fe1 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -3868,32 +3868,50 @@ qla82xx_start_scsi(srb_t *sp)
 }
 
 static void
-qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb)
+qla24xx_abort_iocb(srb_t *sp, void *pkt)
 {
 	struct srb_iocb *aio = &sp->u.iocb_cmd;
 	scsi_qla_host_t *vha = sp->vha;
+	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = sp->qpair->req;
 	srb_t *orig_sp = sp->cmd_sp;
+	struct abort_entry_24xx *abt = pkt;
 
-	memset(abt_iocb, 0, sizeof(struct abort_entry_24xx));
-	abt_iocb->entry_type = ABORT_IOCB_TYPE;
-	abt_iocb->entry_count = 1;
-	abt_iocb->handle = make_handle(req->id, sp->handle);
-	if (sp->fcport) {
-		abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
-		abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
-		abt_iocb->port_id[1] = sp->fcport->d_id.b.area;
-		abt_iocb->port_id[2] = sp->fcport->d_id.b.domain;
-	}
-	abt_iocb->handle_to_abort =
-		make_handle(le16_to_cpu(aio->u.abt.req_que_no),
-			    aio->u.abt.cmd_hndl);
-	abt_iocb->vp_index = vha->vp_idx;
-	abt_iocb->req_que_no = aio->u.abt.req_que_no;
+	/*
+	 * abort_entry_24xx_ext overlays abort_entry_24xx through
+	 * req_que_no (offsets 0-17).  After that the layouts diverge:
+	 * the 24xx variant has 30 bytes of reserved_1 followed by
+	 * port_id[3] and a u8 vp_index at offsets 48-51, while the
+	 * ext variant places a __le16 vp_index at offset 18 and has
+	 * no port_id field.  Common-header writes go through one
+	 * struct abort_entry_24xx * view; only port_id / vp_index
+	 * branch on stride.
+	 */
+	memset(abt, 0, qla_req_entry_size(ha));
+	abt->entry_type = ABORT_IOCB_TYPE;
+	abt->entry_count = 1;
+	abt->handle = make_handle(req->id, sp->handle);
+	if (sp->fcport)
+		abt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+	abt->handle_to_abort =
+	    make_handle(le16_to_cpu(aio->u.abt.req_que_no),
+			aio->u.abt.cmd_hndl);
+	abt->req_que_no = aio->u.abt.req_que_no;
+	if (IS_QLA29XX(ha)) {
+		((struct abort_entry_24xx_ext *)pkt)->vp_index =
+		    cpu_to_le16(vha->vp_idx);
+	} else {
+		if (sp->fcport) {
+			abt->port_id[0] = sp->fcport->d_id.b.al_pa;
+			abt->port_id[1] = sp->fcport->d_id.b.area;
+			abt->port_id[2] = sp->fcport->d_id.b.domain;
+		}
+		abt->vp_index = vha->vp_idx;
+	}
 
 	/* need to pass original sp */
 	if (orig_sp)
-		qla_nvme_abort_set_option(abt_iocb, orig_sp);
+		qla_nvme_abort_set_option(pkt, orig_sp);
 
 	/* Send the command to the firmware */
 	wmb();
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index d76f201d694a..5b5ccf207535 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -4024,7 +4024,7 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
 
 static void
 qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
-	struct abort_entry_24xx *pkt)
+	void *pkt)
 {
 	const char func[] = "ABT_IOCB";
 	srb_t *sp;
@@ -4036,7 +4036,14 @@ qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
 		return;
 
 	abt = &sp->u.iocb_cmd;
-	abt->u.abt.comp_status = pkt->comp_status;
+	/*
+	 * abort_entry_24xx_ext overlays abort_entry_24xx through the
+	 * nport_handle/comp_status union at offset 8, so reading
+	 * comp_status is stride-agnostic and goes through the 24xx view.
+	 */
+	abt->u.abt.comp_status =
+	    ((struct abort_entry_24xx *)pkt)->comp_status;
+
 	orig_sp = sp->cmd_sp;
 	/* Need to pass original sp */
 	if (orig_sp)
@@ -4237,8 +4244,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 			qla_marker_iocb_entry(vha, rsp->req, pkt);
 			break;
 		case ABORT_IOCB_TYPE:
-			qla24xx_abort_iocb_entry(vha, rsp->req,
-			    (struct abort_entry_24xx *)pkt);
+			qla24xx_abort_iocb_entry(vha, rsp->req, pkt);
 			break;
 		case MBX_IOCB_TYPE:
 			qla24xx_mbx_iocb_entry(vha, rsp->req,
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index fbf4579c8594..ea39f3793296 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -3332,7 +3332,7 @@ qla24xx_abort_command(srb_t *sp)
 {
 	int		rval;
 	unsigned long   flags = 0;
-
+	void		*abt_buf;
 	struct abort_entry_24xx *abt;
 	dma_addr_t	abt_dma;
 	uint32_t	handle;
@@ -3364,28 +3364,42 @@ qla24xx_abort_command(srb_t *sp)
 		return QLA_ERR_NOT_FOUND;
 	}
 
-	abt = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &abt_dma);
-	if (abt == NULL) {
+	abt_buf = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &abt_dma);
+	if (abt_buf == NULL) {
 		ql_log(ql_log_warn, vha, 0x108d,
 		    "Failed to allocate abort IOCB.\n");
 		return QLA_MEMORY_ALLOC_FAILED;
 	}
+	abt = abt_buf;
 
+	/*
+	 * abort_entry_24xx_ext overlays abort_entry_24xx through
+	 * req_que_no (offsets 0-17), and entry_status (offset 3) and
+	 * comp_status (offset 8) sit at identical offsets in both, so
+	 * the common header writes and the completion-status reads are
+	 * stride-agnostic and go through the 24xx view.  Only port_id
+	 * (24xx-only) and vp_index width / offset diverge per stride.
+	 */
 	abt->entry_type = ABORT_IOCB_TYPE;
 	abt->entry_count = 1;
 	abt->handle = make_handle(req->id, abt->handle);
 	abt->nport_handle = cpu_to_le16(fcport->loop_id);
 	abt->handle_to_abort = make_handle(req->id, handle);
-	abt->port_id[0] = fcport->d_id.b.al_pa;
-	abt->port_id[1] = fcport->d_id.b.area;
-	abt->port_id[2] = fcport->d_id.b.domain;
-	abt->vp_index = fcport->vha->vp_idx;
-
 	abt->req_que_no = cpu_to_le16(req->id);
+	if (IS_QLA29XX(ha)) {
+		((struct abort_entry_24xx_ext *)abt)->vp_index =
+		    cpu_to_le16(fcport->vha->vp_idx);
+	} else {
+		abt->port_id[0] = fcport->d_id.b.al_pa;
+		abt->port_id[1] = fcport->d_id.b.area;
+		abt->port_id[2] = fcport->d_id.b.domain;
+		abt->vp_index = fcport->vha->vp_idx;
+	}
+
 	/* Need to pass original sp */
-	qla_nvme_abort_set_option(abt, sp);
+	qla_nvme_abort_set_option(abt_buf, sp);
 
-	rval = qla2x00_issue_iocb(vha, abt, abt_dma, 0);
+	rval = qla2x00_issue_iocb(vha, abt_buf, abt_dma, 0);
 	if (rval != QLA_SUCCESS) {
 		ql_dbg(ql_dbg_mbx, vha, 0x108e,
 		    "Failed to issue IOCB (%x).\n", rval);
@@ -3394,11 +3408,11 @@ qla24xx_abort_command(srb_t *sp)
 		    "Failed to complete IOCB -- error status (%x).\n",
 		    abt->entry_status);
 		rval = QLA_FUNCTION_FAILED;
-	} else if (abt->nport_handle != cpu_to_le16(0)) {
+	} else if (abt->comp_status != cpu_to_le16(0)) {
 		ql_dbg(ql_dbg_mbx, vha, 0x1090,
 		    "Failed to complete IOCB -- completion status (%x).\n",
-		    le16_to_cpu(abt->nport_handle));
-		if (abt->nport_handle == cpu_to_le16(CS_IOCB_ERROR))
+		    le16_to_cpu(abt->comp_status));
+		if (abt->comp_status == cpu_to_le16(CS_IOCB_ERROR))
 			rval = QLA_FUNCTION_PARAMETER_ERROR;
 		else
 			rval = QLA_FUNCTION_FAILED;
@@ -3406,12 +3420,13 @@ qla24xx_abort_command(srb_t *sp)
 		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1091,
 		    "Done %s.\n", __func__);
 	}
+
 	if (rval == QLA_SUCCESS)
-		qla_nvme_abort_process_comp_status(abt, sp);
+		qla_nvme_abort_process_comp_status(abt_buf, sp);
 
 	qla_wait_nvme_release_cmd_kref(sp);
 
-	dma_pool_free(ha->s_dma_pool, abt, abt_dma);
+	dma_pool_free(ha->s_dma_pool, abt_buf, abt_dma);
 
 	return rval;
 }
diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index 6ca300f8cc26..cdd9e657bec6 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -1056,36 +1056,69 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha)
 	return ret;
 }
 
-void qla_nvme_abort_set_option(struct abort_entry_24xx *abt, srb_t *orig_sp)
+void qla_nvme_abort_set_option(void *pkt, srb_t *orig_sp)
 {
 	struct qla_hw_data *ha;
+	struct abort_entry_24xx *abt = pkt;
 
 	if (!(ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(orig_sp)))
 		return;
 
 	ha = orig_sp->fcport->vha->hw;
 
+	/*
+	 * abort_entry_24xx_ext overlays abort_entry_24xx through 'options'
+	 * (offset 10), so options writes are stride-agnostic.  The drv
+	 * union sits at offset 56 in the 24xx layout but offset 24 in the
+	 * ext layout, so the drv writes need a typed pointer.
+	 */
 	WARN_ON_ONCE(abt->options & cpu_to_le16(BIT_0));
-	/* Use Driver Specified Retry Count */
 	abt->options |= cpu_to_le16(AOF_ABTS_RTY_CNT);
-	abt->drv.abts_rty_cnt = cpu_to_le16(2);
-	/* Use specified response timeout */
 	abt->options |= cpu_to_le16(AOF_RSP_TIMEOUT);
-	/* set it to 2 * r_a_tov in secs */
-	abt->drv.rsp_timeout = cpu_to_le16(2 * (ha->r_a_tov / 10));
+	if (IS_QLA29XX(ha)) {
+		struct abort_entry_24xx_ext *abt_ext = pkt;
+
+		abt_ext->drv.abts_rty_cnt = cpu_to_le16(2);
+		abt_ext->drv.rsp_timeout =
+		    cpu_to_le16(2 * (ha->r_a_tov / 10));
+	} else {
+		abt->drv.abts_rty_cnt = cpu_to_le16(2);
+		abt->drv.rsp_timeout = cpu_to_le16(2 * (ha->r_a_tov / 10));
+	}
 }
 
-void qla_nvme_abort_process_comp_status(struct abort_entry_24xx *abt, srb_t *orig_sp)
+void qla_nvme_abort_process_comp_status(void *pkt, srb_t *orig_sp)
 {
 	u16	comp_status;
 	struct scsi_qla_host *vha;
+	u8	rjt_vendor_unique, rjt_reason_expl, rjt_reason_code;
+	struct abort_entry_24xx *abt = pkt;
 
 	if (!(ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(orig_sp)))
 		return;
 
 	vha = orig_sp->fcport->vha;
 
+	/*
+	 * comp_status sits at offset 8 in both layouts (the
+	 * nport_handle/comp_status union), so the read is
+	 * stride-agnostic.  The fw union, like drv, lives at offset
+	 * 56 in the 24xx layout and offset 24 in the ext layout, so
+	 * those byte reads still need a typed pointer.
+	 */
 	comp_status = le16_to_cpu(abt->comp_status);
+	if (IS_QLA29XX(vha->hw)) {
+		struct abort_entry_24xx_ext *abt_ext = pkt;
+
+		rjt_vendor_unique = abt_ext->fw.ba_rjt_vendorUnique;
+		rjt_reason_expl = abt_ext->fw.ba_rjt_reasonCodeExpl;
+		rjt_reason_code = abt_ext->fw.ba_rjt_reasonCode;
+	} else {
+		rjt_vendor_unique = abt->fw.ba_rjt_vendorUnique;
+		rjt_reason_expl = abt->fw.ba_rjt_reasonCodeExpl;
+		rjt_reason_code = abt->fw.ba_rjt_reasonCode;
+	}
+
 	switch (comp_status) {
 	case CS_RESET:		/* reset event aborted */
 	case CS_ABORTED:	/* IOCB was cleaned */
@@ -1105,11 +1138,8 @@ void qla_nvme_abort_process_comp_status(struct abort_entry_24xx *abt, srb_t *ori
 	/* BA_RJT was received for the ABTS */
 	case CS_REJECT_RECEIVED:
 		ql_dbg(ql_dbg_async, vha, 0xf09e,
-		       "BA_RJT was received for the ABTS rjt_vendorUnique = %u",
-			abt->fw.ba_rjt_vendorUnique);
-		ql_dbg(ql_dbg_async + ql_dbg_mbx, vha, 0xf09e,
-		       "ba_rjt_reasonCodeExpl = %u, ba_rjt_reasonCode = %u\n",
-		       abt->fw.ba_rjt_reasonCodeExpl, abt->fw.ba_rjt_reasonCode);
+		    "BA_RJT was received for the ABTS rjt_vendorUnique=%u, ba_rjt_reasonCodeExpl=%u, ba_rjt_reasonCode=%u\n",
+		    rjt_vendor_unique, rjt_reason_expl, rjt_reason_code);
 		break;
 
 	case CS_COMPLETE:
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 19daa60953af..a0191bf0e9fd 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8358,6 +8358,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(ms_iocb_entry_t) != 64);
 	BUILD_BUG_ON(sizeof(request_t) != 64);
 	BUILD_BUG_ON(sizeof(struct abort_entry_24xx) != 64);
+	BUILD_BUG_ON(sizeof(struct abort_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct abort_iocb_entry_fx00) != 64);
 	BUILD_BUG_ON(sizeof(struct abts_entry_24xx) != 64);
 	BUILD_BUG_ON(sizeof(struct access_chip_84xx) != 64);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 37/60] scsi: qla2xxx: Enhance ABTS processing for 29xx series
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (35 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 36/60] scsi: qla2xxx: Add abort command " Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 12:41   ` Hannes Reinecke
  2026-06-12 15:12   ` sashiko-bot
  2026-06-12  9:53 ` [PATCH v2 38/60] scsi: qla2xxx: Update VP control IOCB handling " Nilesh Javali
                   ` (22 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Use extended ABTS entry structures (abts_entry_24xx_ext) for 29xx
series adapters to properly handle the larger 128-byte IOCB format.

Introduce type-generic macros (QLA_LOG_ABTS_RCV, QLA_BUILD_ABTS_BA_ACC,
QLA_LOG_ISSUE_ABTS_RSP) that leverage the shared field names between
abts_entry_24xx and abts_entry_24xx_ext to avoid code duplication.
Branch on IS_QLA29XX() for receive logging, exchange termination, and
BA_ACC response construction, with each path passing the correctly
typed pointer to the shared macros. The sof_type handling difference
(direct for 29xx bitfield vs & 0xf0 mask for legacy) is parameterized
through the sof_val macro argument.

Add BUILD_BUG_ON size check for struct abts_entry_24xx_ext.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_isr.c | 167 ++++++++++++++++++++-------------
 drivers/scsi/qla2xxx/qla_os.c  |   1 +
 2 files changed, 104 insertions(+), 64 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 5b5ccf207535..284d874392fd 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -72,15 +72,89 @@ static inline void display_Laser_info(scsi_qla_host_t *vha,
 		       mb3);
 }
 
+/*
+ * Type-generic helpers for qla24xx_process_abts().
+ * Both abts_entry_24xx and abts_entry_24xx_ext share field names for all
+ * accessed fields, so these macros expand correctly for either type.
+ */
+#define QLA_LOG_ABTS_RCV(vha, abts_ptr) do {				\
+	ql_log(ql_log_warn, (vha), 0x0287,				\
+	    "Processing ABTS xchg=%#x oxid=%#x rxid=%#x "		\
+	    "seqid=%#x seqcnt=%#x\n",					\
+	    (abts_ptr)->rx_xch_addr_to_abort, (abts_ptr)->ox_id,	\
+	    (abts_ptr)->rx_id, (abts_ptr)->seq_id,			\
+	    (abts_ptr)->seq_cnt);					\
+	ql_dbg(ql_dbg_init + ql_dbg_verbose, (vha), 0x0287,		\
+	    "-------- ABTS RCV -------\n");				\
+	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, (vha), 0x0287,	\
+	    (uint8_t *)(abts_ptr), sizeof(*(abts_ptr)));		\
+} while (0)
+
+#define QLA_BUILD_ABTS_BA_ACC(rsp, src, sof_val, fctl) do {		\
+	memset((rsp), 0, sizeof(*(rsp)));				\
+	(rsp)->entry_type = ABTS_RSP_TYPE;				\
+	(rsp)->entry_count = 1;						\
+	(rsp)->nport_handle = (src)->nport_handle;			\
+	(rsp)->vp_idx = (src)->vp_idx;					\
+	(rsp)->sof_type = (sof_val);					\
+	(rsp)->rx_xch_addr = (src)->rx_xch_addr;			\
+	(rsp)->d_id[0] = (src)->s_id[0];				\
+	(rsp)->d_id[1] = (src)->s_id[1];				\
+	(rsp)->d_id[2] = (src)->s_id[2];				\
+	(rsp)->r_ctl = FC_ROUTING_BLD | FC_R_CTL_BLD_BA_ACC;		\
+	(rsp)->s_id[0] = (src)->d_id[0];				\
+	(rsp)->s_id[1] = (src)->d_id[1];				\
+	(rsp)->s_id[2] = (src)->d_id[2];				\
+	(rsp)->cs_ctl = (src)->cs_ctl;					\
+	(fctl) = ~((src)->f_ctl[2] | 0x7F) << 16 |			\
+	    FC_F_CTL_LAST_SEQ | FC_F_CTL_END_SEQ | FC_F_CTL_SEQ_INIT;	\
+	(rsp)->f_ctl[0] = (fctl) >> 0 & 0xff;				\
+	(rsp)->f_ctl[1] = (fctl) >> 8 & 0xff;				\
+	(rsp)->f_ctl[2] = (fctl) >> 16 & 0xff;				\
+	(rsp)->type = FC_TYPE_BLD;					\
+	(rsp)->rx_id = (src)->rx_id;					\
+	(rsp)->ox_id = (src)->ox_id;					\
+	(rsp)->payload.ba_acc.aborted_rx_id = (src)->rx_id;		\
+	(rsp)->payload.ba_acc.aborted_ox_id = (src)->ox_id;		\
+	(rsp)->payload.ba_acc.high_seq_cnt = cpu_to_le16(~0);		\
+	(rsp)->rx_xch_addr_to_abort = (src)->rx_xch_addr_to_abort;	\
+} while (0)
+
+#define QLA_LOG_ISSUE_ABTS_RSP(vha, rsp, dma, rval) do {		\
+	ql_dbg(ql_dbg_init, (vha), 0x028b,				\
+	    "Sending BA ACC response to ABTS %#x...\n",			\
+	    (rsp)->rx_xch_addr_to_abort);				\
+	ql_dbg(ql_dbg_init + ql_dbg_verbose, (vha), 0x028b,		\
+	    "-------- ELS RSP -------\n");				\
+	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, (vha), 0x028b,	\
+	    (uint8_t *)(rsp), sizeof(*(rsp)));				\
+	(rval) = qla2x00_issue_iocb((vha), (rsp), (dma), 0);		\
+	if (rval) {							\
+		ql_log(ql_log_warn, (vha), 0x028c,			\
+		    "%s: iocb failed to execute -> %x\n",		\
+		    __func__, (rval));					\
+	} else if ((rsp)->comp_status) {				\
+		ql_log(ql_log_warn, (vha), 0x028d,			\
+		    "%s: iocb failed to complete -> "			\
+		    "completion=%#x subcode=(%#x,%#x)\n",		\
+		    __func__, (rsp)->comp_status,			\
+		    (rsp)->payload.error.subcode1,			\
+		    (rsp)->payload.error.subcode2);			\
+	} else {							\
+		ql_dbg(ql_dbg_init, (vha), 0x028ea,			\
+		    "%s: done.\n", __func__);				\
+	}								\
+} while (0)
+
 static void
 qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
 {
-	struct abts_entry_24xx *abts =
-	    (struct abts_entry_24xx *)&pkt->iocb;
 	struct qla_hw_data *ha = vha->hw;
+	struct abts_entry_24xx *abts = NULL;
+	struct abts_entry_24xx_ext *abts_ext = NULL;
 	struct els_entry_24xx *rsp_els;
-	struct abts_entry_24xx *abts_rsp;
 	dma_addr_t dma;
+	__le32 rx_xch_addr_to_abort;
 	uint32_t fctl;
 	int rval;
 	void *rsp_pkt;
@@ -88,19 +162,17 @@ qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
 
 	ql_dbg(ql_dbg_init, vha, 0x0286, "%s: entered.\n", __func__);
 
-	ql_log(ql_log_warn, vha, 0x0287,
-	    "Processing ABTS xchg=%#x oxid=%#x rxid=%#x seqid=%#x seqcnt=%#x\n",
-	    abts->rx_xch_addr_to_abort, abts->ox_id, abts->rx_id,
-	    abts->seq_id, abts->seq_cnt);
-	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0287,
-	    "-------- ABTS RCV -------\n");
-	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0287,
-	    (uint8_t *)abts, sizeof(*abts));
-
-	if (IS_QLA29XX(ha))
+	if (IS_QLA29XX(ha)) {
+		abts_ext = (struct abts_entry_24xx_ext *)&pkt->iocb;
+		QLA_LOG_ABTS_RCV(vha, abts_ext);
 		rsp_sz = sizeof(struct els_entry_24xx_ext);
-	else
+		rx_xch_addr_to_abort = abts_ext->rx_xch_addr_to_abort;
+	} else {
+		abts = (struct abts_entry_24xx *)&pkt->iocb;
+		QLA_LOG_ABTS_RCV(vha, abts);
 		rsp_sz = sizeof(struct els_entry_24xx);
+		rx_xch_addr_to_abort = abts->rx_xch_addr_to_abort;
+	}
 
 	rsp_pkt = dma_alloc_coherent(&ha->pdev->dev, rsp_sz, &dma,
 	    GFP_KERNEL);
@@ -116,11 +188,11 @@ qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
 	rsp_els->entry_type = ELS_IOCB_TYPE;
 	rsp_els->entry_count = 1;
 	rsp_els->nport_handle = cpu_to_le16(~0);
-	rsp_els->rx_xchg_address = abts->rx_xch_addr_to_abort;
+	rsp_els->rx_xchg_address = rx_xch_addr_to_abort;
 	rsp_els->control_flags = cpu_to_le16(EPD_RX_XCHG);
 	ql_dbg(ql_dbg_init, vha, 0x0283,
 	    "Sending ELS Response to terminate exchange %#x...\n",
-	    abts->rx_xch_addr_to_abort);
+	    rx_xch_addr_to_abort);
 	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0283,
 	    "-------- ELS RSP -------\n");
 	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0283,
@@ -140,60 +212,27 @@ qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
 	}
 
 	/* send ABTS response */
-	abts_rsp = rsp_pkt;
-	memset(abts_rsp, 0, sizeof(*abts_rsp));
-	abts_rsp->entry_type = ABTS_RSP_TYPE;
-	abts_rsp->entry_count = 1;
-	abts_rsp->nport_handle = abts->nport_handle;
-	abts_rsp->vp_idx = abts->vp_idx;
-	abts_rsp->sof_type = abts->sof_type & 0xf0;
-	abts_rsp->rx_xch_addr = abts->rx_xch_addr;
-	abts_rsp->d_id[0] = abts->s_id[0];
-	abts_rsp->d_id[1] = abts->s_id[1];
-	abts_rsp->d_id[2] = abts->s_id[2];
-	abts_rsp->r_ctl = FC_ROUTING_BLD | FC_R_CTL_BLD_BA_ACC;
-	abts_rsp->s_id[0] = abts->d_id[0];
-	abts_rsp->s_id[1] = abts->d_id[1];
-	abts_rsp->s_id[2] = abts->d_id[2];
-	abts_rsp->cs_ctl = abts->cs_ctl;
-	/* include flipping bit23 in fctl */
-	fctl = ~(abts->f_ctl[2] | 0x7F) << 16 |
-	    FC_F_CTL_LAST_SEQ | FC_F_CTL_END_SEQ | FC_F_CTL_SEQ_INIT;
-	abts_rsp->f_ctl[0] = fctl >> 0 & 0xff;
-	abts_rsp->f_ctl[1] = fctl >> 8 & 0xff;
-	abts_rsp->f_ctl[2] = fctl >> 16 & 0xff;
-	abts_rsp->type = FC_TYPE_BLD;
-	abts_rsp->rx_id = abts->rx_id;
-	abts_rsp->ox_id = abts->ox_id;
-	abts_rsp->payload.ba_acc.aborted_rx_id = abts->rx_id;
-	abts_rsp->payload.ba_acc.aborted_ox_id = abts->ox_id;
-	abts_rsp->payload.ba_acc.high_seq_cnt = cpu_to_le16(~0);
-	abts_rsp->rx_xch_addr_to_abort = abts->rx_xch_addr_to_abort;
-	ql_dbg(ql_dbg_init, vha, 0x028b,
-	    "Sending BA ACC response to ABTS %#x...\n",
-	    abts->rx_xch_addr_to_abort);
-	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x028b,
-	    "-------- ELS RSP -------\n");
-	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x028b,
-	    (uint8_t *)abts_rsp, sizeof(*abts_rsp));
-	rval = qla2x00_issue_iocb(vha, abts_rsp, dma, 0);
-	if (rval) {
-		ql_log(ql_log_warn, vha, 0x028c,
-		    "%s: iocb failed to execute -> %x\n", __func__, rval);
-	} else if (abts_rsp->comp_status) {
-		ql_log(ql_log_warn, vha, 0x028d,
-		    "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n",
-		    __func__, abts_rsp->comp_status,
-		    abts_rsp->payload.error.subcode1,
-		    abts_rsp->payload.error.subcode2);
+	if (IS_QLA29XX(ha)) {
+		struct abts_entry_24xx_ext *rsp_ext = rsp_pkt;
+
+		QLA_BUILD_ABTS_BA_ACC(rsp_ext, abts_ext,
+		    abts_ext->sof_type, fctl);
+		QLA_LOG_ISSUE_ABTS_RSP(vha, rsp_ext, dma, rval);
 	} else {
-		ql_dbg(ql_dbg_init, vha, 0x028ea,
-		    "%s: done.\n", __func__);
+		struct abts_entry_24xx *abts_rsp = rsp_pkt;
+
+		QLA_BUILD_ABTS_BA_ACC(abts_rsp, abts,
+		    abts->sof_type & 0xf0, fctl);
+		QLA_LOG_ISSUE_ABTS_RSP(vha, abts_rsp, dma, rval);
 	}
 
 	dma_free_coherent(&ha->pdev->dev, rsp_sz, rsp_pkt, dma);
 }
 
+#undef QLA_LOG_ABTS_RCV
+#undef QLA_BUILD_ABTS_BA_ACC
+#undef QLA_LOG_ISSUE_ABTS_RSP
+
 /**
  * __qla_consume_iocb - this routine is used to tell fw driver has processed
  *   or consumed the head IOCB along with the continuation IOCB's from the
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index a0191bf0e9fd..24a066b304d9 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8361,6 +8361,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct abort_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct abort_iocb_entry_fx00) != 64);
 	BUILD_BUG_ON(sizeof(struct abts_entry_24xx) != 64);
+	BUILD_BUG_ON(sizeof(struct abts_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct access_chip_84xx) != 64);
 	BUILD_BUG_ON(sizeof(struct access_chip_rsp_84xx) != 64);
 	BUILD_BUG_ON(sizeof(struct cmd_bidir) != 64);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 38/60] scsi: qla2xxx: Update VP control IOCB handling for 29xx series
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (36 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 37/60] scsi: qla2xxx: Enhance ABTS processing " Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 12:45   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 39/60] scsi: qla2xxx: Add build-time size check for VP config IOCB layout Nilesh Javali
                   ` (21 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Update VP control IOCB command and response handling to support the
29xx series adapters, which use the 128-byte vp_ctrl_entry_24xx_ext
layout.

Change the qla25xx_ctrlvp_iocb() and qla_ctrlvp_completed() function
signatures from typed struct pointers to void *, since callers already
pass a generic ring-slot pointer.  Both the standard 64-byte
vp_ctrl_entry_24xx and the 128-byte vp_ctrl_entry_24xx_ext are
layout-identical for every field touched in these helpers (entry_type,
handle, entry_count, command, vp_count, vp_idx_map, entry_status,
comp_status, vp_idx_failed), so a single struct vp_ctrl_entry_24xx *
view handles both adapter families without an IS_QLA29XX() branch.

Add a BUILD_BUG_ON size check for the extended structure.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_iocb.c | 23 ++++++++++++++++-------
 drivers/scsi/qla2xxx/qla_isr.c  | 13 +++++++++----
 drivers/scsi/qla2xxx/qla_os.c   |  1 +
 3 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 8e435b170fe1..a286e947fb21 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -4016,22 +4016,31 @@ qla_nvme_ls(srb_t *sp, struct pt_ls4_request *cmd_pkt)
 }
 
 static void
-qla25xx_ctrlvp_iocb(srb_t *sp, struct vp_ctrl_entry_24xx *vce)
+qla25xx_ctrlvp_iocb(srb_t *sp, void *pkt)
 {
+	/*
+	 * vp_ctrl_entry_24xx_ext is layout-identical to vp_ctrl_entry_24xx
+	 * for all fields touched here (entry_type, handle, entry_count,
+	 * command, vp_count, vp_idx_map) -- they all sit at the same
+	 * offsets and types in both structs, and the ext layout merely
+	 * tacks on flags/id/hopct/reserved at offset 32+.  So no
+	 * IS_QLA29XX(ha) dispatch is needed on the issue path.
+	 */
+	struct vp_ctrl_entry_24xx *vce = pkt;
 	int map, pos;
 
-	vce->entry_type = VP_CTRL_IOCB_TYPE;
-	vce->handle = sp->handle;
-	vce->entry_count = 1;
-	vce->command = cpu_to_le16(sp->u.iocb_cmd.u.ctrlvp.cmd);
-	vce->vp_count = cpu_to_le16(1);
-
 	/*
 	 * index map in firmware starts with 1; decrement index
 	 * this is ok as we never use index 0
 	 */
 	map = (sp->u.iocb_cmd.u.ctrlvp.vp_index - 1) / 8;
 	pos = (sp->u.iocb_cmd.u.ctrlvp.vp_index - 1) & 7;
+
+	vce->entry_type = VP_CTRL_IOCB_TYPE;
+	vce->handle = sp->handle;
+	vce->entry_count = 1;
+	vce->command = cpu_to_le16(sp->u.iocb_cmd.u.ctrlvp.cmd);
+	vce->vp_count = cpu_to_le16(1);
 	vce->vp_idx_map[map] |= 1 << pos;
 }
 
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 284d874392fd..9c12e99ba5bd 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -3052,13 +3052,19 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
 }
 
 static void qla_ctrlvp_completed(scsi_qla_host_t *vha, struct req_que *req,
-    struct vp_ctrl_entry_24xx *vce)
+				 void *pkt)
 {
 	const char func[] = "CTRLVP-IOCB";
+	/*
+	 * vp_ctrl_entry_24xx_ext overlays vp_ctrl_entry_24xx for all
+	 * fields read here (entry_status, comp_status, vp_idx_failed),
+	 * so the read goes through one struct vp_ctrl_entry_24xx * view.
+	 */
+	struct vp_ctrl_entry_24xx *vce = pkt;
 	srb_t *sp;
 	int rval = QLA_SUCCESS;
 
-	sp = qla2x00_get_sp_from_handle(vha, func, req, vce);
+	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
 	if (!sp)
 		return;
 
@@ -4290,8 +4296,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 			    (struct mbx_24xx_entry *)pkt);
 			break;
 		case VP_CTRL_IOCB_TYPE:
-			qla_ctrlvp_completed(vha, rsp->req,
-			    (struct vp_ctrl_entry_24xx *)pkt);
+			qla_ctrlvp_completed(vha, rsp->req, pkt);
 			break;
 		case PUREX_IOCB_TYPE:
 			if (IS_QLA29XX(ha)) {
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 24a066b304d9..bf5f3b16bdae 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8436,6 +8436,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct vf_evfp_entry_24xx) != 56);
 	BUILD_BUG_ON(sizeof(struct vp_config_entry_24xx) != 64);
 	BUILD_BUG_ON(sizeof(struct vp_ctrl_entry_24xx) != 64);
+	BUILD_BUG_ON(sizeof(struct vp_ctrl_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct vp_rpt_id_entry_24xx) != 64);
 	BUILD_BUG_ON(sizeof(sts21_entry_t) != 64);
 	BUILD_BUG_ON(sizeof(sts22_entry_t) != 64);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 39/60] scsi: qla2xxx: Add build-time size check for VP config IOCB layout
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (37 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 38/60] scsi: qla2xxx: Update VP control IOCB handling " Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 12:45   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 40/60] scsi: qla2xxx: Add size check for extended VP report ID entry Nilesh Javali
                   ` (20 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Add a BUILD_BUG_ON for struct vp_config_entry_24xx_ext to verify its
128-byte size at compile time alongside the existing 64-byte check for
struct vp_config_entry_24xx.

Document in qla24xx_modify_vp_config() that the ext variant overlays
the base 24xx layout for the first 64 bytes (all fields this helper
reads and writes), so the IOCB can be built through a single struct
vp_config_entry_24xx pointer regardless of the adapter's IOCB stride.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_mbx.c | 8 +++++++-
 drivers/scsi/qla2xxx/qla_os.c  | 1 +
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index ea39f3793296..bdf03d92e552 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -4372,6 +4372,13 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
 		return QLA_MEMORY_ALLOC_FAILED;
 	}
 
+	/*
+	 * vp_config_entry_24xx_ext overlays vp_config_entry_24xx for the
+	 * full 64-byte 24xx layout (the ext variant merely appends fields
+	 * at offset 64+ which this helper never touches), so the IOCB is
+	 * built and inspected through a single struct vp_config_entry_24xx
+	 * pointer regardless of adapter stride.
+	 */
 	vpmod->entry_type = VP_CONFIG_IOCB_TYPE;
 	vpmod->entry_count = 1;
 	vpmod->command = VCT_COMMAND_MOD_ENABLE_VPS;
@@ -4400,7 +4407,6 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
 		    le16_to_cpu(vpmod->comp_status));
 		rval = QLA_FUNCTION_FAILED;
 	} else {
-		/* EMPTY */
 		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10c0,
 		    "Done %s.\n", __func__);
 		fc_vport_set_state(vha->fc_vport, FC_VPORT_INITIALIZING);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index bf5f3b16bdae..397f2ffa56d1 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8435,6 +8435,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct verify_chip_rsp_84xx) != 52);
 	BUILD_BUG_ON(sizeof(struct vf_evfp_entry_24xx) != 56);
 	BUILD_BUG_ON(sizeof(struct vp_config_entry_24xx) != 64);
+	BUILD_BUG_ON(sizeof(struct vp_config_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct vp_ctrl_entry_24xx) != 64);
 	BUILD_BUG_ON(sizeof(struct vp_ctrl_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct vp_rpt_id_entry_24xx) != 64);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 40/60] scsi: qla2xxx: Add size check for extended VP report ID entry
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (38 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 39/60] scsi: qla2xxx: Add build-time size check for VP config IOCB layout Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:05   ` sashiko-bot
  2026-06-12 12:46   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 41/60] scsi: qla2xxx: Unify NVMe IOCB build path for 29xx and legacy adapters Nilesh Javali
                   ` (19 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Add reserved_end[64] padding to bring the struct to 128 bytes, matching
the hardware IOCB stride.  Change qla24xx_report_id_acquisition() to
accept a void pointer and extract vp_idx and vp_status from the extended
structure on 29xx series adapters, maintaining data integrity for the
larger IOCB format.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_fw29.h |  1 +
 drivers/scsi/qla2xxx/qla_gbl.h  |  3 +--
 drivers/scsi/qla2xxx/qla_isr.c  |  3 +--
 drivers/scsi/qla2xxx/qla_mbx.c  | 32 +++++++++++++++++++++-----------
 drivers/scsi/qla2xxx/qla_os.c   |  1 +
 5 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_fw29.h b/drivers/scsi/qla2xxx/qla_fw29.h
index 088a220472a5..a4aa5bacb171 100644
--- a/drivers/scsi/qla2xxx/qla_fw29.h
+++ b/drivers/scsi/qla2xxx/qla_fw29.h
@@ -693,6 +693,7 @@ struct vp_rpt_id_entry_24xx_ext {
 			uint8_t remote_nport_id[4];
 		} f2;
 	} u;
+	uint8_t reserved_end[64];
 };
 
 /*
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index bba324febf09..cb48b9e15a44 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -266,8 +266,7 @@ extern int qla24xx_modify_vp_config(scsi_qla_host_t *);
 extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t, uint16_t);
 extern void qla2x00_vp_stop_timer(scsi_qla_host_t *);
 extern int qla24xx_configure_vhba (scsi_qla_host_t *);
-extern void qla24xx_report_id_acquisition(scsi_qla_host_t *,
-    struct vp_rpt_id_entry_24xx *);
+extern void qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt);
 extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *);
 extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
 extern scsi_qla_host_t *qla24xx_create_vhost(struct fc_vport *);
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 9c12e99ba5bd..fa45d57e3e21 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -4237,8 +4237,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 			qla2x00_status_cont_entry(rsp, pkt);
 			break;
 		case VP_RPT_ID_IOCB_TYPE:
-			qla24xx_report_id_acquisition(vha,
-			    (struct vp_rpt_id_entry_24xx *)pkt);
+			qla24xx_report_id_acquisition(vha, pkt);
 			break;
 		case LOGINOUT_PORT_IOCB_TYPE:
 			qla24xx_logio_entry(vha, rsp->req, pkt);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index bdf03d92e552..1df48593017c 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -4094,15 +4094,18 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
 }
 
 void
-qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
-	struct vp_rpt_id_entry_24xx *rptid_entry)
+qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt)
 {
 	struct qla_hw_data *ha = vha->hw;
+	struct vp_rpt_id_entry_24xx *rptid_entry = pkt;
+	struct vp_rpt_id_entry_24xx_ext *rptid_entry_ext = pkt;
 	scsi_qla_host_t *vp = NULL;
 	unsigned long   flags;
 	int found;
 	port_id_t id;
 	struct fc_port *fcport;
+	u16 vp_idx;
+	u8 vp_status;
 
 	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10b6,
 	    "Entered %s.\n", __func__);
@@ -4110,6 +4113,14 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
 	if (rptid_entry->entry_status != 0)
 		return;
 
+	if (IS_QLA29XX(ha)) {
+		vp_idx = rptid_entry_ext->vp_idx;
+		vp_status = rptid_entry_ext->vp_status;
+	} else {
+		vp_idx = rptid_entry->vp_idx;
+		vp_status = rptid_entry->vp_status;
+	}
+
 	id.b.domain = rptid_entry->port_id[2];
 	id.b.area   = rptid_entry->port_id[1];
 	id.b.al_pa  = rptid_entry->port_id[0];
@@ -4132,9 +4143,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
 	} else if (rptid_entry->format == 1) {
 		/* fabric */
 		ql_dbg(ql_dbg_async, vha, 0x10b9,
-		    "Format 1: VP[%d] enabled - status %d - with "
-		    "port id %02x%02x%02x.\n", rptid_entry->vp_idx,
-			rptid_entry->vp_status,
+		    "Format 1: VP[%d] enabled - status %d - with port id %02x%02x%02x.\n",
+		    vp_idx, vp_status,
 		    rptid_entry->port_id[2], rptid_entry->port_id[1],
 		    rptid_entry->port_id[0]);
 		ql_dbg(ql_dbg_async, vha, 0x5075,
@@ -4231,8 +4241,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
 		/* buffer to buffer credit flag */
 		vha->flags.bbcr_enable = (rptid_entry->u.f1.bbcr & 0xf) != 0;
 
-		if (rptid_entry->vp_idx == 0) {
-			if (rptid_entry->vp_status == VP_STAT_COMPL) {
+		if (vp_idx == 0) {
+			if (vp_status == VP_STAT_COMPL) {
 				/* FA-WWN is only for physical port */
 				if (qla_ini_mode_enabled(vha) &&
 				    ha->flags.fawwpn_enabled &&
@@ -4249,18 +4259,18 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
 			set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
 			set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
 		} else {
-			if (rptid_entry->vp_status != VP_STAT_COMPL &&
-				rptid_entry->vp_status != VP_STAT_ID_CHG) {
+			if (vp_status != VP_STAT_COMPL &&
+				vp_status != VP_STAT_ID_CHG) {
 				ql_dbg(ql_dbg_mbx, vha, 0x10ba,
 				    "Could not acquire ID for VP[%d].\n",
-				    rptid_entry->vp_idx);
+				    vp_idx);
 				return;
 			}
 
 			found = 0;
 			spin_lock_irqsave(&ha->vport_slock, flags);
 			list_for_each_entry(vp, &ha->vp_list, list) {
-				if (rptid_entry->vp_idx == vp->vp_idx) {
+				if (vp_idx == vp->vp_idx) {
 					found = 1;
 					break;
 				}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 397f2ffa56d1..d8945cab3251 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8439,6 +8439,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct vp_ctrl_entry_24xx) != 64);
 	BUILD_BUG_ON(sizeof(struct vp_ctrl_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct vp_rpt_id_entry_24xx) != 64);
+	BUILD_BUG_ON(sizeof(struct vp_rpt_id_entry_24xx_ext) != 128);
 	BUILD_BUG_ON(sizeof(sts21_entry_t) != 64);
 	BUILD_BUG_ON(sizeof(sts22_entry_t) != 64);
 	BUILD_BUG_ON(sizeof(sts_cont_entry_t) != 64);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 41/60] scsi: qla2xxx: Unify NVMe IOCB build path for 29xx and legacy adapters
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (39 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 40/60] scsi: qla2xxx: Add size check for extended VP report ID entry Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:02   ` sashiko-bot
  2026-06-12 12:49   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 42/60] scsi: qla2xxx: Add LS4 pass-through IOCB handling for 29xx series Nilesh Javali
                   ` (18 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

The cmd_nvme and cmd_nvme_ext structs share an identical header layout
through byte_count, so the IOCB build code in qla2x00_start_nvme_mq()
need not duplicate all common-field writes in separate IS_QLA29XX(ha)
and legacy blocks.

Initialize the cmd_pkt and cmd_pkt_ext pointers to NULL, then write
common header fields through a single cmd_pkt (struct cmd_nvme *) view,
branching on IS_QLA29XX(ha) only where the layouts genuinely diverge:

  - port_id[] vs __le16 vp_index
  - single inline DSD vs NUM_NVME_DSDS DSD array

Add BUILD_BUG_ON checks that enforce the layout contract at compile
time so any future struct change that breaks the common-header overlap
fails the build rather than silently corrupting IOCBs.

Also add a BUILD_BUG_ON size check for struct cmd_nvme_ext during
module initialization and a reserved_end field to
vp_rpt_id_entry_24xx_ext to ensure proper memory allocation and data
integrity for 29xx series adapters.

No functional change.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_nvme.c | 58 ++++++++++++++++++++++++---------
 drivers/scsi/qla2xxx/qla_os.c   |  1 +
 2 files changed, 43 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index cdd9e657bec6..fa89cd2b5f29 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -554,8 +554,8 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
 	unsigned long   flags;
 	uint32_t        *clr_ptr;
 	uint32_t        handle;
-	struct cmd_nvme *cmd_pkt;
-	struct cmd_nvme_ext *cmd_pkt_ext;
+	struct cmd_nvme *cmd_pkt = NULL;
+	struct cmd_nvme_ext *cmd_pkt_ext = NULL;
 	uint16_t        cnt, i;
 	uint16_t        req_cnt;
 	uint16_t        tot_dsds;
@@ -634,12 +634,44 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
 	req->cnt -= req_cnt;
 
 	/*
-	 * 29xx operates on the 128-byte extended IOCB ring via ring_ext_ptr;
-	 * the header layout of struct cmd_nvme is identical to the head of
-	 * struct cmd_nvme_ext through 'byte_count', so common field writes
-	 * below go through 'cmd_pkt'.  Divergent tail fields
-	 * (port_id/vp_index, DSD array) are handled via IS_QLA29XX() branches.
+	 * 29xx operates on the 128-byte extended IOCB ring; the header
+	 * layout of struct cmd_nvme is identical to the head of struct
+	 * cmd_nvme_ext through 'byte_count', so the common-field writes
+	 * below go through cmd_pkt regardless of stride.  Divergent tail
+	 * fields (port_id/vp_index, DSD array) are handled via
+	 * IS_QLA29XX(ha) branches.
+	 *
+	 * Enforce the layout contract at compile time so any future
+	 * change to either struct that breaks the common-header overlap
+	 * fails the build rather than silently corrupting IOCBs.
 	 */
+	BUILD_BUG_ON(offsetof(struct cmd_nvme, entry_type) !=
+		     offsetof(struct cmd_nvme_ext, entry_type));
+	BUILD_BUG_ON(offsetof(struct cmd_nvme, handle) !=
+		     offsetof(struct cmd_nvme_ext, handle));
+	BUILD_BUG_ON(offsetof(struct cmd_nvme, nport_handle) !=
+		     offsetof(struct cmd_nvme_ext, nport_handle));
+	BUILD_BUG_ON(offsetof(struct cmd_nvme, timeout) !=
+		     offsetof(struct cmd_nvme_ext, timeout));
+	BUILD_BUG_ON(offsetof(struct cmd_nvme, dseg_count) !=
+		     offsetof(struct cmd_nvme_ext, dseg_count));
+	BUILD_BUG_ON(offsetof(struct cmd_nvme, nvme_rsp_dsd_len) !=
+		     offsetof(struct cmd_nvme_ext, nvme_rsp_dsd_len));
+	BUILD_BUG_ON(offsetof(struct cmd_nvme, rsvd) !=
+		     offsetof(struct cmd_nvme_ext, rsvd));
+	BUILD_BUG_ON(offsetof(struct cmd_nvme, control_flags) !=
+		     offsetof(struct cmd_nvme_ext, control_flags));
+	BUILD_BUG_ON(offsetof(struct cmd_nvme, nvme_cmnd_dseg_len) !=
+		     offsetof(struct cmd_nvme_ext, nvme_cmnd_dseg_len));
+	BUILD_BUG_ON(offsetof(struct cmd_nvme, nvme_cmnd_dseg_address) !=
+		     offsetof(struct cmd_nvme_ext, nvme_cmnd_dseg_address));
+	BUILD_BUG_ON(offsetof(struct cmd_nvme, nvme_rsp_dseg_address) !=
+		     offsetof(struct cmd_nvme_ext, nvme_rsp_dseg_address));
+	BUILD_BUG_ON(offsetof(struct cmd_nvme, byte_count) !=
+		     offsetof(struct cmd_nvme_ext, byte_count));
+	BUILD_BUG_ON(sizeof_field(struct cmd_nvme, byte_count) !=
+		     sizeof_field(struct cmd_nvme_ext, byte_count));
+
 	if (IS_QLA29XX(ha))
 		cmd_pkt = (struct cmd_nvme *)req->ring_ext_ptr;
 	else
@@ -655,11 +687,8 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
 		memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
 
 	cmd_pkt->entry_status = 0;
-
-	/* Update entry type to indicate Command NVME IOCB */
 	cmd_pkt->entry_type = COMMAND_NVME;
 
-	/* No data transfer how do we check buffer len == 0?? */
 	if (fd->io_dir == NVMEFC_FCP_READ) {
 		cmd_pkt->control_flags = cpu_to_le16(CF_READ_DATA);
 		qpair->counters.input_bytes += fd->payload_length;
@@ -684,18 +713,15 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
 	if (sp->fcport->edif.enable && fd->io_dir != 0)
 		cmd_pkt->control_flags |= cpu_to_le16(CF_EN_EDIF);
 
-	/* Set BIT_13 of control flags for Async event */
 	if (vha->flags.nvme2_enabled &&
-	    cmd->sqe.common.opcode == nvme_admin_async_event) {
+	    cmd->sqe.common.opcode == nvme_admin_async_event)
 		cmd_pkt->control_flags |= cpu_to_le16(CF_ADMIN_ASYNC_EVENT);
-	}
 
-	/* Set NPORT-ID */
 	cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
 	if (IS_QLA29XX(ha)) {
 		/*
-		 * 29xx extended NVMe IOCB has no port_id[] field; vp_index is a
-		 * 9-bit __le16 (see CMD_EXT_VP_INDEX_MASK).
+		 * 29xx extended NVMe IOCB has no port_id[] field; vp_index is
+		 * a 9-bit __le16 (see CMD_EXT_VP_INDEX_MASK).
 		 */
 		cmd_pkt_ext->vp_index = cpu_to_le16(sp->fcport->vha->vp_idx);
 	} else {
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index d8945cab3251..f539190dd504 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8366,6 +8366,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct access_chip_rsp_84xx) != 64);
 	BUILD_BUG_ON(sizeof(struct cmd_bidir) != 64);
 	BUILD_BUG_ON(sizeof(struct cmd_nvme) != 64);
+	BUILD_BUG_ON(sizeof(struct cmd_nvme_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct cmd_type_6) != 64);
 	BUILD_BUG_ON(sizeof(struct cmd_type_7) != 64);
 	BUILD_BUG_ON(sizeof(struct cmd_type_7_fx00) != 64);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 42/60] scsi: qla2xxx: Add LS4 pass-through IOCB handling for 29xx series
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (40 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 41/60] scsi: qla2xxx: Unify NVMe IOCB build path for 29xx and legacy adapters Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 12:50   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 43/60] scsi: qla2xxx: Convert NVMe ring advance to use qla_req_ring_advance() Nilesh Javali
                   ` (17 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Manish Rangankar <mrangankar@marvell.com>

Extend the LS4 pass-through IOCB handling to support the 128-byte
pt_ls4_request_ext layout used by 29xx series adapters.  The extension
grows inline DSD capacity from 2 to 5 entries.  Function signatures are
widened to void * so both layouts can be passed without casts.

pt_ls4_request_ext overlays pt_ls4_request through exchange_address
(offsets 0-27 are byte-identical), so common-header writes go through a
single struct pt_ls4_request * view; only the divergent fields
(vp_index width, tx_/rx_byte_count offset, dsd[] base) are branched.

Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_fw29.h | 37 +++++++++++++++++
 drivers/scsi/qla2xxx/qla_iocb.c | 73 ++++++++++++++++++++++-----------
 drivers/scsi/qla2xxx/qla_isr.c  |  9 ++--
 drivers/scsi/qla2xxx/qla_nvme.c | 64 +++++++++++++++++++----------
 drivers/scsi/qla2xxx/qla_nvme.h |  4 +-
 drivers/scsi/qla2xxx/qla_os.c   |  1 +
 6 files changed, 137 insertions(+), 51 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_fw29.h b/drivers/scsi/qla2xxx/qla_fw29.h
index a4aa5bacb171..600a40d8bd5f 100644
--- a/drivers/scsi/qla2xxx/qla_fw29.h
+++ b/drivers/scsi/qla2xxx/qla_fw29.h
@@ -295,6 +295,43 @@ struct ct_entry_24xx_ext {
 	struct dsd64 dsd[NUM_CT_DSDS];	/* Data Segment Descriptors */
 };
 
+/*
+ * 29xx extended Link Service pass-through request IOCB (128 bytes).
+ *
+ * Same wire purpose as the 64-byte struct pt_ls4_request used on 24xx-class
+ * adapters, but laid out for the 128-byte 29xx request ring:
+ *   - vp_index widened to __le16 (bits [8:0] meaningful, see
+ *     CMD_EXT_VP_INDEX_MASK).
+ *   - reserved area expanded to 32 bytes between exchange_address and
+ *     rx_byte_count.
+ *   - inline DSD capacity grown from 2 to 5.
+ * Header through 'tx_dseg_count' (offset 14) and the control_flags /
+ * exchange_address fields keep the same offsets as struct pt_ls4_request,
+ * so common code can populate them via either type once IS_QLA29XX(ha) is
+ * branched for the layout-divergent fields.
+ */
+#define NUM_PT_LS4_EXT_DSDS	5
+struct pt_ls4_request_ext {
+	uint8_t entry_type;
+	uint8_t entry_count;
+	uint8_t sys_define;
+	uint8_t entry_status;
+	uint32_t handle;
+	__le16	status;
+	__le16	nport_handle;
+	__le16	tx_dseg_count;
+	__le16	vp_index;	/* VP Index 9 bits; see CMD_EXT_VP_INDEX_MASK */
+	__le16	timeout;
+	__le16	control_flags;	/* CF_LS4_* (see struct pt_ls4_request) */
+	__le16	rx_dseg_count;
+	__le16	rsvd2;
+	__le32	exchange_address;
+	uint8_t rsvd3[32];
+	__le32	rx_byte_count;
+	__le32	tx_byte_count;
+	struct dsd64 dsd[NUM_PT_LS4_EXT_DSDS];
+};
+
 /*
  * ISP queue - PUREX IOCB entry structure definition
  */
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index a286e947fb21..a103be30fddb 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -3981,38 +3981,65 @@ static void qla2x00_send_notify_ack_iocb(srb_t *sp,
 }
 
 /*
- * Build NVME LS request
+ * Build NVME LS request.
+ *
+ * pt_ls4_request_ext overlays pt_ls4_request through exchange_address
+ * (offsets 0-27 are byte-identical), so the common-header writes go
+ * through one struct pt_ls4_request * view.  The ext layout has a wider
+ * __le16 vp_index and places rx_/tx_byte_count and dsd[] at different
+ * offsets, so those assignments diverge per stride.
  */
 static void
-qla_nvme_ls(srb_t *sp, struct pt_ls4_request *cmd_pkt)
+qla_nvme_ls(srb_t *sp, void *cmd_pkt)
 {
-	struct srb_iocb *nvme;
+	struct srb_iocb *nvme = &sp->u.iocb_cmd;
+	struct qla_hw_data *ha = sp->vha->hw;
+	struct pt_ls4_request *pkt = cmd_pkt;
 
-	nvme = &sp->u.iocb_cmd;
-	cmd_pkt->entry_type = PT_LS4_REQUEST;
-	cmd_pkt->entry_count = 1;
-	cmd_pkt->timeout = cpu_to_le16(nvme->u.nvme.timeout_sec);
-	cmd_pkt->vp_index = sp->fcport->vha->vp_idx;
+	pkt->entry_type = PT_LS4_REQUEST;
+	pkt->entry_count = 1;
+	pkt->timeout = cpu_to_le16(nvme->u.nvme.timeout_sec);
+	pkt->tx_dseg_count = cpu_to_le16(1);
 
 	if (sp->unsol_rsp) {
-		cmd_pkt->control_flags =
-				cpu_to_le16(CF_LS4_RESPONDER << CF_LS4_SHIFT);
-		cmd_pkt->nport_handle = nvme->u.nvme.nport_handle;
-		cmd_pkt->exchange_address = nvme->u.nvme.exchange_address;
+		pkt->control_flags =
+			cpu_to_le16(CF_LS4_RESPONDER << CF_LS4_SHIFT);
+		pkt->nport_handle = nvme->u.nvme.nport_handle;
+		pkt->exchange_address = nvme->u.nvme.exchange_address;
 	} else {
-		cmd_pkt->control_flags =
-				cpu_to_le16(CF_LS4_ORIGINATOR << CF_LS4_SHIFT);
-		cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
-		cmd_pkt->rx_dseg_count = cpu_to_le16(1);
-		cmd_pkt->rx_byte_count = nvme->u.nvme.rsp_len;
-		cmd_pkt->dsd[1].length  = nvme->u.nvme.rsp_len;
-		put_unaligned_le64(nvme->u.nvme.rsp_dma, &cmd_pkt->dsd[1].address);
+		pkt->control_flags =
+			cpu_to_le16(CF_LS4_ORIGINATOR << CF_LS4_SHIFT);
+		pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+		pkt->rx_dseg_count = cpu_to_le16(1);
 	}
 
-	cmd_pkt->tx_dseg_count = cpu_to_le16(1);
-	cmd_pkt->tx_byte_count = nvme->u.nvme.cmd_len;
-	cmd_pkt->dsd[0].length = nvme->u.nvme.cmd_len;
-	put_unaligned_le64(nvme->u.nvme.cmd_dma, &cmd_pkt->dsd[0].address);
+	if (IS_QLA29XX(ha)) {
+		struct pt_ls4_request_ext *ext = cmd_pkt;
+
+		ext->vp_index = cpu_to_le16(sp->fcport->vha->vp_idx);
+		ext->tx_byte_count = nvme->u.nvme.cmd_len;
+		ext->dsd[0].length = nvme->u.nvme.cmd_len;
+		put_unaligned_le64(nvme->u.nvme.cmd_dma,
+				   &ext->dsd[0].address);
+		if (!sp->unsol_rsp) {
+			ext->rx_byte_count = nvme->u.nvme.rsp_len;
+			ext->dsd[1].length = nvme->u.nvme.rsp_len;
+			put_unaligned_le64(nvme->u.nvme.rsp_dma,
+					   &ext->dsd[1].address);
+		}
+	} else {
+		pkt->vp_index = sp->fcport->vha->vp_idx;
+		pkt->tx_byte_count = nvme->u.nvme.cmd_len;
+		pkt->dsd[0].length = nvme->u.nvme.cmd_len;
+		put_unaligned_le64(nvme->u.nvme.cmd_dma,
+				   &pkt->dsd[0].address);
+		if (!sp->unsol_rsp) {
+			pkt->rx_byte_count = nvme->u.nvme.rsp_len;
+			pkt->dsd[1].length = nvme->u.nvme.rsp_len;
+			put_unaligned_le64(nvme->u.nvme.rsp_dma,
+					   &pkt->dsd[1].address);
+		}
+	}
 }
 
 static void
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index fa45d57e3e21..31a685ce6ba6 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -4098,7 +4098,7 @@ qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
 }
 
 void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha,
-    struct pt_ls4_request *pkt, struct req_que *req)
+			   void *pkt, struct req_que *req)
 {
 	srb_t *sp;
 	const char func[] = "LS4_IOCB";
@@ -4108,7 +4108,9 @@ void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha,
 	if (!sp)
 		return;
 
-	comp_status = le16_to_cpu(pkt->status);
+	/* status lives at the same offset (8) in both IOCB strides */
+	comp_status = le16_to_cpu(((struct pt_ls4_request *)pkt)->status);
+
 	sp->done(sp, comp_status);
 }
 
@@ -4273,8 +4275,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 			qlt_response_pkt_all_vps(vha, rsp, (response_t *)pkt);
 			break;
 		case PT_LS4_REQUEST:
-			qla24xx_nvme_ls4_iocb(vha, (struct pt_ls4_request *)pkt,
-			    rsp->req);
+			qla24xx_nvme_ls4_iocb(vha, pkt, rsp->req);
 			break;
 		case NOTIFY_ACK_TYPE:
 			if (((response_t *)pkt)->handle == QLA_TGT_SKIP_HANDLE)
diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index fa89cd2b5f29..61a8e9162135 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -1212,37 +1212,57 @@ static void qla_nvme_fc_format_rjt(void *buf, u8 ls_cmd, u8 reason,
 	rjt->rjt.vendor = vendor;
 }
 
+/*
+ * pt_ls4_request_ext overlays pt_ls4_request through exchange_address
+ * (offsets 0-27 are byte-identical), so the common-header writes go
+ * through one struct pt_ls4_request * view.  The ext layout has a wider
+ * __le16 vp_index and places tx_/rx_byte_count and dsd[] at different
+ * offsets, so those assignments diverge per stride.
+ */
 static void qla_nvme_lsrjt_pt_iocb(struct scsi_qla_host *vha,
-				   struct pt_ls4_request *lsrjt_iocb,
+				   void *lsrjt_iocb,
 				   struct qla_nvme_lsrjt_pt_arg *a)
 {
-	lsrjt_iocb->entry_type = PT_LS4_REQUEST;
-	lsrjt_iocb->entry_count = 1;
-	lsrjt_iocb->sys_define = 0;
-	lsrjt_iocb->entry_status = 0;
-	lsrjt_iocb->handle = QLA_SKIP_HANDLE;
-	lsrjt_iocb->nport_handle = a->nport_handle;
-	lsrjt_iocb->exchange_address = a->xchg_address;
-	lsrjt_iocb->vp_index = a->vp_idx;
-
-	lsrjt_iocb->control_flags = cpu_to_le16(a->control_flags);
-
-	put_unaligned_le64(a->tx_addr, &lsrjt_iocb->dsd[0].address);
-	lsrjt_iocb->dsd[0].length = cpu_to_le32(a->tx_byte_count);
-	lsrjt_iocb->tx_dseg_count = cpu_to_le16(1);
-	lsrjt_iocb->tx_byte_count = cpu_to_le32(a->tx_byte_count);
-
-	put_unaligned_le64(a->rx_addr, &lsrjt_iocb->dsd[1].address);
-	lsrjt_iocb->dsd[1].length = 0;
-	lsrjt_iocb->rx_dseg_count = 0;
-	lsrjt_iocb->rx_byte_count = 0;
+	struct qla_hw_data *ha = vha->hw;
+	struct pt_ls4_request *pkt = lsrjt_iocb;
+
+	pkt->entry_type = PT_LS4_REQUEST;
+	pkt->entry_count = 1;
+	pkt->sys_define = 0;
+	pkt->entry_status = 0;
+	pkt->handle = QLA_SKIP_HANDLE;
+	pkt->nport_handle = a->nport_handle;
+	pkt->exchange_address = a->xchg_address;
+	pkt->control_flags = cpu_to_le16(a->control_flags);
+	pkt->tx_dseg_count = cpu_to_le16(1);
+	pkt->rx_dseg_count = 0;
+
+	if (IS_QLA29XX(ha)) {
+		struct pt_ls4_request_ext *ext = lsrjt_iocb;
+
+		ext->vp_index = cpu_to_le16(a->vp_idx);
+		ext->tx_byte_count = cpu_to_le32(a->tx_byte_count);
+		ext->rx_byte_count = 0;
+		put_unaligned_le64(a->tx_addr, &ext->dsd[0].address);
+		ext->dsd[0].length = cpu_to_le32(a->tx_byte_count);
+		put_unaligned_le64(a->rx_addr, &ext->dsd[1].address);
+		ext->dsd[1].length = 0;
+	} else {
+		pkt->vp_index = a->vp_idx;
+		pkt->tx_byte_count = cpu_to_le32(a->tx_byte_count);
+		pkt->rx_byte_count = 0;
+		put_unaligned_le64(a->tx_addr, &pkt->dsd[0].address);
+		pkt->dsd[0].length = cpu_to_le32(a->tx_byte_count);
+		put_unaligned_le64(a->rx_addr, &pkt->dsd[1].address);
+		pkt->dsd[1].length = 0;
+	}
 }
 
 static int
 qla_nvme_ls_reject_iocb(struct scsi_qla_host *vha, struct qla_qpair *qp,
 			struct qla_nvme_lsrjt_pt_arg *a, bool is_xchg_terminate)
 {
-	struct pt_ls4_request *lsrjt_iocb;
+	void *lsrjt_iocb;
 
 	lsrjt_iocb = __qla2x00_alloc_iocbs(qp, NULL);
 	if (!lsrjt_iocb) {
diff --git a/drivers/scsi/qla2xxx/qla_nvme.h b/drivers/scsi/qla2xxx/qla_nvme.h
index a253ac55171b..e6a41d53cbe1 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.h
+++ b/drivers/scsi/qla2xxx/qla_nvme.h
@@ -144,7 +144,7 @@ struct pt_ls4_rx_unsol {
 int qla_nvme_register_hba(struct scsi_qla_host *);
 int  qla_nvme_register_remote(struct scsi_qla_host *, struct fc_port *);
 void qla_nvme_delete(struct scsi_qla_host *);
-void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *, struct pt_ls4_request *,
-    struct req_que *);
+void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha, void *pkt,
+			   struct req_que *req);
 void qla24xx_async_gffid_sp_done(struct srb *sp, int);
 #endif
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index f539190dd504..186c6c7a3944 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -8402,6 +8402,7 @@ qla2x00_module_init(void)
 	BUILD_BUG_ON(sizeof(struct nvram_24xx) != 512);
 	BUILD_BUG_ON(sizeof(struct nvram_81xx) != 512);
 	BUILD_BUG_ON(sizeof(struct pt_ls4_request) != 64);
+	BUILD_BUG_ON(sizeof(struct pt_ls4_request_ext) != 128);
 	BUILD_BUG_ON(sizeof(struct pt_ls4_rx_unsol) != 64);
 	BUILD_BUG_ON(sizeof(struct purex_entry_24xx) != 64);
 	BUILD_BUG_ON(sizeof(struct purex_entry_24xx_ext) != 128);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 43/60] scsi: qla2xxx: Convert NVMe ring advance to use qla_req_ring_advance()
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (41 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 42/60] scsi: qla2xxx: Add LS4 pass-through IOCB handling for 29xx series Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 12:52   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 44/60] scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support Nilesh Javali
                   ` (16 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

Replace the open-coded IS_QLA29XX() ring_ext_ptr/ring_ptr advancement
in qla2x00_start_nvme_mq() with the qla_req_ring_advance() helper,
removing 16 lines of duplicated logic.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_nvme.c | 17 +----------------
 1 file changed, 1 insertion(+), 16 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index 61a8e9162135..0038b6274d44 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -798,22 +798,7 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
 	wmb();
 
 	/* Adjust ring index. */
-	req->ring_index++;
-	if (IS_QLA29XX(ha)) {
-		if (req->ring_index == req->length) {
-			req->ring_index = 0;
-			req->ring_ext_ptr = req->ring_ext;
-		} else {
-			req->ring_ext_ptr++;
-		}
-	} else {
-		if (req->ring_index == req->length) {
-			req->ring_index = 0;
-			req->ring_ptr = req->ring;
-		} else {
-			req->ring_ptr++;
-		}
-	}
+	qla_req_ring_advance(ha, req);
 
 	/* ignore nvme async cmd due to long timeout */
 	if (!nvme->u.nvme.aen_op)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 44/60] scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (42 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 43/60] scsi: qla2xxx: Convert NVMe ring advance to use qla_req_ring_advance() Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:16   ` sashiko-bot
  2026-06-12 12:53   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 45/60] scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking Nilesh Javali
                   ` (15 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

From: Manish Rangankar <mrangankar@marvell.com>

Extend qla2xxx BSG command handling to recognize QLA29xx adapters and
align feature availability with hardware capabilities.

Allow QLA29xx in paths previously restricted to QLA27xx/28xx:
  - Flash update capability queries (get/set)
  - BBCR data retrieval
  - D-port diagnostics
  - MPI and PEP version sysfs attributes

Restrict unsupported operations on QLA29xx:
  - Reject flash image status query (no active image tracking)
  - Block qla28xx_validate_flash_image()

Guard the qla27xx_get_active_image() call with an explicit IS_QLA27XX
|| IS_QLA28XX check so it is not reached from adapters that lack the
legacy active-image layout.

Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_attr.c |  4 ++--
 drivers/scsi/qla2xxx/qla_bsg.c  | 19 ++++++++++++-------
 drivers/scsi/qla2xxx/qla_def.h  |  2 +-
 drivers/scsi/qla2xxx/qla_fw.h   |  2 +-
 4 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 37478af9cdec..fd3c8c207535 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1542,7 +1542,7 @@ qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr,
 	struct qla_hw_data *ha = vha->hw;
 
 	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha) &&
-	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
 		return scnprintf(buf, PAGE_SIZE, "\n");
 
 	return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
@@ -1770,7 +1770,7 @@ qla2x00_pep_version_show(struct device *dev, struct device_attribute *attr,
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
 		return scnprintf(buf, PAGE_SIZE, "\n");
 
 	return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 00e980f0cd78..7f4558beee2c 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -1900,7 +1900,7 @@ static int qla2900_bsg_load_mpi(struct bsg_job *bsg_job)
 	bsg_job_done(bsg_job, bsg_reply->result,
 		     bsg_reply->reply_payload_rcv_len);
 
-	return rval;
+	return 0;
 }
 
 static int
@@ -2544,7 +2544,7 @@ qla27xx_get_flash_upd_cap(struct bsg_job *bsg_job)
 	struct qla_hw_data *ha = vha->hw;
 	struct qla_flash_update_caps cap;
 
-	if (!(IS_QLA27XX(ha)) && !IS_QLA28XX(ha))
+	if (!(IS_QLA27XX(ha)) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
 		return -EPERM;
 
 	memset(&cap, 0, sizeof(cap));
@@ -2577,7 +2577,7 @@ qla27xx_set_flash_upd_cap(struct bsg_job *bsg_job)
 	uint64_t online_fw_attr = 0;
 	struct qla_flash_update_caps cap;
 
-	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
 		return -EPERM;
 
 	memset(&cap, 0, sizeof(cap));
@@ -2625,7 +2625,7 @@ qla27xx_get_bbcr_data(struct bsg_job *bsg_job)
 	uint8_t domain, area, al_pa, state;
 	int rval;
 
-	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
 		return -EPERM;
 
 	memset(&bbcr, 0, sizeof(bbcr));
@@ -2741,7 +2741,7 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job)
 	struct qla_dport_diag *dd;
 
 	if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
-	    !IS_QLA28XX(vha->hw))
+	    !IS_QLA28XX(vha->hw) && !IS_QLA29XX(vha->hw))
 		return -EPERM;
 
 	dd = kmalloc_obj(*dd);
@@ -2867,8 +2867,13 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job)
 	struct qla_active_regions regions = { };
 	struct active_regions active_regions = { };
 
-	qla27xx_get_active_image(vha, &active_regions);
-	regions.global_image = active_regions.global;
+	if (IS_QLA29XX(ha))
+		return -EPERM;
+
+	if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+		qla27xx_get_active_image(vha, &active_regions);
+		regions.global_image = active_regions.global;
+	}
 
 	if (IS_QLA27XX(ha))
 		regions.nvme_params = QLA27XX_PRIMARY_IMAGE;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 3e2f1d8ba904..4fd2a28af7e4 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -4454,7 +4454,7 @@ struct qla_hw_data {
 #define IS_QLA27XX(ha)  (IS_QLA2071(ha) || IS_QLA2271(ha) || IS_QLA2261(ha))
 #define IS_QLA28XX(ha)	(IS_QLA2081(ha) || IS_QLA2281(ha))
 #define IS_QLA29XX(ha)	(IS_QLA2099(ha) || IS_QLA2299(ha) || \
-			 IS_QLA2091(ha) || IS_QLA2291(ha))
+				IS_QLA2091(ha) || IS_QLA2291(ha))
 
 #define IS_QLA24XX_TYPE(ha)     (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
 				IS_QLA84XX(ha))
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 050986c6217f..4d6f8b1a36d1 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -2360,7 +2360,7 @@ struct qla_fmb_upd_time {
 
 struct qla_flash_memo_block {
 	__le32   signature;	/* "FMBS" */
-#define QLFC_FMB_SIG	cpu_to_le32(0x464D4253)
+#define QLFC_FMB_SIG	cpu_to_le32(0x53424D46)
 	__le32   length;
 	__le32   version;
 #define QLFC_FMB_VERSION 3
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 45/60] scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (43 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 44/60] scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 12:56   ` Hannes Reinecke
  2026-06-12 13:23   ` sashiko-bot
  2026-06-12  9:53 ` [PATCH v2 46/60] scsi: qla2xxx: Replace __le16 bitfields with scalar and accessors Nilesh Javali
                   ` (14 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

qla25xx_free_req_que() and qla25xx_free_rsp_que() have two pre-existing
bugs exposed on the error path of qla25xx_create_{req,rsp}_que():

1. When dma_alloc_coherent() fails during queue creation, the error path
   calls the free function with req->ring / rsp->ring still NULL (from
   kzalloc).  The unconditional dma_free_coherent() with a NULL cpu_addr
   is undefined behavior and can panic.

2. The free functions clear req_qid_map / rsp_qid_map under vport_lock,
   but the create functions protect the same bitmaps with mq_lock.  This
   provides no mutual exclusion.  Additionally, the create error path
   clears the bit and releases mq_lock before calling the free function,
   creating a window where another thread can allocate the same que_id
   and have its ha->req_q_map entry clobbered by the subsequent lockless
   NULL assignment in the free function.

Fix by:
 - Guarding dma_free_coherent() with a NULL check on the ring pointer.
 - Using mq_lock (the lock held by all creators) in the free functions
   to atomically NULL the map entry and clear the bitmap bit.
 - Removing the now-redundant clear_bit blocks from the create error
   paths since the free functions handle it atomically.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_mid.c | 28 ++++++++++++----------------
 1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index bb2521c052bf..7072af5b4217 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -576,16 +576,17 @@ qla25xx_free_req_que(struct scsi_qla_host *vha, struct req_que *req)
 	uint16_t que_id = req->id;
 	size_t req_entry_size = qla_req_entry_size(ha);
 
-	dma_free_coherent(&ha->pdev->dev,
-			  (req->length + 1) * req_entry_size,
-			  req->ring, req->dma);
+	if (req->ring)
+		dma_free_coherent(&ha->pdev->dev,
+				  (req->length + 1) * req_entry_size,
+				  req->ring, req->dma);
 	req->ring = NULL;
 	req->dma = 0;
 	if (que_id) {
+		mutex_lock(&ha->mq_lock);
 		ha->req_q_map[que_id] = NULL;
-		mutex_lock(&ha->vport_lock);
 		clear_bit(que_id, ha->req_qid_map);
-		mutex_unlock(&ha->vport_lock);
+		mutex_unlock(&ha->mq_lock);
 	}
 	kfree(req->outstanding_cmds);
 	kfree(req);
@@ -605,16 +606,17 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
 		rsp->msix->handle = NULL;
 	}
 
-	dma_free_coherent(&ha->pdev->dev,
-			  (rsp->length + 1) * rsp_entry_size,
-			  rsp->ring, rsp->dma);
+	if (rsp->ring)
+		dma_free_coherent(&ha->pdev->dev,
+				  (rsp->length + 1) * rsp_entry_size,
+				  rsp->ring, rsp->dma);
 	rsp->ring = NULL;
 	rsp->dma = 0;
 	if (que_id) {
+		mutex_lock(&ha->mq_lock);
 		ha->rsp_q_map[que_id] = NULL;
-		mutex_lock(&ha->vport_lock);
 		clear_bit(que_id, ha->rsp_qid_map);
-		mutex_unlock(&ha->vport_lock);
+		mutex_unlock(&ha->mq_lock);
 	}
 	kfree(rsp);
 }
@@ -820,9 +822,6 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
 		if (ret != QLA_SUCCESS) {
 			ql_log(ql_log_fatal, base_vha, 0x00df,
 			    "%s failed.\n", __func__);
-			mutex_lock(&ha->mq_lock);
-			clear_bit(que_id, ha->req_qid_map);
-			mutex_unlock(&ha->mq_lock);
 			goto que_failed;
 		}
 		vha->flags.qpairs_req_created = 1;
@@ -942,9 +941,6 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
 		if (ret != QLA_SUCCESS) {
 			ql_log(ql_log_fatal, base_vha, 0x00e7,
 			    "%s failed.\n", __func__);
-			mutex_lock(&ha->mq_lock);
-			clear_bit(que_id, ha->rsp_qid_map);
-			mutex_unlock(&ha->mq_lock);
 			goto que_failed;
 		}
 		vha->flags.qpairs_rsp_created = 1;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 46/60] scsi: qla2xxx: Replace __le16 bitfields with scalar and accessors
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (44 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 45/60] scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 12:57   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 47/60] scsi: qla2xxx: Fix endianness annotations in vp_rpt_id_entry structures Nilesh Javali
                   ` (13 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

C bitfield packing order is implementation-defined: GCC packs LSB-first
on little-endian targets and MSB-first on big-endian targets.  The
__le16 bitfield declarations for vp_index/sof_type in the 29xx extended
IOCB structures produce incorrect bit positions on big-endian hosts,
and Sparse cannot enforce endianness checks on bitfield members.

Replace the three sets of __le16 bitfields (in els_entry_24xx_ext,
els_sts_entry_24xx_ext, and abts_entry_24xx_ext) with a single __le16
scalar field and provide inline accessor functions that use proper
le16_to_cpu()/cpu_to_le16() with shift-and-mask operations.

Fixes: 1b923fdfaeb5 ("scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx")
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_fw29.h   | 39 ++++++++++++++++++++++++-------
 drivers/scsi/qla2xxx/qla_inline.h |  8 +++----
 drivers/scsi/qla2xxx/qla_isr.c    | 15 ++++++------
 3 files changed, 42 insertions(+), 20 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_fw29.h b/drivers/scsi/qla2xxx/qla_fw29.h
index 600a40d8bd5f..63bf350ddffc 100644
--- a/drivers/scsi/qla2xxx/qla_fw29.h
+++ b/drivers/scsi/qla2xxx/qla_fw29.h
@@ -24,6 +24,33 @@
  * Access on a host-endian value via le16_to_cpu(vp_index) & CMD_EXT_VP_INDEX_MASK.
  */
 #define CMD_EXT_VP_INDEX_MASK		0x01ff
+
+/*
+ * Combined vp_index/sof_type field layout (used by ELS and ABTS ext IOCBs):
+ *   bits [8:0]   - VP index (9 bits)
+ *   bits [11:9]  - reserved
+ *   bits [15:12] - SOF type (4 bits)
+ */
+#define EXT_VP_SOF_VP_INDEX_MASK	0x01ff
+#define EXT_VP_SOF_SOF_TYPE_SHIFT	12
+#define EXT_VP_SOF_SOF_TYPE_MASK	0xf000
+
+static inline u16 qla_ext_get_vp_index(__le16 vp_sof)
+{
+	return le16_to_cpu(vp_sof) & EXT_VP_SOF_VP_INDEX_MASK;
+}
+
+static inline u16 qla_ext_get_sof_type(__le16 vp_sof)
+{
+	return (le16_to_cpu(vp_sof) >> EXT_VP_SOF_SOF_TYPE_SHIFT) & 0xf;
+}
+
+static inline __le16 qla_ext_build_vp_sof(u16 vp_idx, u16 sof_type)
+{
+	return cpu_to_le16((vp_idx & EXT_VP_SOF_VP_INDEX_MASK) |
+			   ((sof_type & 0xf) << EXT_VP_SOF_SOF_TYPE_SHIFT));
+}
+
 /*
  * ISP queue - command entry structure definition.
  */
@@ -393,9 +420,7 @@ struct els_entry_24xx_ext {
 
 	__le16	tx_dsd_count;
 
-	__le16	vp_index : 9;		/* VP Index 9bits */
-	__le16	reserved_1_sof : 3;
-	__le16	sof_type : 4;
+	__le16	vp_index_sof;		/* bits [8:0]=VP index, [15:12]=SOF type */
 
 	__le32	rx_xchg_address;	/* Receive exchange address. */
 	__le16	rx_dsd_count;
@@ -444,9 +469,7 @@ struct els_sts_entry_24xx_ext {
 
 	__le16	reserved_1;
 
-	__le16	vp_index : 9;		/* VP Index 9bits */
-	__le16	reserved_1_sof : 3;
-	__le16	sof_type : 4;
+	__le16	vp_index_sof;		/* bits [8:0]=VP index, [15:12]=SOF type */
 
 	__le32	rx_xchg_address;	/* Receive exchange address. */
 	__le16	reserved_2;
@@ -563,9 +586,7 @@ struct abts_entry_24xx_ext {
 	__le16	nport_handle;		/* type 0x54 only */
 
 	__le16	control_flags;		/* type 0x55 only */
-	__le16	vp_idx : 9;		/* VP index 9 bits */
-	__le16	reserved_1_sof : 3;
-	__le16	sof_type : 4;		/* sof_type is upper nibble */
+	__le16	vp_idx_sof;		/* bits [8:0]=VP index, [15:12]=SOF type */
 
 	__le32	rx_xch_addr;
 
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 3e6a5208d108..b6dca1dd0a95 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -855,8 +855,8 @@ qla_sts_fwi2_extract(struct qla_hw_data *ha, void *pkt,
  * Both layouts have the same 16-bit slot at offset 14, but it is encoded
  * differently:
  *   - 24xx: separate u8 vp_index + u8 sof_type with EST_SOFI3 (1 << 4)
- *   - 29xx: __le16 with bitfields { vp_index:9, reserved_1_sof:3,
- *           sof_type:4 } and ELS_EXT_EST_SOFI3
+ *   - 29xx: __le16 vp_index_sof with bits [8:0]=VP index, [15:12]=SOF type
+ *           and ELS_EXT_EST_SOFI3
  * so this is the single point in the driver that knows about that
  * encoding split.
  */
@@ -866,8 +866,8 @@ qla_els_set_vp_sof(struct scsi_qla_host *vha, void *pkt, u16 vp_idx)
 	if (IS_QLA29XX(vha->hw)) {
 		struct els_entry_24xx_ext *ext = pkt;
 
-		ext->vp_index = vp_idx;
-		ext->sof_type = ELS_EXT_EST_SOFI3;
+		ext->vp_index_sof =
+		    qla_ext_build_vp_sof(vp_idx, ELS_EXT_EST_SOFI3);
 	} else {
 		struct els_entry_24xx *e = pkt;
 
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 31a685ce6ba6..784aa5c1dcba 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -90,13 +90,11 @@ static inline void display_Laser_info(scsi_qla_host_t *vha,
 	    (uint8_t *)(abts_ptr), sizeof(*(abts_ptr)));		\
 } while (0)
 
-#define QLA_BUILD_ABTS_BA_ACC(rsp, src, sof_val, fctl) do {		\
+#define QLA_BUILD_ABTS_BA_ACC(rsp, src, fctl) do {			\
 	memset((rsp), 0, sizeof(*(rsp)));				\
 	(rsp)->entry_type = ABTS_RSP_TYPE;				\
 	(rsp)->entry_count = 1;						\
 	(rsp)->nport_handle = (src)->nport_handle;			\
-	(rsp)->vp_idx = (src)->vp_idx;					\
-	(rsp)->sof_type = (sof_val);					\
 	(rsp)->rx_xch_addr = (src)->rx_xch_addr;			\
 	(rsp)->d_id[0] = (src)->s_id[0];				\
 	(rsp)->d_id[1] = (src)->s_id[1];				\
@@ -215,14 +213,17 @@ qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
 	if (IS_QLA29XX(ha)) {
 		struct abts_entry_24xx_ext *rsp_ext = rsp_pkt;
 
-		QLA_BUILD_ABTS_BA_ACC(rsp_ext, abts_ext,
-		    abts_ext->sof_type, fctl);
+		QLA_BUILD_ABTS_BA_ACC(rsp_ext, abts_ext, fctl);
+		rsp_ext->vp_idx_sof = qla_ext_build_vp_sof(
+		    qla_ext_get_vp_index(abts_ext->vp_idx_sof),
+		    qla_ext_get_sof_type(abts_ext->vp_idx_sof));
 		QLA_LOG_ISSUE_ABTS_RSP(vha, rsp_ext, dma, rval);
 	} else {
 		struct abts_entry_24xx *abts_rsp = rsp_pkt;
 
-		QLA_BUILD_ABTS_BA_ACC(abts_rsp, abts,
-		    abts->sof_type & 0xf0, fctl);
+		QLA_BUILD_ABTS_BA_ACC(abts_rsp, abts, fctl);
+		abts_rsp->vp_idx = abts->vp_idx;
+		abts_rsp->sof_type = abts->sof_type & 0xf0;
 		QLA_LOG_ISSUE_ABTS_RSP(vha, abts_rsp, dma, rval);
 	}
 
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 47/60] scsi: qla2xxx: Fix endianness annotations in vp_rpt_id_entry structures
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (45 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 46/60] scsi: qla2xxx: Replace __le16 bitfields with scalar and accessors Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 12:59   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 48/60] scsi: qla2xxx: Use 64-bit FPM word counters for 29xx host stats Nilesh Javali
                   ` (12 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

The vp_rpt_id_entry_24xx and vp_rpt_id_entry_24xx_ext DMA structures
use plain uint16_t for fip_flags and bbcr fields that the firmware
writes in little-endian format.  On big-endian hosts, reading bbcr
without le16_to_cpu() produces an incorrect value, breaking the
buffer-to-buffer credit enable detection.

Additionally, the 29xx ext struct uses __le16 bitfields for
vp_idx:9/vp_status:7 which suffer from architecture-dependent
bit packing order (same class of bug fixed in the ELS/ABTS
extended IOCBs).

Fix by:
  - Changing uint16_t fip_flags/bbcr to __le16 in both qla_fw.h
    and qla_fw29.h (enables Sparse endianness checking)
  - Replacing the __le16 bitfields with a scalar __le16 vp_idx_status
    and defined shift/mask constants
  - Adding le16_to_cpu() at the bbcr and vp_idx_status access sites
    in qla_mbx.c

Fixes: 1b923fdfaeb5 ("scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx")
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_fw.h   |  8 ++++----
 drivers/scsi/qla2xxx/qla_fw29.h | 20 ++++++++++++++------
 drivers/scsi/qla2xxx/qla_mbx.c  |  9 ++++++---
 3 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 4d6f8b1a36d1..b29abcc7f74f 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1538,7 +1538,7 @@ struct vp_rpt_id_entry_24xx {
 #define TOPO_N2N   0x4
 #define TOPO_F     0x6
 
-			uint16_t fip_flags;
+			__le16 fip_flags;
 			uint8_t rsv2[12];
 
 			uint8_t ls_rjt_vendor;
@@ -1548,13 +1548,13 @@ struct vp_rpt_id_entry_24xx {
 
 			uint8_t port_name[8];
 			uint8_t node_name[8];
-			uint16_t bbcr;
+			__le16 bbcr;
 			uint8_t reserved_5[6];
 		} f1;
 		struct _f2 { /* format 2: N2N direct connect */
 			uint8_t vpstat1_subcode;
 			uint8_t flags;
-			uint16_t fip_flags;
+			__le16 fip_flags;
 			uint8_t rsv2[12];
 
 			uint8_t ls_rjt_vendor;
@@ -1564,7 +1564,7 @@ struct vp_rpt_id_entry_24xx {
 
 			uint8_t port_name[8];
 			uint8_t node_name[8];
-			uint16_t bbcr;
+			__le16 bbcr;
 			uint8_t reserved_5[2];
 			uint8_t remote_nport_id[4];
 		} f2;
diff --git a/drivers/scsi/qla2xxx/qla_fw29.h b/drivers/scsi/qla2xxx/qla_fw29.h
index 63bf350ddffc..6382a054310a 100644
--- a/drivers/scsi/qla2xxx/qla_fw29.h
+++ b/drivers/scsi/qla2xxx/qla_fw29.h
@@ -51,6 +51,15 @@ static inline __le16 qla_ext_build_vp_sof(u16 vp_idx, u16 sof_type)
 			   ((sof_type & 0xf) << EXT_VP_SOF_SOF_TYPE_SHIFT));
 }
 
+/*
+ * Combined vp_idx/vp_status field layout (vp_rpt_id_entry_24xx_ext):
+ *   bits [8:0]   - VP index (9 bits)
+ *   bits [15:9]  - VP status (7 bits)
+ */
+#define EXT_VP_STATUS_VP_INDEX_MASK	0x01ff
+#define EXT_VP_STATUS_VP_STATUS_SHIFT	9
+#define EXT_VP_STATUS_VP_STATUS_MASK	0xfe00
+
 /*
  * ISP queue - command entry structure definition.
  */
@@ -708,8 +717,7 @@ struct vp_rpt_id_entry_24xx_ext {
 	__le32 resv1;
 	uint8_t vp_acquired;
 	uint8_t vp_setup;
-	__le16	vp_idx : 9;		/* VP Index 9bits */
-	__le16	vp_status : 7;		/* VP Status 7bits */
+	__le16	vp_idx_status;		/* bits [8:0]=VP index, [15:9]=VP status */
 
 	uint8_t port_id[3];
 	uint8_t format;
@@ -719,7 +727,7 @@ struct vp_rpt_id_entry_24xx_ext {
 			uint8_t vpstat1_subcode; /* vp_status=1 subcode */
 			uint8_t flags;
 
-			uint16_t fip_flags;
+			__le16 fip_flags;
 			uint8_t rsv2[12];
 
 			uint8_t ls_rjt_vendor;
@@ -730,13 +738,13 @@ struct vp_rpt_id_entry_24xx_ext {
 			__le16	flogi_acc_payload_size;	/* bits [8:0] meaningful */
 			uint8_t port_name[8];
 			uint8_t node_name[8];
-			uint16_t bbcr;
+			__le16 bbcr;
 			uint8_t reserved_5[6];
 		} f1;
 		struct vp_rpt_id_ext_f2 { /* format 2: N2N direct connect */
 			uint8_t vpstat1_subcode;
 			uint8_t flags;
-			uint16_t fip_flags;
+			__le16 fip_flags;
 			uint8_t rsv2[12];
 
 			uint8_t ls_rjt_vendor;
@@ -746,7 +754,7 @@ struct vp_rpt_id_entry_24xx_ext {
 
 			uint8_t port_name[8];
 			uint8_t node_name[8];
-			uint16_t bbcr;
+			__le16 bbcr;
 			uint8_t reserved_5[2];
 			uint8_t remote_nport_id[4];
 		} f2;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 1df48593017c..7c0cc3e9c738 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -4114,8 +4114,10 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt)
 		return;
 
 	if (IS_QLA29XX(ha)) {
-		vp_idx = rptid_entry_ext->vp_idx;
-		vp_status = rptid_entry_ext->vp_status;
+		vp_idx = le16_to_cpu(rptid_entry_ext->vp_idx_status) &
+			 EXT_VP_STATUS_VP_INDEX_MASK;
+		vp_status = (le16_to_cpu(rptid_entry_ext->vp_idx_status) >>
+			     EXT_VP_STATUS_VP_STATUS_SHIFT) & 0x7f;
 	} else {
 		vp_idx = rptid_entry->vp_idx;
 		vp_status = rptid_entry->vp_status;
@@ -4239,7 +4241,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt)
 		ha->flags.gpsc_supported = 1;
 		ha->current_topology = ISP_CFG_F;
 		/* buffer to buffer credit flag */
-		vha->flags.bbcr_enable = (rptid_entry->u.f1.bbcr & 0xf) != 0;
+		vha->flags.bbcr_enable =
+		    (le16_to_cpu(rptid_entry->u.f1.bbcr) & 0xf) != 0;
 
 		if (vp_idx == 0) {
 			if (vp_status == VP_STAT_COMPL) {
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 48/60] scsi: qla2xxx: Use 64-bit FPM word counters for 29xx host stats
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (46 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 47/60] scsi: qla2xxx: Fix endianness annotations in vp_rpt_id_entry structures Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 13:00   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 49/60] scsi: qla2xxx: Add 64G/128G port speed setting support Nilesh Javali
                   ` (11 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

29xx provides the 64-bit FPM transmit/receive word counters in the link
statistics block, like 83xx/27xx/28xx.  qla2x00_get_fc_host_stats()
only consumed those counters for the older families and fell back to the
software approximation (input/output bytes >> 2) on 29xx, reporting less
accurate rx_words/tx_words.

Add IS_QLA29XX() to the high-speed branch so 29xx reports the hardware
word counters.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_attr.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index fd3c8c207535..308b85e04f26 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -2990,7 +2990,8 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
 		p->error_frames =
 		    le32_to_cpu(stats->dropped_frames) +
 		    le32_to_cpu(stats->discarded_frames);
-		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
+		    IS_QLA29XX(ha)) {
 			p->rx_words = le64_to_cpu(stats->fpm_recv_word_cnt);
 			p->tx_words = le64_to_cpu(stats->fpm_xmit_word_cnt);
 		} else {
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 49/60] scsi: qla2xxx: Add 64G/128G port speed setting support
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (47 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 48/60] scsi: qla2xxx: Use 64-bit FPM word counters for 29xx host stats Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 13:02   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 50/60] scsi: qla2xxx: Fix 64G link speed reporting in get_data_rate Nilesh Javali
                   ` (10 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

The port speed setting paths topped out at 32G: qla2x00_port_speed_store()
only mapped sysfs inputs up to 32 (and their no-loss-of-sync forms up to
320), and qla2x00_set_data_rate() only accepted PORT_SPEED_AUTO/4/8/16/32
in its switch.  A user request for 64G or 128G therefore hit the default
arm and was silently downgraded to auto-negotiation.

Map the 64 and 128 sysfs inputs (and their /10 no-loss-of-sync forms 640
and 1280) to PORT_SPEED_64GB and PORT_SPEED_128GB, and accept those
values in qla2x00_set_data_rate().  The firmware validates the requested
rate against the adapter's actual capability.

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_attr.c | 8 +++++++-
 drivers/scsi/qla2xxx/qla_mbx.c  | 2 ++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 308b85e04f26..4c1812c4b420 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1835,7 +1835,7 @@ qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
 		return rval;
 	speed = type;
 	if (type == 40 || type == 80 || type == 160 ||
-	    type == 320) {
+	    type == 320 || type == 640 || type == 1280) {
 		ql_dbg(ql_dbg_user, vha, 0x70d9,
 		    "Setting will be affected after a loss of sync\n");
 		type = type/10;
@@ -1860,6 +1860,12 @@ qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
 	case 32:
 		ha->set_data_rate = PORT_SPEED_32GB;
 		break;
+	case 64:
+		ha->set_data_rate = PORT_SPEED_64GB;
+		break;
+	case 128:
+		ha->set_data_rate = PORT_SPEED_128GB;
+		break;
 	default:
 		ql_log(ql_log_warn, vha, 0x1199,
 		    "Unrecognized speed setting:%lx. Setting Autoneg\n",
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 7c0cc3e9c738..5a5d33e8ee7f 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -5728,6 +5728,8 @@ qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode)
 	case PORT_SPEED_8GB:
 	case PORT_SPEED_16GB:
 	case PORT_SPEED_32GB:
+	case PORT_SPEED_64GB:
+	case PORT_SPEED_128GB:
 		val = ha->set_data_rate;
 		break;
 	default:
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 50/60] scsi: qla2xxx: Fix 64G link speed reporting in get_data_rate
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (48 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 49/60] scsi: qla2xxx: Add 64G/128G port speed setting support Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 13:03   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 51/60] scsi: qla2xxx: edif: Fix NULL pointer deref in RX SA delete check Nilesh Javali
                   ` (9 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

qla2x00_get_data_rate() skips updating ha->link_data_rate when the
firmware returns mcp->mb[1] == 0x7.  That value was a legacy sentinel
from before 64G hardware existed, but PORT_SPEED_64GB is now defined as
0x07 and ha->link_data_rate is decoded with the PORT_SPEED_* encoding.
On a 64G-capable adapter a genuine 64G link is therefore dropped, and
the port speed is misreported (port_speed sysfs, fc_host speed, FDMI).

Only 28xx and 29xx support 64G, so accept 0x07 on those adapters while
keeping the legacy filter for older ones.  Also drop the duplicate
copy of the check at the end of the success branch; it repeated the
first assignment with no intervening change.

Fixes: ecc89f25e225 ("scsi: qla2xxx: Add Device ID for ISP28XX")
Cc: stable@vger.kernel.org
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_mbx.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 5a5d33e8ee7f..d661662aed26 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -5793,10 +5793,11 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
 		ql_dbg(ql_dbg_mbx, vha, 0x1107,
 		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
 	} else {
-		if (mcp->mb[1] != 0x7)
+		if (mcp->mb[1] != 0x7 || IS_QLA28XX(ha) || IS_QLA29XX(ha))
 			ha->link_data_rate = mcp->mb[1];
 
-		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
+		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
+		    IS_QLA29XX(ha)) {
 			if (mcp->mb[4] & BIT_0)
 				ql_log(ql_log_info, vha, 0x11a2,
 				    "FEC=enabled (data rate).\n");
@@ -5804,8 +5805,6 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
 
 		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1108,
 		    "Done %s.\n", __func__);
-		if (mcp->mb[1] != 0x7)
-			ha->link_data_rate = mcp->mb[1];
 	}
 
 	return rval;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 51/60] scsi: qla2xxx: edif: Fix NULL pointer deref in RX SA delete check
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (49 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 50/60] scsi: qla2xxx: Fix 64G link speed reporting in get_data_rate Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:43   ` sashiko-bot
  2026-06-12 13:04   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 52/60] scsi: qla2xxx: Fix Name Server logout detection on FWI2 adapters Nilesh Javali
                   ` (8 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

qla_chk_edif_rx_sa_delete_pending() obtains the SCSI command via
GET_CMD_SP(sp) and immediately dereferences cmd->sc_data_direction.
That command pointer can be NULL: the firmware may post a status
completion for a command that has already been returned or aborted.
The caller qla2x00_status_entry() acknowledges this on the very same
status path, re-fetching GET_CMD_SP(sp) and bailing out with the
"Command already returned" message when it is NULL -- but that check
runs only after qla_chk_edif_rx_sa_delete_pending() has already
dereferenced the pointer, so a NULL cmd crashes the kernel in
interrupt context.

Return early when cmd is NULL, before touching cmd->sc_data_direction.

Fixes: dd30706e73b7 ("scsi: qla2xxx: edif: Add key update")
Cc: stable@vger.kernel.org
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_edif.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
index f8bc248e5d18..c8889ea199d3 100644
--- a/drivers/scsi/qla2xxx/qla_edif.c
+++ b/drivers/scsi/qla2xxx/qla_edif.c
@@ -3543,6 +3543,9 @@ void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
 	uint32_t handle;
 	uint16_t sa_index;
 
+	if (!cmd)
+		return;
+
 	handle = (uint32_t)LSW(sts24->handle);
 
 	/* find out if this status iosb is for a scsi read */
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 52/60] scsi: qla2xxx: Fix Name Server logout detection on FWI2 adapters
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (50 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 51/60] scsi: qla2xxx: edif: Fix NULL pointer deref in RX SA delete check Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 13:08   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 53/60] scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size Nilesh Javali
                   ` (7 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

In the CS_PORT_LOGGED_OUT case of qla2x00_chk_ms_status(), the
FWI2-capable branch compared ms_pkt->loop_id.extended against NPH_SNS
to decide whether the Name Server had logged out. On FWI2 and later
adapters the response is a ct_entry_24xx / ct_entry_24xx_ext, where
loop_id.extended (via the legacy ms_iocb_entry_t view) aliases offset 8,
which is comp_status, not nport_handle (offset 10). As this code runs
under CS_PORT_LOGGED_OUT, the field read back 0x29 (CS_PORT_LOGGED_OUT)
and the comparison against NPH_SNS (0x7fc) was always false.

As a result the driver never recognized a Name Server logout on FWI2/
29xx adapters: it returned the generic QLA_FUNCTION_FAILED instead of
QLA_NOT_LOGGED_IN and skipped setting LOOP_RESYNC_NEEDED /
LOCAL_LOOP_UPDATE, so the fabric rediscovery triggered by an SNS logout
did not happen.

Read nport_handle from the ct_entry_24xx layout (offset 10) instead.
nport_handle is at the same offset in ct_entry_24xx and
ct_entry_24xx_ext, so a single cast covers 24xx-class and 29xx. The
non-FWI2 branch keeps using loop_id.extended, which is correct for the
ms_iocb_entry_t response on those adapters.

Fixes: b98ae0d748db ("scsi: qla2xxx: Fix name server relogin")
Cc: stable@vger.kernel.org
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_gs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index eefd1440d197..0d345009732a 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -192,8 +192,8 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
 			break;
 		case CS_PORT_LOGGED_OUT:
 			if (IS_FWI2_CAPABLE(ha)) {
-				if (le16_to_cpu(ms_pkt->loop_id.extended) ==
-				    NPH_SNS)
+				if (le16_to_cpu(((struct ct_entry_24xx *)
+				    ms_pkt)->nport_handle) == NPH_SNS)
 					lid_is_sns = true;
 			} else {
 				if (le16_to_cpu(ms_pkt->loop_id.extended) ==
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 53/60] scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (51 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 52/60] scsi: qla2xxx: Fix Name Server logout detection on FWI2 adapters Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:35   ` sashiko-bot
  2026-06-12 13:09   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 54/60] scsi: qla2xxx: Check entry_status in qla24xx_modify_vp_config() Nilesh Javali
                   ` (6 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

The VP control IOCB selects its target virtual port by setting one bit
in vp_idx_map, a fixed 16-byte (128-bit) array in both
vp_ctrl_entry_24xx and vp_ctrl_entry_24xx_ext. qla25xx_ctrlvp_iocb()
computes map = (vp_index - 1) / 8 and writes vce->vp_idx_map[map]
without checking that map stays within the array.

max_npiv_vports is taken from firmware and only sanitized to a
MIN_MULTI_ID_FABRIC-aligned boundary, so it can legitimately be 191 or
255, and qla24xx_control_vp() only rejects vp_index >= max_npiv_vports.
A vp_index above 128 therefore yields map >= 16 and an out-of-bounds
write of up to 16 bytes past vp_idx_map, corrupting the trailing IOCB
fields (or the adjacent request-ring slot on the 64-byte layout).

Reject a vp_index that cannot be represented in the IOCB bitmap in
qla24xx_control_vp(), and add a defensive ARRAY_SIZE() guard in
qla25xx_ctrlvp_iocb() before the write. Adapters that report the usual
63 or 127 NPIV vports are unaffected.

Fixes: 2853192e154b ("scsi: qla2xxx: Use IOCB path to submit Control VP MBX command")
Cc: stable@vger.kernel.org
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_iocb.c | 6 ++++++
 drivers/scsi/qla2xxx/qla_mid.c  | 8 ++++++++
 2 files changed, 14 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index a103be30fddb..8b5a13823b3d 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -4068,6 +4068,12 @@ qla25xx_ctrlvp_iocb(srb_t *sp, void *pkt)
 	vce->entry_count = 1;
 	vce->command = cpu_to_le16(sp->u.iocb_cmd.u.ctrlvp.cmd);
 	vce->vp_count = cpu_to_le16(1);
+	if (map >= ARRAY_SIZE(vce->vp_idx_map)) {
+		ql_log(ql_log_warn, sp->vha, 0x307c,
+		       "ctrlvp: vp_index %u exceeds vp_idx_map capacity\n",
+		       sp->u.iocb_cmd.u.ctrlvp.vp_index);
+		return;
+	}
 	vce->vp_idx_map[map] |= 1 << pos;
 }
 
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 7072af5b4217..b7d9c1a53f3c 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -987,6 +987,14 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
 	if (vp_index == 0 || vp_index >= ha->max_npiv_vports)
 		return QLA_PARAMETER_ERROR;
 
+	/*
+	 * The VP_CTRL IOCB selects the target VP through a fixed 128-bit
+	 * (16-byte) vp_idx_map bitmap, so vp_index must fit within it even
+	 * if firmware advertises more NPIV vports.
+	 */
+	if (vp_index > sizeof_field(struct vp_ctrl_entry_24xx, vp_idx_map) * 8)
+		return QLA_PARAMETER_ERROR;
+
 	/* ref: INIT */
 	sp = qla2x00_get_sp(base_vha, NULL, GFP_KERNEL);
 	if (!sp)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 54/60] scsi: qla2xxx: Check entry_status in qla24xx_modify_vp_config()
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (52 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 53/60] scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 13:10   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 55/60] scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition() Nilesh Javali
                   ` (5 subsequent siblings)
  59 siblings, 1 reply; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

The Modify VP Config completion handler labelled its first error branch
"error status" but tested vpmod->comp_status instead of
vpmod->entry_status. Because CS_COMPLETE is 0, the following
"comp_status != CS_COMPLETE" branch duplicated that test and was dead
code, and entry_status was never examined at all.

When firmware rejects the IOCB early it sets entry_status while leaving
comp_status zero. As the IOCB is allocated with dma_pool_zalloc(), both
comp_status branches evaluate false and the handler falls through to the
success path, calling fc_vport_set_state(FC_VPORT_INITIALIZING) for a
configuration the firmware never accepted. This can leave the virtual
port enabled on top of an invalid config and surface later as login
timeouts or follow-on firmware errors.

Test entry_status in the first branch, matching qla_ctrlvp_completed()
and the login/logout/abort/reset IOCB handlers; the comp_status branch
then becomes the live completion-status check.

Fixes: 2c3dfe3f6ad8 ("[SCSI] qla2xxx: add support for NPIV")
Cc: stable@vger.kernel.org
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_mbx.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index d661662aed26..8a001b489fc0 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -4409,10 +4409,10 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
 	if (rval != QLA_SUCCESS) {
 		ql_dbg(ql_dbg_mbx, vha, 0x10bd,
 		    "Failed to issue VP config IOCB (%x).\n", rval);
-	} else if (vpmod->comp_status != 0) {
+	} else if (vpmod->entry_status != 0) {
 		ql_dbg(ql_dbg_mbx, vha, 0x10be,
 		    "Failed to complete IOCB -- error status (%x).\n",
-		    vpmod->comp_status);
+		    vpmod->entry_status);
 		rval = QLA_FUNCTION_FAILED;
 	} else if (vpmod->comp_status != cpu_to_le16(CS_COMPLETE)) {
 		ql_dbg(ql_dbg_mbx, vha, 0x10bf,
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 55/60] scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition()
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (53 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 54/60] scsi: qla2xxx: Check entry_status in qla24xx_modify_vp_config() Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:38   ` sashiko-bot
  2026-06-12 13:10   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 56/60] scsi: qla2xxx: Initialize NVMe abort_work once at submission Nilesh Javali
                   ` (4 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

In the format 1 path, the virtual port is located on ha->vp_list while
holding vport_slock, but the lock is dropped before vp is used:
qla_update_host_map() is called and VP_IDX_ACQUIRED/REGISTER_FC4_NEEDED/
REGISTER_FDMI_NEEDED are set on vp. No reference is taken across that
window, so a concurrent qla24xx_deallocate_vp_id() can tear the vport
down and free it, leading to a use-after-free.

Take a vport reference (vref_count) under vport_slock when the matching
vp is found, and drop it after the last use of vp. qla24xx_deallocate_vp_id()
waits for vref_count to reach zero before unlinking and freeing the vport,
so the pointer stays valid. This matches the reference idiom already used
by the other ha->vp_list traversals.

Fixes: 2c3dfe3f6ad8 ("[SCSI] qla2xxx: add support for NPIV")
Cc: stable@vger.kernel.org
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_mbx.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 8a001b489fc0..bfb931eb14f6 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -4275,6 +4275,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt)
 			list_for_each_entry(vp, &ha->vp_list, list) {
 				if (vp_idx == vp->vp_idx) {
 					found = 1;
+					atomic_inc(&vp->vref_count);
 					break;
 				}
 			}
@@ -4292,6 +4293,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt)
 			set_bit(VP_IDX_ACQUIRED, &vp->vp_flags);
 			set_bit(REGISTER_FC4_NEEDED, &vp->dpc_flags);
 			set_bit(REGISTER_FDMI_NEEDED, &vp->dpc_flags);
+
+			atomic_dec(&vp->vref_count);
 		}
 		set_bit(VP_DPC_NEEDED, &vha->dpc_flags);
 		qla2xxx_wake_dpc(vha);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 56/60] scsi: qla2xxx: Initialize NVMe abort_work once at submission
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (54 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 55/60] scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition() Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:34   ` sashiko-bot
  2026-06-12 13:11   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 57/60] scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject Nilesh Javali
                   ` (3 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

qla_nvme_fcp_abort() and qla_nvme_ls_abort() ran INIT_WORK() on
priv->abort_work immediately before schedule_work(). INIT_WORK()
reinitializes the work_struct, resetting its list head and clearing the
pending bit. If an abort is issued more than once for the same command
(for example, concurrent transport teardown and a timeout-driven abort),
the second INIT_WORK() reinitializes a work item that is already queued,
which can corrupt the workqueue list and lead to crashes or a looping
worker.

Initialize priv->abort_work once at command submission, next to the
existing per-command spin_lock_init(&priv->cmd_lock), and leave only
schedule_work() in the abort paths. schedule_work() already does nothing
when the work item is still pending, so a repeated abort no longer
disturbs an in-flight work item. The command is not returned to the
transport until the final kref_put()/release callback runs after
abort_work has completed, so the work item is idle before priv is
reused and the single submission-time INIT_WORK() is safe.

Fixes: e473b3074104 ("scsi: qla2xxx: Add FC-NVMe abort processing")
Cc: stable@vger.kernel.org
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_nvme.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index 0038b6274d44..3b2f255a5d7d 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -463,7 +463,6 @@ static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport,
 	}
 	spin_unlock_irqrestore(&priv->cmd_lock, flags);
 
-	INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
 	schedule_work(&priv->abort_work);
 }
 
@@ -501,6 +500,7 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
 	priv->sp = sp;
 	kref_init(&sp->cmd_kref);
 	spin_lock_init(&priv->cmd_lock);
+	INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
 	nvme = &sp->u.iocb_cmd;
 	priv->fd = fd;
 	nvme->u.nvme.desc = fd;
@@ -545,7 +545,6 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport,
 	}
 	spin_unlock_irqrestore(&priv->cmd_lock, flags);
 
-	INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
 	schedule_work(&priv->abort_work);
 }
 
@@ -877,6 +876,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
 
 	kref_init(&sp->cmd_kref);
 	spin_lock_init(&priv->cmd_lock);
+	INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
 	sp->priv = priv;
 	priv->sp = sp;
 	sp->type = SRB_NVME_CMD;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 57/60] scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (55 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 56/60] scsi: qla2xxx: Initialize NVMe abort_work once at submission Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:39   ` sashiko-bot
  2026-06-12 13:11   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 58/60] scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak Nilesh Javali
                   ` (2 subsequent siblings)
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

qla_nvme_ls_reject_iocb() allocates from and advances the request ring
through __qla2x00_alloc_iocbs() (which assumes the hardware_lock is held)
and qla2x00_start_iocbs() (which advances the ring and rings the
request-in doorbell), but takes no lock itself. Two of its callers invoke
it without the producer lock held:

  - qla_nvme_xmt_ls_rsp(), the NVMe-FC .xmt_ls_rsp transport callback, on
    its error path, and
  - qla2xxx_process_purls_pkt(), run from the purex work/DPC context.

Both use ha->base_qpair, whose qp_lock_ptr is hardware_lock, so they can
run concurrently with normal I/O submission on the base ring and corrupt
the ring producer state, leading to duplicated or dropped commands. The
third caller, qla2xxx_process_purls_iocb(), runs inside
qla24xx_process_response_queue() with the qpair lock already held and is
safe; that is also why the lock cannot be taken inside the helper itself
(it would recursively re-acquire hardware_lock on the response path).

Take qp_lock_ptr around the two unlocked callers and document the helper
as caller-locked. Both run in process context, so spin_lock_irqsave() is
used and nothing in the locked region sleeps.

Fixes: 875386b98857 ("scsi: qla2xxx: Add Unsolicited LS Request and Response Support for NVMe")
Cc: stable@vger.kernel.org
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_nvme.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index 3b2f255a5d7d..8dc6df6c2e1c 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -374,6 +374,7 @@ static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport,
 	srb_t *sp;
 	int rval = QLA_FUNCTION_FAILED;
 	uint8_t cnt = 0;
+	unsigned long flags;
 
 	if (!fcport || fcport->deleted)
 		goto out;
@@ -440,7 +441,9 @@ static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport,
 	a.vp_idx = vha->vp_idx;
 	a.nport_handle = uctx->nport_handle;
 	a.xchg_address = uctx->exchange_address;
+	spin_lock_irqsave(ha->base_qpair->qp_lock_ptr, flags);
 	qla_nvme_ls_reject_iocb(vha, ha->base_qpair, &a, true);
+	spin_unlock_irqrestore(ha->base_qpair->qp_lock_ptr, flags);
 	kfree(uctx);
 	return rval;
 }
@@ -1243,6 +1246,10 @@ static void qla_nvme_lsrjt_pt_iocb(struct scsi_qla_host *vha,
 	}
 }
 
+/*
+ * Allocates from and advances the request ring, so the caller must hold
+ * qp->qp_lock_ptr (the response-queue caller already holds it).
+ */
 static int
 qla_nvme_ls_reject_iocb(struct scsi_qla_host *vha, struct qla_qpair *qp,
 			struct qla_nvme_lsrjt_pt_arg *a, bool is_xchg_terminate)
@@ -1299,6 +1306,7 @@ qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item)
 {
 	struct qla_nvme_unsol_ctx *uctx = item->purls_context;
 	struct qla_nvme_lsrjt_pt_arg a;
+	unsigned long flags;
 	int ret = 1;
 
 #if (IS_ENABLED(CONFIG_NVME_FC))
@@ -1311,7 +1319,9 @@ qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item)
 		a.vp_idx = vha->vp_idx;
 		a.nport_handle = uctx->nport_handle;
 		a.xchg_address = uctx->exchange_address;
+		spin_lock_irqsave(vha->hw->base_qpair->qp_lock_ptr, flags);
 		qla_nvme_ls_reject_iocb(vha, vha->hw->base_qpair, &a, true);
+		spin_unlock_irqrestore(vha->hw->base_qpair->qp_lock_ptr, flags);
 		list_del(&uctx->elem);
 		kfree(uctx);
 	}
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 58/60] scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (56 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 57/60] scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:40   ` sashiko-bot
  2026-06-12 13:12   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 59/60] scsi: qla2xxx: Fix BSG job leak on validate flash image error path Nilesh Javali
  2026-06-12  9:53 ` [PATCH v2 60/60] scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions() Nilesh Javali
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

qla2x00_do_dport_diagnostics() allocates the qla_dport_diag response
buffer with kmalloc_obj() (non-zeroing) and, on success, copies the
full sizeof(*dd) back to user space via sg_copy_from_buffer(). The
inbound sg_copy_to_buffer() only fills as many bytes as the user
request payload provides, and qla26xx_dport_diagnostics() zeroes only
dd->buf. The options and unused[] fields are therefore copied out
uninitialized, leaking kernel heap contents to user space.

Allocate with kzalloc_obj(), matching qla2x00_do_dport_diagnostics_v2().

Fixes: ec89146215d1 ("qla2xxx: Add bsg interface to support D_Port Diagnostics.")
Cc: stable@vger.kernel.org
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_bsg.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 7f4558beee2c..b57c55964f9e 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -2744,7 +2744,7 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job)
 	    !IS_QLA28XX(vha->hw) && !IS_QLA29XX(vha->hw))
 		return -EPERM;
 
-	dd = kmalloc_obj(*dd);
+	dd = kzalloc_obj(*dd);
 	if (!dd) {
 		ql_log(ql_log_warn, vha, 0x70db,
 		    "Failed to allocate memory for dport.\n");
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 59/60] scsi: qla2xxx: Fix BSG job leak on validate flash image error path
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (57 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 58/60] scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:38   ` sashiko-bot
  2026-06-12 13:12   ` Hannes Reinecke
  2026-06-12  9:53 ` [PATCH v2 60/60] scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions() Nilesh Javali
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

qla28xx_validate_flash_image() returns QLA_SUCCESS (0) unconditionally,
telling the FC BSG transport (fc_bsg_host_dispatch()) that the driver
owns and will complete the request. But bsg_job_done() is guarded by
"if (!rval)", so on the error path (rval == -EINVAL) neither the driver
nor the transport completes the job. The request dangles until it times
out, leaking block layer resources.

Commit c2c68225b145 ("scsi: qla2xxx: Fix bsg_done() causing double
free") added the "if (!rval)" guard to a batch of BSG handlers. That is
correct for handlers that also return the error code (the transport then
completes the job once via fail_host_msg), but this function returns
QLA_SUCCESS unconditionally, so the guard turned a correct single
completion into a leak.

Always call bsg_job_done(): bsg_reply->result is DID_OK and the error is
reported in vendor_rsp[0], and since the function returns 0 the transport
will not complete the job a second time.

Fixes: c2c68225b145 ("scsi: qla2xxx: Fix bsg_done() causing double free")
Cc: stable@vger.kernel.org
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_bsg.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index b57c55964f9e..22be6c822dda 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -3734,9 +3734,8 @@ static int qla28xx_validate_flash_image(struct bsg_job *bsg_job)
 	bsg_reply->result = DID_OK << 16;
 	bsg_reply->reply_payload_rcv_len = 0;
 	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
-	if (!rval)
-		bsg_job_done(bsg_job, bsg_reply->result,
-			     bsg_reply->reply_payload_rcv_len);
+	bsg_job_done(bsg_job, bsg_reply->result,
+		     bsg_reply->reply_payload_rcv_len);
 
 	return QLA_SUCCESS;
 }
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v2 60/60] scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions()
  2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
                   ` (58 preceding siblings ...)
  2026-06-12  9:53 ` [PATCH v2 59/60] scsi: qla2xxx: Fix BSG job leak on validate flash image error path Nilesh Javali
@ 2026-06-12  9:53 ` Nilesh Javali
  2026-06-12 11:45   ` sashiko-bot
  2026-06-12 13:13   ` Hannes Reinecke
  59 siblings, 2 replies; 154+ messages in thread
From: Nilesh Javali @ 2026-06-12  9:53 UTC (permalink / raw)
  To: martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi,
	hare

qla2x00_update_fru_versions() copies the user-supplied BSG request into
a fixed 256-byte stack buffer (bsg[DMA_POOL_SIZE]) and then iterates
list->count times over the qla_image_version array embedded in that
buffer, advancing the image pointer each iteration. count is taken
directly from user input with no upper bound, while only
(DMA_POOL_SIZE - sizeof(list->count)) / sizeof(struct qla_image_version)
= 6 entries actually fit. A larger count walks the image pointer off the
end of the stack buffer, reading adjacent kernel stack memory and
sending it to the device via qla2x00_write_sfp().

Reject requests whose declared count does not fit in the buffer.

Fixes: 697a4bc69159 ("[SCSI] qla2xxx: Provide method for updating I2C attached VPD.")
Cc: stable@vger.kernel.org
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_bsg.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 22be6c822dda..bcca4ef3c23e 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -1929,6 +1929,13 @@ qla2x00_update_fru_versions(struct bsg_job *bsg_job)
 
 	image = list->version;
 	count = list->count;
+
+	if (struct_size(list, version, count) > sizeof(bsg)) {
+		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
+		    EXT_STATUS_INVALID_PARAM;
+		goto dealloc;
+	}
+
 	while (count--) {
 		memcpy(sfp, &image->field_info, sizeof(image->field_info));
 		rval = qla2x00_write_sfp(vha, sfp_dma, sfp,
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 07/60] scsi: qla2xxx: Add flash block read/write BSG support for 29xx
  2026-06-12  9:52 ` [PATCH v2 07/60] scsi: qla2xxx: Add flash block read/write BSG support " Nilesh Javali
@ 2026-06-12 10:11   ` sashiko-bot
  2026-06-12 10:55   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:11 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Silent truncation of the 32-bit `region` parameter to 16 bits in BSG flash read/write handlers.
--

commit 42123b5c17ee809c301462b168b534861a97e40d
Author: Manish Rangankar <mrangankar@marvell.com>

scsi: qla2xxx: Add flash block read/write BSG support for 29xx

Introduce QL_VND_READ_FLASH_BLOCK and QL_VND_WRITE_FLASH_BLOCK
BSG vendor commands so that userspace tools can perform flash
block-level operations on 29xx adapters via the isp_ops interface.

> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index 5e910b5ca670d..0baf486e8fb89 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
[ ... ]
> +static int qla29xx_bsg_flash_block_read(struct bsg_job *bsg_job)
> +{
[ ... ]
> +	buf = ha->isp_ops->read_optrom_region(vha, brcmd->region, opts,
> +				ha->optrom_buffer, ha->optrom_region_start,
> +				ha->optrom_region_size);

[Severity: Medium]
Does this code silently truncate brcmd->region? 

The qla_block_rw structure defines region as a uint32_t, but the
read_optrom_region() function pointer takes a uint16_t for the reg_code
parameter.

If userspace passes a region ID greater than 0xFFFF, this will silently
truncate the ID instead of returning -EINVAL. Could this lead to accidental
firmware corruption if an invalid region ID wraps around to a valid one?

[ ... ]
> +static int qla29xx_bsg_flash_block_write(struct bsg_job *bsg_job)
> +{
[ ... ]
> +	rval = ha->isp_ops->write_optrom_region(vha, bwcmd->region, opts,
> +				ha->optrom_buffer, ha->optrom_region_start,
> +				ha->optrom_region_size);

[Severity: Medium]
Similarly, does this silently truncate bwcmd->region from uint32_t to
uint16_t when passing it to write_optrom_region()?

> diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
> index a920c8e482bc6..ca0d83986b57f 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.h
> +++ b/drivers/scsi/qla2xxx/qla_bsg.h
[ ... ]
> +struct qla_block_rw {
> +	uint32_t region;
> +	uint32_t rw_length;
> +	uint32_t options;
> +	uint32_t region_offset;
> +	uint32_t chunk_length;
> +	uint8_t  reserved[44];
> +} __packed;

> diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
> index 1ec7ee578e0c3..719b6a1f9123a 100644
> --- a/drivers/scsi/qla2xxx/qla_def.h
> +++ b/drivers/scsi/qla2xxx/qla_def.h
> @@ -3534,6 +3534,13 @@ struct isp_operations {
>  	int (*write_optrom)(struct scsi_qla_host *, void *, uint32_t,
>  		uint32_t);
>  
> +	void *(*read_optrom_region)(struct scsi_qla_host *vha,
> +		uint16_t reg_code, uint16_t opts, void *buf,
> +		uint32_t offset, uint32_t length);
> +	int (*write_optrom_region)(struct scsi_qla_host *vha,
> +		uint16_t reg_code, uint16_t opts, void *buf,
> +		uint32_t offset, uint32_t length);
> +

The function pointers use uint16_t for reg_code, but the caller above
provides a uint32_t.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=7

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 06/60] scsi: qla2xxx: Add FC operational firmware load for 29xx
  2026-06-12  9:52 ` [PATCH v2 06/60] scsi: qla2xxx: Add FC operational firmware load for 29xx Nilesh Javali
@ 2026-06-12 10:14   ` sashiko-bot
  2026-06-12 10:52   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:14 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Unconditional byte-swapping of `risc_attr` using `swab32()` instead of `be32_to_cpu()` causes endianness corruption.
- [High] Heap out-of-bounds read in `qla29xx_load_fw_template()` due to missing bounds check on `template_size`.
- [High] Out-of-bounds read in `qla29xx_load_risc_blob()` due to missing bounds checks on `array3_addr` dereferences.
- [High] Logic Error: Missing `BIT_1` (last chunk) flag due to flawed `is_last_chunk` calculation.
- [High] Integer overflow of firmware section offsets and lengths bypasses bounds checks on 32-bit systems.
--

commit 010601e8a1ad75507948f2ba92e178c2b94266b2
Author: Manish Rangankar <mrangankar@marvell.com>
scsi: qla2xxx: Add FC operational firmware load for 29xx

This commit adds support to load the 29xx FC operational firmware from the
filesystem and sets up the corresponding firmware dump template.

> diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
> --- a/drivers/scsi/qla2xxx/qla_init.c
> +++ b/drivers/scsi/qla2xxx/qla_init.c

[ ... ]

> +static int qla29xx_process_rd_image(struct scsi_qla_host *vha,

[ ... ]

> +				is_last_chunk =
> +					(chunk == (chunks_per_segment - 1) ||
> +					 size_remainder < CHUNK_SIZE);

[Severity: High]
Does this logic accurately capture the final chunk when the remaining size is
exactly a multiple of the chunk size?

If the final segment's remaining size is exactly CHUNK_SIZE, size_remainder <
CHUNK_SIZE evaluates to false. Because it is a partial segment, the chunk
index will also be less than chunks_per_segment - 1. Since both conditions
are false, is_last_chunk becomes false. Could this cause the final chunk to
be sent without the BIT_1 flag, potentially hanging the firmware load?

[ ... ]

> +static int
> +qla29xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
> +{

[ ... ]

> +	header->header_length <<= 2;
> +	header->tim_length <<= 2;
> +	header->array1_length <<= 2;
> +	header->array2_length <<= 2;
> +	header->array3_length <<= 2;
> +	header->array4_length <<= 2;
> +
> +	if (!header->segment_size) {

[Severity: High]
Could these shifts result in integer overflow on 32-bit systems?

The firmware section lengths are multiplied by 4 without verifying if the
multiplication overflows.

[ ... ]

> +		/* Array 1 */
> +		offset += header->tim_length;
> +		if (offset + header->array1_length > fw_size) {
> +			ql_log(ql_log_fatal, vha, 0x0098,

If a crafted firmware image provides large section lengths (for instance,
0xFFFFFFFC), adding the offset could wrap around to a small value on 32-bit
architectures. Would this bypass the bounds check and cause the inner copy
loop in qla29xx_process_rd_image() to read past the end of the firmware
buffer?

[ ... ]

> +		/* Array 3: FW_DUMP template */
> +		if (offset + 10 * sizeof(__be32) > fw_size) {
> +			ql_log(ql_log_fatal, vha, 0x0098,
> +			       "FW image too small for risc_attr.\n");
> +			goto img_corrupt;
> +		}
> +		array1_addr = (__be32 *)((char *)fwcode +
> +				header->header_length +
> +				header->tim_length);
> +		risc_attr = swab32(array1_addr[9]);

[Severity: High]
Does using swab32() here cause endianness issues on big-endian architectures?

Since array1_addr is defined as an array of __be32, the data is already being
read in native memory order. Converting this to CPU endianness typically
requires be32_to_cpu(). Using an unconditional byte swap produces the correct
result on little-endian machines, but might corrupt the value on big-endian
systems, which could break the template count logic.

[ ... ]

> +	array3_addr = (__be32 *)(((char *)fwcode) + array3_offset);
> +	for (j = 0; j < templates; j++, fwdt++) {
> +		vfree(fwdt->template);
> +		fwdt->template = NULL;
> +		fwdt->length = 0;
> +
> +		array_size = be32_to_cpu(array3_addr[2]);

[Severity: High]
Is there a bounds check ensuring array3_addr has enough capacity before
dereferencing it?

While there is a check earlier to ensure array3_offset does not exceed the
total firmware size, that check allows the offset to sit exactly at the
end of the file. Dereferencing array3_addr[2] here might read past the end
of the buffer if the remaining size is less than 12 bytes.

[ ... ]

> +		fwdt->length = dlen;
> +		ql_dbg(ql_dbg_init, vha, 0x0168,
> +		       "-> fwdt%u loaded template ok\n", j);
> +
> +		array3_addr += array_size + 1;
> +	}

Additionally, if the loop continues for another template, array3_addr is
advanced and immediately dereferenced at the start of the next iteration
without validating if the new address remains within the firmware blob.
Could this also lead to an out-of-bounds read?

[ ... ]

> +static int
> +qla29xx_load_fw_template(scsi_qla_host_t *vha)
> +{

[ ... ]

> +	for (j = 0; j < templates; j++, fwdt++) {
> +		vfree(fwdt->template);
> +		fwdt->template = NULL;
> +		fwdt->length = 0;
> +
> +		template_size = le32_to_cpu(((__le32 *)fw_dump_tmplt)[2]);

[ ... ]

> +		fwdt->template = vmalloc(template_size);
> +		if (!fwdt->template) {
> +			ql_log(ql_log_warn, vha, 0x0164,
> +			       "-> fwdt%u failed allocate template.\n", j);
> +			goto failed;
> +		}
> +
> +		dcode = fwdt->template;
> +		memcpy((char *)dcode, (char *)fw_dump_tmplt, template_size);

[Severity: High]
Does template_size need to be validated against the actual size of the
fw_dump_tmplt allocation?

The template_size is read directly from the flash buffer data. Without
checking if template_size is less than or equal to ha->fw_dump_tmplt_len,
a malformed flash image specifying an excessively large template_size might
cause memcpy() to read out of bounds from the fw_dump_tmplt heap allocation.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=6

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 08/60] scsi: qla2xxx: Add BSG MPI firmware load/dump for 29xx
  2026-06-12  9:52 ` [PATCH v2 08/60] scsi: qla2xxx: Add BSG MPI firmware load/dump " Nilesh Javali
@ 2026-06-12 10:14   ` sashiko-bot
  2026-06-12 10:57   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:14 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] The implementations of LOAD and DUMP MPI commands are semantically reversed, leading to firmware data corruption.
- [High] Incorrect address scaling in `qla29xx_mpi_optrom_data()` mixes byte offsets with word counts during burst transfers, causing corrupted memory chunks.
- [Medium] Applying Option ROM (Flash) bounds to MPI RAM addresses causes spurious rejections and truncated transfers.
--

commit b9c1c98154245d3fd8c709eb1527874ff55f8c3a
Author: Manish Rangankar <mrangankar@marvell.com>

scsi: qla2xxx: Add BSG MPI firmware load/dump for 29xx

Add BSG vendor commands for loading and dumping MPI firmware on
29xx adapters. This extends the existing BSG infrastructure with
the necessary mailbox wrappers and flash helpers for MPI
operations.

> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index 0baf486e8fb89..92a0bc6dc7bcd 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -1756,6 +1756,153 @@ static int qla29xx_bsg_flash_block_write(struct bsg_job *bsg_job)
>  	return 0;
>  }
>  
> +static int qla2900_bsg_dump_mpi(struct bsg_job *bsg_job)
> +{
[ ... ]
> +	mutex_lock(&ha->optrom_mutex);
> +	rval = qla2x00_optrom_setup(bsg_job, vha, dmcmd->mpi_address, 1);

[Severity: Medium]
Will this correctly validate the MPI RAM boundaries? It looks like
qla2x00_optrom_setup() validates the start parameter against ha->optrom_size,
which is the physical size of the flash chip, not the MPI RAM size. Could
this falsely reject or truncate valid MPI RAM addresses if they exceed the
flash size limits?

> +	if (rval) {
> +		mutex_unlock(&ha->optrom_mutex);
> +		return rval;
> +	}
> +
> +	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
> +			  bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
> +			  ha->optrom_region_size);
[ ... ]
> +	rval = qla29xx_mpi_optrom_data(vha, opts, ha->optrom_buffer,
> +				       ha->optrom_region_start,
> +				       ha->optrom_region_size,
> +				       QLA29XX_MPI_OP_DUMP);

[Severity: High]
Are the semantics of DUMP and LOAD reversed here? The function is named
qla2900_bsg_dump_mpi(), but it copies data from the user's request_payload
and passes QLA29XX_MPI_OP_DUMP, which acts as a Write operation to the
device. Usually, dumping firmware implies reading it from the device into a
buffer.

[ ... ]
> +static int qla2900_bsg_load_mpi(struct bsg_job *bsg_job)
> +{
[ ... ]
> +	mutex_lock(&ha->optrom_mutex);
> +	rval = qla2x00_optrom_setup(bsg_job, vha, lmcmd->mpi_address, 0);

[Severity: Medium]
Similar to qla2900_bsg_dump_mpi(), this passes lmcmd->mpi_address to
qla2x00_optrom_setup(). Could this result in the transfer being silently
truncated if the requested MPI RAM address space differs from the flash
size constraints?

> +	if (rval) {
[ ... ]
> +	rval = qla29xx_mpi_optrom_data(vha, opts, ha->optrom_buffer,
> +				       ha->optrom_region_start,
> +				       ha->optrom_region_size,
> +				       QLA29XX_MPI_OP_LOAD);
[ ... ]
> +	sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
> +			    bsg_job->reply_payload.sg_cnt,
> +			    ha->optrom_buffer,
> +			    ha->optrom_region_size);

[Severity: High]
This function is named qla2900_bsg_load_mpi(), but it appears to be reading
data from the device into the reply_payload (a Read operation). Standard
firmware conventions typically define LOAD as sending data to the device.
Could invoking these commands overwrite the adapter's MPI RAM with
uninitialized data due to the reversed directions?

> diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
> index 1d5ea5e432edc..af7509083910d 100644
> --- a/drivers/scsi/qla2xxx/qla_sup.c
> +++ b/drivers/scsi/qla2xxx/qla_sup.c
> @@ -527,6 +527,123 @@ qla29xx_read_optrom_data(struct scsi_qla_host *vha, uint16_t reg_code,
[ ... ]
> +int
> +qla29xx_mpi_optrom_data(struct scsi_qla_host *vha, uint16_t opts, void *buf,
> +		       uint32_t offset, uint32_t length, enum qla29xx_mpi_optrom_op op)
> +{
[ ... ]
> +	mpi_addr = offset;
> +	dcode = (uint32_t *)optrom;
> +	memset(dcode, 0, OPTROM_BURST_SIZE);
> +
> +	fwcode = (uint32_t *)buf;
> +	mpi_size = length >> 2;
> +	burst = OPTROM_BURST_SIZE >> 2;
> +	total_chunks = (mpi_size + burst - 1) / burst;
> +
> +	while (mpi_size > 0) {
[ ... ]
> +		chunk_count++;
> +		fwcode += burst;
> +		mpi_addr += burst;
> +		mpi_size -= burst;
> +	}

[Severity: High]
Does this loop mix byte offsets with word counts? It looks like mpi_addr is
initialized to offset (a byte address from the user parameter), but it is
advanced by burst. Since burst is calculated as OPTROM_BURST_SIZE >> 2
(a count of 32-bit words), mpi_addr will only advance by a quarter of the
intended byte distance each iteration. Will this cause successive transfers
to heavily overlap and corrupt the firmware load or dump?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=8

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 02/60] scsi: qla2xxx: Add flash read/write interface for 29xx
  2026-06-12  9:52 ` [PATCH v2 02/60] scsi: qla2xxx: Add flash read/write interface for 29xx Nilesh Javali
@ 2026-06-12 10:16   ` sashiko-bot
  2026-06-12 10:43   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:16 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] FLT version check is bypassed due to incorrect logical operator and signature constant.
- [High] Flash layout parsing iterates over regions using a fixed struct size instead of the firmware-provided `region_size`.
- [High] Unprotected concurrent modification of `ha->flt_data` during ISP abort can cause out-of-bounds reads in sysfs/BSG handlers.
--

commit 406f516c2c12956321654662c33a7512be63f8be
Author: Manish Rangankar <mrangankar@marvell.com>

scsi: qla2xxx: Add flash read/write interface for 29xx

The 29xx series uses a different flash access mechanism than
earlier adapters. Add the mailbox wrappers and qla_sup helpers
needed for flash read and write operations, including the
necessary hooks in isp_ops so that the existing flash
infrastructure can drive the new hardware.

> diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
> index b6c36a8a2d60b..eb10904f14caa 100644
> --- a/drivers/scsi/qla2xxx/qla_sup.c
> +++ b/drivers/scsi/qla2xxx/qla_sup.c
> @@ -10,6 +10,651 @@
>  #include <linux/vmalloc.h>
>  #include <linux/uaccess.h>
>  
> +/**
> + * qla29xx_get_flt_layout - Retrieve the flash layout table (FLT) for QLA29xx.
[ ... ]
> +static void
> +qla29xx_get_flt_layout(scsi_qla_host_t *vha)
> +{
> +	struct qla_hw_data *ha = vha->hw;
> +	struct qla_flash_layout *flt_layout = ha->flt_data;
> +	struct qla_flt_region_header *flt_header = &flt_layout->flt_header;
> +	struct qla_flt_region_data *region = &flt_layout->region[0];
> +	uint32_t flt_options = 0;
> +	uint32_t flt_size;
> +	uint32_t cnt, chksum;
> +	uint16_t reg_cnt, i;
> +	__le32 *wptr;
> +	void *buf = NULL;
> +
> +	flt_size = sizeof(struct qla_flt_region_header);
> +	wptr = (__force __le32 *)ha->flt_data;
> +
> +	buf = qla29xx_read_optrom_data(vha, FLT_REG_MINI_FLT, flt_options,
> +				       ha->flt_data, 0, flt_size);

[Severity: High]
Is ha->flt_data safe from concurrent modification here?

This function can be reached asynchronously via the DPC thread during an
ISP abort (qla2x00_do_dpc -> qla2x00_abort_isp -> qla2x00_setup_chip ->
qla2xxx_get_flash_info), and it unconditionally overwrites ha->flt_data
without acquiring ha->optrom_mutex.

Concurrently, a sysfs or BSG read request might execute
qla29xx_get_flash_region(), holding only ha->optrom_mutex. If this
overwrite happens at the same time, the reading thread could see a torn
or garbage region_count value (up to 65535). Since the flt_data array is
sized for 255 regions, the subsequent loop could read far past the
allocated buffer bounds.

> +	if (!buf) {
> +		ql_log(ql_log_warn, vha, 0x007b,
> +		    "Failed to read FLT information.\n");
> +		goto exit_flt;
> +	}
> +
> +	ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0111,
> +	       "Contents of Flash Layout (0x%x):\n", flt_size);
> +	ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0112,
> +		       ha->flt_data, flt_size);
> +
> +	/* check flt version checksum and other info */
> +	if ((le32_to_cpu(*wptr) == 0xffff) &&
> +	    flt_header->version != cpu_to_le32(FLT_HDR_VERSION)) {

[Severity: High]
Will this correctly catch corrupted or invalid FLT headers?

It looks like the logical && is used instead of ||, and the 32-bit
pointer is checked against 0xffff (which resolves to 0x0000ffff)
instead of 0xffffffff for an empty flash block.

Because both conditions must be true for the error to trigger, corrupted
or uninitialized flash data with an incorrect version but a first DWORD
other than 0x0000ffff might silently bypass this validation check. This
would allow the driver to parse garbage data as valid flash layout
regions.

> +		ql_log(ql_log_warn, vha, 0x007c,
[ ... ]
> +	ql_dbg(ql_dbg_init, vha, 0x007f,
> +		"FLT detected: version=0x%08x length=0x%08x signature=0x%08x region_count=0x%04x region_len=0x%04x segment_len=0x%08x checksum=0x%08x.\n",
> +		le32_to_cpu(flt_header->version),
> +		le32_to_cpu(flt_header->length),
> +		le32_to_cpu(flt_header->signature),
> +		le16_to_cpu(flt_header->region_count),
> +		le16_to_cpu(flt_header->region_size),
> +		le32_to_cpu(flt_header->segment_size),
> +		le32_to_cpu(flt_header->checksum));
> +
> +	for (i = 0; reg_cnt; i++, reg_cnt--) {
> +		region = &flt_layout->region[i];

[Severity: High]
Could this array indexing result in misaligned memory reads?

The total flash layout size is calculated dynamically using
le16_to_cpu(flt_header->region_size). However, standard C array indexing
(&flt_layout->region[i]) strides by the compile-time size of
struct qla_flt_region_data.

If the firmware provides a region_size that differs from
sizeof(struct qla_flt_region_data) due to padding or future extensions,
the pointer arithmetic will be misaligned, causing the driver to read
garbage memory for subsequent regions.

> +		ql_dbg(ql_dbg_init, vha, 0x0080,
[ ... ]
> +static int
> +qla29xx_get_flash_region(struct scsi_qla_host *vha, uint32_t code,
> +			 struct qla_flt_region_data *region)
> +{
> +	struct qla_hw_data *ha = vha->hw;
> +	struct qla_flash_layout *flt = ha->flt_data;
> +	struct qla_flt_region_header *flt_hdr = &flt->flt_header;
> +	struct qla_flt_region_data *flt_reg = &flt->region[0];
> +	uint16_t cnt;
> +	int rval = QLA_FUNCTION_FAILED;
> +
> +	if (!ha->flt_data || !ha->flags.valid_flt)
> +		return QLA_FUNCTION_FAILED;
> +
> +	cnt = le16_to_cpu(flt_hdr->region_count);
> +	for (; cnt; cnt--, flt_reg++) {

[Severity: High]
Does this loop also suffer from the same fixed-size stride issue as above?

Using flt_reg++ advances the pointer by sizeof(struct qla_flt_region_data)
rather than the dynamic region_size provided by the firmware. If those
sizes differ, this will misalign and read garbage memory.

> +		if (le16_to_cpu(flt_reg->region_code) == code) {
> +			memcpy((uint8_t *)region, flt_reg,
> +			    sizeof(struct qla_flt_region_data));
> +			rval = QLA_SUCCESS;
> +			break;
> +		}
> +	}
> +
> +	return rval;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=2

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 05/60] scsi: qla2xxx: Add 29xx support in queue initialisation path
  2026-06-12  9:52 ` [PATCH v2 05/60] scsi: qla2xxx: Add 29xx support in queue initialisation path Nilesh Javali
@ 2026-06-12 10:17   ` sashiko-bot
  2026-06-12 10:49   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:17 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Use-After-Free (UAF) in queue pair teardown due to missing work item cancellation.
--

commit a6fdb9faf346a1dfcb7285602fa98749fbabf7ba
Author: Manish Rangankar <mrangankar@marvell.com>

scsi: qla2xxx: Add 29xx support in queue initialisation path

This commit extends the queue initialization and management to include 29xx
adapters. It introduces support for 128-byte request and response entries by
adding new extended structures and adjusting pointer arithmetic and allocations.

> diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
> --- a/drivers/scsi/qla2xxx/qla_mid.c
> +++ b/drivers/scsi/qla2xxx/qla_mid.c

[ ... ]

> @@ -594,6 +598,10 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
>  {
>  	struct qla_hw_data *ha = vha->hw;
>  	uint16_t que_id = rsp->id;
> +	uint16_t rspsz;
> +
> +	rspsz = IS_QLA29XX(ha) ? sizeof(struct response_ext) :
> +				 sizeof(response_t);
>  
>  	if (rsp->msix && rsp->msix->have_irq) {
>  		free_irq(rsp->msix->vector, rsp->msix->handle);
> @@ -601,8 +609,9 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
>  		rsp->msix->in_use = 0;
>  		rsp->msix->handle = NULL;
>  	}

[Severity: High]
This is a pre-existing issue, but can this lead to a use-after-free when
tearing down the queue pair?

The q_work item is initialized in qla25xx_create_rsp_que() to process
responses. During teardown, qla2xxx_delete_qpair() calls
qla25xx_free_rsp_que(), which unregisters the interrupt using free_irq()
as seen here.

While free_irq() waits for running hardirq handlers, it does not flush or
cancel work items already placed on the workqueue.

After qla25xx_free_rsp_que() returns, qla2xxx_delete_qpair() immediately
frees the qpair structure:

qla2xxx_delete_qpair() {
    ...
    mempool_destroy(qpair->srb_mempool);
    kfree(qpair);
    mutex_unlock(&ha->mq_lock);
}

If qpair->q_work was pending, it will later execute qla_do_work(),
dereferencing the freed qpair pointer to access vha and lock
qpair->qp_lock:

qla_do_work() {
    struct qla_qpair *qpair = container_of(work, struct qla_qpair, q_work);
    struct scsi_qla_host *vha = qpair->vha;

    spin_lock_irqsave(&qpair->qp_lock, flags);
    ...
}

This seems especially problematic in full adapter teardown, where
destroy_workqueue(ha->wq) forces pending work to run right after the queue
pairs are freed. Should a cancel_work_sync(&qpair->q_work) be added?

> +
>  	dma_free_coherent(&ha->pdev->dev, (rsp->length + 1) *
> -		sizeof(response_t), rsp->ring, rsp->dma);
> +			  rspsz, rsp->ring, rsp->dma);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=5

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 04/60] scsi: qla2xxx: Add get_flash_version support for 29xx adapters
  2026-06-12  9:52 ` [PATCH v2 04/60] scsi: qla2xxx: Add get_flash_version " Nilesh Javali
@ 2026-06-12 10:18   ` sashiko-bot
  2026-06-12 10:48   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:18 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [Medium] Inconsistent fallback error handling logic and commit message mismatch in `qla24xx_get_flash_version()`.

Pre-existing issues:
- [High] Hardware flash registers are read/written via `qla24xx_read_flash_dword` without proper locking, creating a race condition with concurrent sysfs operations.
--

commit 94d10a85b890acf6bb363bf65b3e955e838a9522
Author: Manish Rangankar <mrangankar@marvell.com>

scsi: qla2xxx: Add get_flash_version support for 29xx adapters

This commit removes the standalone qla29xx_get_flash_version() and folds 
29xx support directly into qla24xx_get_flash_version(). It uses early 
metadata reads for 29xx firmware and modifies PCI expansion ROM reads.

>   - PCI expansion ROM reads (header + data structure): a new
>     file-static helper, qla24xx_read_pci_rom_chunk(), abstracts the
>     per-generation flash access so both read sites are straight-line
>     calls instead of inline if/else twin blocks.  29xx uses
>     qla29xx_read_optrom_data(FLT_REG_BOOT_CODE, byte-offset); 24xx
>     uses qla24xx_read_flash_data(dword-address).

The commit message mentions a new file-static helper,
qla24xx_read_pci_rom_chunk(), but this function does not appear in the code.
Is the commit message out of sync with the patch?

> diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
> index eb10904f14caa..2229c2b084cff 100644
> --- a/drivers/scsi/qla2xxx/qla_sup.c
> +++ b/drivers/scsi/qla2xxx/qla_sup.c
[ ... ]
> @@ -4137,7 +4108,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
>  		if (ret) {
>  			ql_log(ql_log_info, vha, 0x017d,
>  			    "Unable to read PCI EXP Rom Header(%x).\n", ret);
> -			return QLA_FUNCTION_FAILED;
> +			break;
>  		}

[Severity: High]
This is a pre-existing issue, but can qla24xx_read_flash_data() race with
concurrent sysfs operations?

Hardware flash registers are read/written via qla24xx_read_flash_dword()
without proper locking:

qla24xx_read_flash_dword() {
	wrt_reg_dword(&reg->flash_addr, addr & ~FARX_DATA_FLAG);
	while (cnt--) {
		if (rd_reg_dword(&reg->flash_addr) & FARX_DATA_FLAG) {
        ...
}

When invoked via the sysfs reset handler:

qla2x00_sysfs_write_reset() {
    ...
    ha->isp_ops->get_flash_version(vha, tmp_data);
    ...
}

It doesn't appear to hold ha->optrom_mutex or ha->hardware_lock. Could
concurrent calls interleave their register accesses and corrupt data?

[Severity: Medium]
When qla24xx_read_flash_data() fails, the code now uses break to fall through
and read the active firmware image version. However, signature validation
failures later in this loop still return QLA_FUNCTION_FAILED:

		bcode = mbuf + (pcihdr % 4);
		if (memcmp(bcode, "\x55\xaa", 2)) {
			/* No signature */
			ql_log(ql_log_fatal, vha, 0x0059,
			    "No matching ROM signature.\n");
			return QLA_FUNCTION_FAILED;
		}

If the flash read succeeds but contains invalid boot code, the function aborts
entirely and skips reading the firmware version, whereas a complete flash read
failure successfully falls through. Is this inconsistent fallback behavior
intentional?

>  
>  		bcode = mbuf + (pcihdr % 4);
> @@ -4155,7 +4126,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
>  		if (ret) {
>  			ql_log(ql_log_info, vha, 0x018e,
>  			    "Unable to read PCI Data Structure (%x).\n", ret);
> -			return QLA_FUNCTION_FAILED;
> +			break;
>  		}
>  
>  		bcode = mbuf + (pcihdr % 4);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=4

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 17/60] scsi: qla2xxx: Extend execute_fw mailbox to include 29xx
  2026-06-12  9:52 ` [PATCH v2 17/60] scsi: qla2xxx: Extend execute_fw mailbox to include 29xx Nilesh Javali
@ 2026-06-12 10:25   ` sashiko-bot
  2026-06-12 11:17   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:25 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Incomplete implementation of 128 Gbps link speed reporting and capability parsing.
--

commit 132584b87856488e93a0fd2c24a72b08430be770
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Extend execute_fw mailbox to include 29xx

Add IS_QLA29XX() to the BPM capability macros and to the
execute-firmware mailbox command so that NVMe enable, minimum
speed negotiation, 128 Gbps speed reporting, EDIF hardware
detection, and FW-semaphore retry logic all apply to 29xx
adapters.

[ ... ]

> diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
> index 2b57782b3cd34..e93766e814809 100644
> --- a/drivers/scsi/qla2xxx/qla_def.h
> +++ b/drivers/scsi/qla2xxx/qla_def.h
> @@ -4333,6 +4333,7 @@ struct qla_hw_data {
>  #define PORT_SPEED_16GB 0x05
>  #define PORT_SPEED_32GB 0x06
>  #define PORT_SPEED_64GB 0x07
> +#define PORT_SPEED_128GB 0x08

[Severity: Medium]
Will this new speed cause qla2x00_get_link_speed_str() and
qla2x00_port_speed_capability() to return unknown values for 128 Gbps links?

In drivers/scsi/qla2xxx/qla_isr.c:qla2x00_get_link_speed_str(), QLA_LAST_SPEED
is 8. Because PORT_SPEED_128GB is 8, the condition speed < QLA_LAST_SPEED
evaluates to false, causing the function to fall through to LS_UNKNOWN.

Consequently, the driver logs "LOOP UP detected (? Gbps)" instead of
reporting 128 Gbps.

In drivers/scsi/qla2xxx/qla_gs.c:qla2x00_port_speed_capability(), there is no
case for the FC-GS GPSC 128 Gbps bit (BIT_6).

Remote ports operating at 128 Gbps are mapped to PORT_SPEED_UNKNOWN, which may
prevent the driver from correctly adjusting iIDMA tuning parameters for
128 Gbps targets in qla2x00_set_idma_speed().

>  #define PORT_SPEED_10GB	0x13
>  	uint16_t	link_data_rate;         /* F/W operating speed */
>  	uint16_t	set_data_rate;		/* Set by user */

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=17

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 15/60] scsi: qla2xxx: Skip unsupported sysfs attributes for 29xx
  2026-06-12  9:52 ` [PATCH v2 15/60] scsi: qla2xxx: Skip unsupported sysfs attributes " Nilesh Javali
@ 2026-06-12 10:28   ` sashiko-bot
  2026-06-12 11:15   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:28 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Use-after-free of `ha->cs84xx` due to premature release in `qla2x00_remove_one`.
--

commit ace8a251663829b774dad26691a4ec0924aeadf0
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Skip unsupported sysfs attributes for 29xx

This commit updates several sysfs attribute show functions to return
-EPERM for the QLA29xx adapter. This prevents userspace tools from
seeing stale or undefined values for attributes that are meaningless
on this hardware.

> diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
> index 800751ab562a1..e8755ab86b6ac 100644
> --- a/drivers/scsi/qla2xxx/qla_attr.c
> +++ b/drivers/scsi/qla2xxx/qla_attr.c
> @@ -1499,6 +1502,9 @@ qla24xx_84xx_fw_version_show(struct device *dev,
>  	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
>  	struct qla_hw_data *ha = vha->hw;
>  
> +	if (IS_QLA29XX(ha))
> +		return -EPERM;
> +
>  	if (!IS_QLA84XX(ha))
>  		return scnprintf(buf, PAGE_SIZE, "\n");
>  
>  	if (!ha->cs84xx->op_fw_version) {

[Severity: High]
This isn't a bug introduced by this patch, but can this lead to a
use-after-free during driver teardown?

During driver teardown, qla2x00_remove_one() appears to drop the reference
to cs84xx and free it before the sysfs attributes are unregistered:

drivers/scsi/qla2xxx/qla_os.c:qla2x00_remove_one() {
    ...
    qla84xx_put_chip(base_vha);
    ...
    scsi_remove_host(base_vha->host);
    ...
}

If a user concurrently reads the 84xx_fw_version sysfs file during this window,
it executes qla24xx_84xx_fw_version_show() which unconditionally dereferences
the now-freed ha->cs84xx pointer:

drivers/scsi/qla2xxx/qla_attr.c:qla24xx_84xx_fw_version_show() {
    ...
    if (!ha->cs84xx->op_fw_version) {
    ...
}

Does this window between dropping the reference to ha->cs84xx and unregistering
the host sysfs attributes allow for a use-after-free?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=15

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 12/60] scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx
  2026-06-12  9:52 ` [PATCH v2 12/60] scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx Nilesh Javali
@ 2026-06-12 10:29   ` sashiko-bot
  2026-06-12 11:12   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:29 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Single-queue SCSI submission paths (`qla24xx_start_scsi` and `qla24xx_dif_start_scsi`) fail to format 128-byte extended IOCBs on 29xx adapters.
- [High] Target mode IOCB builders write 64-byte packets to the frozen `req->ring_ptr` on 29xx adapters.
- [High] T10-PI DIF bundling is unconditionally disabled on 29xx adapters in MQ mode.
--

commit 9d1c8cdada293dd8d2e57a08796bee646ebd3d4f
Author: Anil Gurumurthy <agurumurthy@marvell.com>
scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx
    
Wire the 128-byte extended IOCB structures into the IO submission,
completion, and queue-management paths. On 29xx adapters the driver
now builds cmd_type_6_ext / cmd_type_7_ext command IOCBs and processes
the corresponding extended status entries.

> diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
> index 948242f0088e7..c79c1cca0b7df 100644
> --- a/drivers/scsi/qla2xxx/qla_os.c
> +++ b/drivers/scsi/qla2xxx/qla_os.c
[ ... ]
> @@ -2693,6 +2697,7 @@ static struct isp_operations qla29xx_isp_ops = {
>  	.read_optrom_region	= qla29xx_read_optrom_data,
>  	.write_optrom_region	= qla29xx_write_optrom_data,
>  	.get_flash_version	= qla24xx_get_flash_version,
> +	.start_scsi		= qla24xx_dif_start_scsi,
>  	.start_scsi_mq		= qla2xxx_dif_start_scsi_mq,
>  	.abort_isp		= qla2x00_abort_isp,
>  	.iospace_config		= qla83xx_iospace_config,

[Severity: High]
Does this legacy 24xx function handle the 128-byte extended IOCBs for 29xx?

If MQ is disabled, 29xx adapters fallback to the single-queue handlers like
qla24xx_start_scsi() and qla24xx_dif_start_scsi() registered here. 

Looking at qla24xx_start_scsi(), it seems to only zero the first 56 bytes:

	cmd_pkt = (struct cmd_type_7 *)qla_req_ring_slot(ha, req);
	cmd_pkt->handle = make_handle(req->id, handle);

	/* Zero out remaining portion of packet. */
	/*    tagged queuing modifier -- default is TSK_SIMPLE (0). */
	clr_ptr = (uint32_t *)cmd_pkt + 2;
	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);

Could this leave the latter 64 bytes of the slot (which contain extended
inline DSDs on 29xx) entirely uninitialized, leading the firmware to fetch
and parse uninitialized memory as DMA descriptors?

> diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
> index e47da45e93a01..fd8abdc36a56f 100644
> --- a/drivers/scsi/qla2xxx/qla_target.c
> +++ b/drivers/scsi/qla2xxx/qla_target.c
[ ... ]
> @@ -2605,6 +2601,7 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm)
>  	while (prm->seg_cnt > 0) {
>  		cont_a64_entry_t *cont_pkt64 =
>  			(cont_a64_entry_t *)qlt_get_req_pkt(
> +			   prm->cmd->qpair->vha->hw,
>  			   prm->cmd->qpair->req);
>  
>  		/*

[Severity: High]
Can the target mode IOCB builders properly initialize the 128-byte slot?

In qlt_load_cont_data_segments(), the slot is cast to the legacy 64-byte
cont_a64_entry_t structure. This results in only 64 bytes being zeroed
out, leaving the remaining 64 bytes of the 29xx extended continuation IOCB
uninitialized.

Additionally, in qlt_24xx_build_ctio_pkt() and qlt_build_ctio_crc2_pkt(),
the code writes to req->ring_ptr directly instead of using
qla_req_ring_slot(). Since qla_req_ring_advance() only advances ring_ext_ptr
on 29xx and leaves ring_ptr frozen at index 0, could this continually overwrite
the 0th index of the request ring buffer instead of the active slot?

> diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
> index dbe3cd4e274c8..048942986231a 100644
> --- a/drivers/scsi/qla2xxx/qla_iocb.c
> +++ b/drivers/scsi/qla2xxx/qla_iocb.c
[ ... ]
> @@ -2231,29 +2337,41 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp)
>  	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
>  
>  	/* Build IOCB segments and adjust for data protection segments */
> -	if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *)
> -	    req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) !=
> -		QLA_SUCCESS)
> -		goto queuing_error;
> +	if (IS_QLA29XX(ha)) {
> +		struct cmd_type_crc_2_ext *cmd_pkt_ext =
> +			(struct cmd_type_crc_2_ext *)cmd_pkt;
> +
> +		cmd_pkt_ext->vp_index = cpu_to_le16(sp->vha->vp_idx);
> +
> +		if (qla29xx_build_scsi_crc_2_iocbs(sp, cmd_pkt_ext, tot_dsds,
> +						   tot_prot_dsds,
> +						   fw_prot_opts, 0) !=
> +		    QLA_SUCCESS)
> +			goto queuing_error;

[Severity: High]
Is there a reason the bundling parameter is hardcoded to 0 here?

The 24xx path calculates bundling dynamically based on the SCSI protection
operation, but here for 29xx it is unconditionally 0. This prevents the
29xx extended builder from setting up PO_ENABLE_DIF_BUNDLING.

Will this cause the firmware to use the wrong DSD layout and fail the I/O
or corrupt T10-PI protection data for SCSI operations that require
interleaved protection data?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=12

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 01/60] scsi: qla2xxx: Add 29xx series PCI device ID support
  2026-06-12  9:52 ` [PATCH v2 01/60] scsi: qla2xxx: Add 29xx series PCI device ID support Nilesh Javali
@ 2026-06-12 10:30   ` sashiko-bot
  2026-06-12 10:40   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:30 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [Critical] Out-of-bounds write during firmware dump due to undersized buffer allocation

Pre-existing issues:
- [High] Integer truncation and underflow of `max_req_queues` leading to zero-sized allocation and kernel panic
--

commit 3a7611054d56fb889d96ec52acc8efac418ed86d
Author: Manish Rangankar <mrangankar@marvell.com>
Subject: scsi: qla2xxx: Add 29xx series PCI device ID support

This commit introduces support for the QLA29xx series of Fibre Channel HBAs.
It registers the new PCI device IDs and adds IS_QLA29XX() capability checks
across the driver to handle initialization, MSI-X setup, and other hardware
specifics.

> --- a/drivers/scsi/qla2xxx/qla_init.c
> +++ b/drivers/scsi/qla2xxx/qla_init.c
> @@ -2773,7 +2773,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
>  	ha->isp_ops->reset_chip(vha);
>  
>  	/* Check for secure flash support */
> -	if (IS_QLA28XX(ha)) {
> +	if (IS_QLA28XX(ha) || IS_QLA29XX(ha)) {

[Severity: Critical]
Is it possible that the new IS_QLA29XX() check is missing in
qla2x00_alloc_fw_dump()? 

In qla2x00_alloc_fw_dump() within drivers/scsi/qla2xxx/qla_init.c, the driver
dynamically calculates the firmware dump buffer size for 27xx and 28xx
adapters:

	if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
		/* dynamic size calculation */
	}

Without the IS_QLA29XX() check, the driver falls back to a hardcoded legacy
formula, which allocates an undersized buffer. Later, when a firmware dump
is triggered (e.g., from a RISC pause), qla27xx_fwdump() blindly writes to
this buffer via qla27xx_insert32() in drivers/scsi/qla2xxx/qla_tmpl.c:

	buf += *len;
	*(__le32 *)buf = cpu_to_le32(value);

Will this result in an out-of-bounds write and kernel memory corruption since
the 29xx firmware template requires significantly more space?

>  		if (rd_reg_word(&reg->mailbox12) & BIT_0)
>  			ha->flags.secure_adapter = 1;

[ ... ]

> --- a/drivers/scsi/qla2xxx/qla_os.c
> +++ b/drivers/scsi/qla2xxx/qla_os.c
[ ... ]
> @@ -2203,10 +2202,18 @@ qla83xx_iospace_config(struct qla_hw_data *ha)
>  	ha->msixbase = ioremap(pci_resource_start(ha->pdev, 2),
>  			pci_resource_len(ha->pdev, 2));
>  	if (ha->msixbase) {
> +		int msix_cnt;
> +
>  		/* Read MSIX vector size of the board */
> -		pci_read_config_word(ha->pdev,
> -		    QLA_83XX_PCI_MSIX_CONTROL, &msix);
> -		ha->msix_count = (msix & PCI_MSIX_FLAGS_QSIZE)  + 1;
> +		msix_cnt = pci_msix_vec_count(ha->pdev);
> +		if (msix_cnt <= 0) {
> +			ql_log_pci(ql_log_warn, ha->pdev, 0x0120,
> +				   "Failed to read MSI-X count (%d), falling back to base vectors.\n",
> +				   msix_cnt);
> +			goto mqiobase_exit;
> +		}
> +		ha->msix_count = msix_cnt;

[Severity: High]
This is a pre-existing issue, but does assigning msix_cnt to ha->msix_count
expose us to a truncation bug if the device advertises 257 vectors?

The ha->max_req_queues field is defined as an 8-bit unsigned integer
(uint8_t) in struct qla_hw_data in drivers/scsi/qla2xxx/qla_def.h. Later in
qla83xx_iospace_config(), we do:

	ha->max_req_queues = ha->msix_count - 1;

If the device advertises exactly 257 MSI-X vectors, msix_count - 1 evaluates
to 256, which truncates to 0 in the 8-bit max_req_queues. (It would also
underflow to 0 if the MSI-X count is 1).

Subsequently, qla2x00_alloc_queues() uses this truncated value:

	ha->req_q_map = kzalloc_objs(struct req_que *, ha->max_req_queues);

Passing 0 to kzalloc_objs() returns the ZERO_SIZE_PTR. The driver then
dereferences it:

	ha->req_q_map[0] = req;

Could this lead to a kernel panic when a misconfigured or malicious
hot-plugged PCIe device provides these vector counts?

> +
>  		/*
>  		 * By default, driver uses at least two msix vectors
>  		 * (default & rspq)

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=1

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 16/60] scsi: qla2xxx: Enable get_fw_version mailbox for 29xx
  2026-06-12  9:52 ` [PATCH v2 16/60] scsi: qla2xxx: Enable get_fw_version mailbox " Nilesh Javali
@ 2026-06-12 10:31   ` sashiko-bot
  2026-06-12 11:16   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:31 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The `fw_attr` sysfs attribute is not exposed for 29xx adapters due to a missing IS_QLA29XX check.
--

commit 87a8bb4cf363158a780d18c48d9c990e59d3d1aa
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Enable get_fw_version mailbox for 29xx

The serdes_version and several firmware capability fields were not
populated for 29xx because the get_fw_version mailbox path
excluded it from the 27xx/28xx checks.  Add IS_QLA29XX() to
the relevant conditionals so that firmware version, EDIF, and
serdes information are correctly retrieved on 29xx adapters.

> diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
> --- a/drivers/scsi/qla2xxx/qla_attr.c
> +++ b/drivers/scsi/qla2xxx/qla_attr.c
> @@ -1526,7 +1526,7 @@ qla2x00_serdes_version_show(struct device *dev, struct device_attribute *attr,
>  	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
>  	struct qla_hw_data *ha = vha->hw;
>  
> -	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
> +	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
>  		return scnprintf(buf, PAGE_SIZE, "\n");

[Severity: Medium]
Since this sysfs attribute export is updated to include 29xx, should
qla2x00_fw_attr_show() be updated as well?

It looks like qla2x00_fw_attr_show() still has a hardcoded check that
will hide the fw_attr sysfs attribute for 29xx adapters:

drivers/scsi/qla2xxx/qla_attr.c:qla2x00_fw_attr_show() {
	...
	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
		return scnprintf(buf, PAGE_SIZE, "\n");
	...
}

I noticed that similar omissions for mpi_version and pep_version were fixed by
subsequent patches later in the series, but it appears the fix for fw_attr was
missed and it remains broken at the end of the series.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=16

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 21/60] scsi: qla2xxx: Enable serdes, resource count and FCE trace for 29xx
  2026-06-12  9:52 ` [PATCH v2 21/60] scsi: qla2xxx: Enable serdes, resource count and FCE trace " Nilesh Javali
@ 2026-06-12 10:38   ` sashiko-bot
  2026-06-12 11:19   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:38 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

Pre-existing issues:
- [High] Calling kstrtoul(buf, 0, 0) passes a NULL pointer for the result, which unconditionally causes a kernel panic upon successful string parsing.
- [High] qla2x00_alloc_fw_dump() lacks an IS_QLA29XX check when deciding whether to size the fw_dump buffer using FWDT, leading to legacy fixed-size allocations that are too small.
- [High] Enabling FCE trace dynamically via debugfs does not resize the pre-allocated firmware dump buffer, leading to an out-of-bounds write of 64KB (FCE_SIZE) during a firmware dump.
- [High] A race condition between disabling the FCE trace via debugfs and a concurrent firmware dump leads to a Use-After-Free of the DMA-allocated FCE trace buffer.
--

commit f8a1650862943af8f27bc3e84bb79567498967d8
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Enable serdes, resource count and FCE trace for 29xx
    
The 29xx adapters share the diagnostic and management interfaces
already supported on ISP27xx/28xx, but several family capability
gates still omitted IS_QLA29XX(), leaving these paths unreachable
on 29xx.

[ ... ]

> diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
> index 43970caca7b39..177d47e92e494 100644
> --- a/drivers/scsi/qla2xxx/qla_dfs.c
> +++ b/drivers/scsi/qla2xxx/qla_dfs.c
> @@ -497,7 +497,7 @@ qla2x00_dfs_fce_write(struct file *file, const char __user *buffer,
>  	unsigned long enable;
>  
>  	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
> -	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) {
> +	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha)) {

[Severity: High]
This isn't a bug introduced by this patch, but exposing this interface to 29xx
adapters makes it relevant here. Looking further down in qla2x00_dfs_fce_write(),
there is a call to kstrtoul():

    enable = kstrtoul(buf, 0, 0);
    rc = count;

Does passing a NULL pointer as the third argument to kstrtoul() cause a kernel
crash when parsing succeeds? Additionally, since kstrtoul() returns a status
code (0 on success, negative on failure), does assigning its return value
directly to the boolean enable flag cause inverse logic where writing a valid
number skips FCE enablement?

[Severity: High]
This is a pre-existing issue, but since 29xx adapters are now enabling FCE and
fw dump features, should IS_QLA29XX be added to the sizing check in
qla2x00_alloc_fw_dump()?

Currently, the check only includes IS_QLA27XX and IS_QLA28XX:

    if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
        struct fwdt *fwdt = ha->fwdt;

If a 29xx adapter falls through this check, it defaults to legacy fixed-size
allocations that are too small. When qla27xx_fwdump() later executes the FWDT
templates for QLA29XX, could this write past the end of the undersized buffer?

[Severity: High]
This is a pre-existing issue, but exposing FCE trace dynamically via debugfs
highlights it. When qla2x00_dfs_fce_write() enables FCE, it attempts to resize
the firmware dump buffer to account for the new 64KB FCE trace:

    if (!ha->flags.fce_dump_buf_alloced)
        qla2x00_alloc_fw_dump(vha);

However, if ha->fw_dump is already allocated, qla2x00_alloc_fw_dump() returns
immediately without expanding the buffer.

Later, if a firmware dump occurs, qla27xx_fwdt_entry_t264() sees ha->fce is not
NULL and unconditionally copies FCE_SIZE (64KB) bytes into the dump buffer.
Can this result in an out-of-bounds write since the buffer was never actually
enlarged?

[Severity: High]
This is a pre-existing issue, but could disabling the FCE trace via this
debugfs node race with a concurrent firmware dump?

When FCE is disabled in qla2x00_dfs_fce_write(), qla2x00_free_fce_trace()
frees the DMA memory and sets ha->fce to NULL under ha->fce_mutex, but
without holding ha->hardware_lock.

Conversely, the firmware dump routines (like qla27xx_fwdt_entry_t264)
execute under ha->hardware_lock and read from ha->fce without acquiring
ha->fce_mutex.

Could this race allow the FCE buffer to be freed after the dump routine
verifies the pointer but before the memcpy completes, leading to a
use-after-free?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=21

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 26/60] scsi: qla2xxx: Add support for QLA29XX in memory allocation
  2026-06-12  9:52 ` [PATCH v2 26/60] scsi: qla2xxx: Add support for QLA29XX in memory allocation Nilesh Javali
@ 2026-06-12 10:40   ` sashiko-bot
  2026-06-12 11:22   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:40 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Double frees and NULL pointer dereferences occur on `qla2x00_mem_alloc` error paths because freed pointers are not set to NULL.
--

commit ec7e8420d4fa55d2851ed0f0ca2bc56ab9339db8
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Add support for QLA29XX in memory allocation

This commit enhances qla2x00_mem_alloc to support QLA29XX adapters. It modifies
the conditions for memory allocation and cleanup, ensuring proper handling of
the new adapter series alongside existing QLA27XX and QLA28XX checks.

> diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
> index a3e2c0a95a99b..3ac48eeb9f698 100644
> --- a/drivers/scsi/qla2xxx/qla_os.c
> +++ b/drivers/scsi/qla2xxx/qla_os.c
[ ... ]
> @@ -4681,12 +4683,12 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
>  	}
>  
>  fail_dif_bundl_dma_pool:
> -	if (IS_QLA82XX(ha) || ql2xenabledif) {
> +	if (IS_QLA82XX(ha) || IS_QLA29XX(ha) || ql2xenabledif) {
>  		dma_pool_destroy(ha->fcp_cmnd_dma_pool);
>  		ha->fcp_cmnd_dma_pool = NULL;
>  	}
>  fail_dl_dma_pool:
> -	if (IS_QLA82XX(ha) || ql2xenabledif) {
> +	if (IS_QLA82XX(ha) || IS_QLA29XX(ha) || ql2xenabledif) {
>  		dma_pool_destroy(ha->dl_dma_pool);
>  		ha->dl_dma_pool = NULL;
>  	}

[Severity: High]
This is a pre-existing issue, but does the error path in qla2x00_mem_alloc()
lead to double-frees and NULL pointer dereferences?

When qla2x00_mem_alloc() fails during late allocation stages (e.g., at
fail_lsrjt or fail_async_pd), it frees adapter members like ha->elsrej.c or
ha->async_pd but leaves the pointers non-NULL. The function returns -ENOMEM,
and the caller qla2x00_probe_one() handles this by branching to
probe_hw_failed, which unconditionally calls qla2x00_mem_free(ha).

Because the pointers were not zeroed out, qla2x00_mem_free(ha) evaluates them
as valid and attempts to free them again, resulting in a systemic double-free.

Additionally, fail_s_dma_pool destroys and correctly NULLs ha->s_dma_pool.
When qla2x00_mem_free(ha) later evaluates the dangling ha->async_pd as true,
it calls dma_pool_free(ha->s_dma_pool, ...) with a NULL pool pointer, which
will cause an immediate kernel panic when the allocator lock is dereferenced:

qla2x00_mem_free() {
	...
	if (ha->async_pd)
		dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma);
	...
}

Should the error labels in qla2x00_mem_alloc() that free resources be updated
to also set their corresponding pointers to NULL?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=26

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 01/60] scsi: qla2xxx: Add 29xx series PCI device ID support
  2026-06-12  9:52 ` [PATCH v2 01/60] scsi: qla2xxx: Add 29xx series PCI device ID support Nilesh Javali
  2026-06-12 10:30   ` sashiko-bot
@ 2026-06-12 10:40   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 10:40 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Manish Rangankar <mrangankar@marvell.com>
> 
> The QLA29xx is a new generation FC HBA that shares much of its
> architecture with the 27xx/28xx family.  Register the new PCI
> device IDs, wire up IS_QLA29XX() capability checks in the probe
> and ISP-flags paths, and extend speed-capability logic so the
> driver correctly recognises and initialises 29xx adapters.
> 
> Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_def.h  | 33 +++++++++++----
>   drivers/scsi/qla2xxx/qla_init.c |  2 +-
>   drivers/scsi/qla2xxx/qla_isr.c  |  5 ++-
>   drivers/scsi/qla2xxx/qla_os.c   | 74 ++++++++++++++++++++++++++-------
>   4 files changed, 88 insertions(+), 26 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 25/60] scsi: qla2xxx: Use ring-slot helpers in __qla2x00_alloc_iocbs
  2026-06-12  9:52 ` [PATCH v2 25/60] scsi: qla2xxx: Use ring-slot helpers in __qla2x00_alloc_iocbs Nilesh Javali
@ 2026-06-12 10:41   ` sashiko-bot
  2026-06-12 11:21   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:41 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Standard `memset()` is used on an `__iomem` mapped request ring pointer for QLAFX00 adapters, which can cause unaligned access faults or bus errors on architectures like ARM64.
--

commit 9791936eaf3c9274e9174a4c671ecce5a7c3c126
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Use ring-slot helpers in __qla2x00_alloc_iocbs

This commit refactors __qla2x00_alloc_iocbs() to use qla_req_ring_slot() and
qla_req_entry_size() helpers instead of open-coding the ring pointer selection
and entry size based on the adapter type.

> diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
> index d16570a6a0724..e2b64029a5743 100644
> --- a/drivers/scsi/qla2xxx/qla_iocb.c
> +++ b/drivers/scsi/qla2xxx/qla_iocb.c
[ ... ]
> @@ -2469,13 +2468,8 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp)
>  	 * layout-compatible once we return the pkt as request_t *.
>  	 */
>  	req->cnt -= req_cnt;
> -	if (IS_QLA29XX(ha)) {
> -		pkt = (request_t *)req->ring_ext_ptr;
> -		memset(pkt, 0, REQUEST_ENTRY_SIZE_EXT);
> -	} else {
> -		pkt = req->ring_ptr;
> -		memset(pkt, 0, REQUEST_ENTRY_SIZE);
> -	}
> +	pkt = qla_req_ring_slot(ha, req);
> +	memset(pkt, 0, qla_req_entry_size(ha));
>  	if (IS_QLAFX00(ha)) {
>  		wrt_reg_byte((u8 __force __iomem *)&pkt->entry_count, req_cnt);

[Severity: High]
This is a pre-existing issue, but does using standard memset() on the request
ring slot pointer cause problems for QLAFX00 adapters?

For QLAFX00 adapters, req->ring is mapped I/O memory, which is why the
register-mapped writes below require __iomem casts. On architectures like
ARM64, calling standard memset() directly on device memory can utilize
unaligned or optimized instructions that are invalid for I/O memory, leading
to a synchronous external abort and a kernel panic. 

Should this be using an I/O specific memset, or could the memset be
skipped entirely for QLAFX00 device memory?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=25

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 02/60] scsi: qla2xxx: Add flash read/write interface for 29xx
  2026-06-12  9:52 ` [PATCH v2 02/60] scsi: qla2xxx: Add flash read/write interface for 29xx Nilesh Javali
  2026-06-12 10:16   ` sashiko-bot
@ 2026-06-12 10:43   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 10:43 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Manish Rangankar <mrangankar@marvell.com>
> 
> The 29xx series uses a different flash access mechanism than
> earlier adapters.  Add the mailbox wrappers and qla_sup helpers
> needed for flash read and write operations, including the
> necessary hooks in isp_ops so that the existing flash
> infrastructure can drive the new hardware.
> 
> Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_def.h |  20 +
>   drivers/scsi/qla2xxx/qla_fw.h  |  54 +++
>   drivers/scsi/qla2xxx/qla_gbl.h |  15 +-
>   drivers/scsi/qla2xxx/qla_mbx.c | 144 +++++++
>   drivers/scsi/qla2xxx/qla_os.c  |  18 +-
>   drivers/scsi/qla2xxx/qla_sup.c | 661 ++++++++++++++++++++++++++++++++-
>   6 files changed, 905 insertions(+), 7 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 29/60] scsi: qla2xxx: Update handling of status entries for 29xx series
  2026-06-12  9:53 ` [PATCH v2 29/60] scsi: qla2xxx: Update handling of status entries for 29xx series Nilesh Javali
@ 2026-06-12 10:44   ` sashiko-bot
  2026-06-12 12:12   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:44 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] An attacker-controlled target can cause an integer underflow in `par_sense_len` resulting in an out-of-bounds read of adjacent kernel heap/DMA ring memory, leaking it to user-space.
--

commit f656a1805f0e016da73a51f8736cdf5930510fd1
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Update handling of status entries for 29xx series

This commit modifies the handling of status entries in the qla2xxx driver to
accommodate the extended structure for the 29xx series. It updates function
signatures to accept generic pointers and adjusts logic to differentiate
between standard and extended status entries.

> diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
> index c18ee2459f5bd..f81cf70a0542c 100644
> --- a/drivers/scsi/qla2xxx/qla_isr.c
> +++ b/drivers/scsi/qla2xxx/qla_isr.c

[ ... ]

> @@ -3480,20 +3505,20 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
>  	sense_len = par_sense_len = rsp_info_len = resid_len =
>  	    fw_resid_len = 0;
>  	if (IS_FWI2_CAPABLE(ha)) {
> +		qla_sts_fwi2_extract(ha, pkt, &sf);
>  		if (scsi_status & SS_SENSE_LEN_VALID)
> -			sense_len = le32_to_cpu(sts24->sense_len);
> +			sense_len = sf.sense_len;
>  		if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
> -			rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
> +			rsp_info_len = sf.rsp_data_len;

[Severity: High]
This is a pre-existing issue, but can an attacker-controlled target cause an
integer underflow here?

If a compromised target provides an rsp_info_len (via sf.rsp_data_len)
larger than the actual data buffer size (par_sense_len, initialized to 28
or 60), the subtraction later in qla2x00_status_entry():

    if (IS_FWI2_CAPABLE(ha)) {
        sense_data += rsp_info_len;
        par_sense_len -= rsp_info_len;
    }

will underflow par_sense_len to a massive positive value.

Subsequently, when qla2x00_handle_sense() is called, the length check:

    if (sense_len > par_sense_len)
        sense_len = par_sense_len;

fails to cap sense_len, allowing the following memcpy:

    memcpy(cp->sense_buffer, sense_data, sense_len);

to read out-of-bounds adjacent kernel heap or DMA ring memory, leaking it
into the SCSI command's sense buffer.

>  		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
> -			resid_len = le32_to_cpu(sts24->rsp_residual_count);
> +			resid_len = sf.rsp_residual_count;
>  		if (comp_status == CS_DATA_UNDERRUN)
>  			fw_resid_len = le32_to_cpu(sts24->residual_len);
> -		rsp_info = sts24->data;
> -		sense_data = sts24->data;
> -		host_to_fcp_swap(sts24->data, sizeof(sts24->data));
> +		rsp_info = sf.data;
> +		sense_data = sf.data;
> +		par_sense_len = sf.data_sz;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=29

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 03/60] scsi: qla2xxx: Add NVRAM config support for 29xx adapters
  2026-06-12  9:52 ` [PATCH v2 03/60] scsi: qla2xxx: Add NVRAM config support for 29xx adapters Nilesh Javali
@ 2026-06-12 10:46   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 10:46 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Manish Rangankar <mrangankar@marvell.com>
> 
> Extend the NVRAM read and configuration-apply paths to handle the
> 29xx series.  The 29xx NVRAM layout is similar to the 81xx family,
> so reuse the existing nvram_81xx parsing while adding
> 29xx-specific fields and init-sequence integration.
> 
> Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_def.h  |   1 +
>   drivers/scsi/qla2xxx/qla_fw.h   |  42 ++++++++++-
>   drivers/scsi/qla2xxx/qla_init.c | 123 +++++++++++++++++++++++++-------
>   drivers/scsi/qla2xxx/qla_os.c   |   2 +
>   4 files changed, 141 insertions(+), 27 deletions(-)
> 
[ .. ]
> @@ -9386,7 +9449,10 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
>   		nv->login_timeout = cpu_to_le16(0);
>   		nv->firmware_options_1 =
>   		    cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
> -		nv->firmware_options_2 = cpu_to_le32(2 << 4);
> +		if (IS_QLA29XX(ha))
> +			nv->firmware_options_2 = cpu_to_le32(1 << 4);
> +		else
> +			nv->firmware_options_2 = cpu_to_le32(2 << 4);

Please use 'BIT()' notation to be consistent with the previous lines.

Otherwise looks okay.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 04/60] scsi: qla2xxx: Add get_flash_version support for 29xx adapters
  2026-06-12  9:52 ` [PATCH v2 04/60] scsi: qla2xxx: Add get_flash_version " Nilesh Javali
  2026-06-12 10:18   ` sashiko-bot
@ 2026-06-12 10:48   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 10:48 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Manish Rangankar <mrangankar@marvell.com>
> 
> Remove the standalone qla29xx_get_flash_version() and fold 29xx
> support directly into qla24xx_get_flash_version():
> 
>    - Firmware version: 29xx reads version metadata from the FLT region
>      via qla29xx_get_flash_region(FLT_REG_FW) rather than parsing the
>      flash image; an early return skips the legacy firmware-image read.
> 
>    - PCI expansion ROM reads (header + data structure): a new
>      file-static helper, qla24xx_read_pci_rom_chunk(), abstracts the
>      per-generation flash access so both read sites are straight-line
>      calls instead of inline if/else twin blocks.  29xx uses
>      qla29xx_read_optrom_data(FLT_REG_BOOT_CODE, byte-offset); 24xx
>      uses qla24xx_read_flash_data(dword-address).
> 
> Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_sup.c | 235 +++++++++++++++------------------
>   1 file changed, 103 insertions(+), 132 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
> index eb10904f14ca..2229c2b084cf 100644
> --- a/drivers/scsi/qla2xxx/qla_sup.c
> +++ b/drivers/scsi/qla2xxx/qla_sup.c
> @@ -527,134 +527,6 @@ qla29xx_read_optrom_data(struct scsi_qla_host *vha, uint16_t reg_code,
>   	return NULL;
>   }
>   
> -/**
> - * qla29xx_get_flash_version - Retrieve flash version information for QLA29xx adapters.
> - * @vha: Pointer to SCSI QLogic host structure.
> - * @mbuf: Buffer to store the flash version information.
> - *
> - * This function retrieves the flash version information for QLA29xx adapters.
> - * It initializes the version fields and prepares for future flash read logic.
> - *
> - * Returns QLA_SUCCESS on success or QLA_FUNCTION_FAILED on failure.
> - */
> -int
> -qla29xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
> -{

You just added this function in patch 2, and now you move it again.
Please consider merging these two patches.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 05/60] scsi: qla2xxx: Add 29xx support in queue initialisation path
  2026-06-12  9:52 ` [PATCH v2 05/60] scsi: qla2xxx: Add 29xx support in queue initialisation path Nilesh Javali
  2026-06-12 10:17   ` sashiko-bot
@ 2026-06-12 10:49   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 10:49 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Manish Rangankar <mrangankar@marvell.com>
> 
> Extend the queue initialisation and multi-queue management mailbox
> commands to include IS_QLA29XX() checks, following the same mailbox
> interface as 27xx/28xx.
> 
> Unlike earlier adapters that use 64-byte request/response ring entries
> (request_t / response_t), 29xx uses 128-byte entries.  Add struct
> request_ext and struct response_ext, which extend the legacy 64-byte
> layout with a 64-byte reserved area.  The first 64 bytes are
> layout-compatible with the legacy structures, so common header
> accesses remain valid.
> 
> The enlarged entry stride doubles the DMA ring memory allocated for
> both request and response queues on 29xx, and all ring pointer
> arithmetic must account for the wider entries (handled by later
> patches in this series).
> 
> Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_def.h | 30 ++++++++++++++++++++++++++++++
>   drivers/scsi/qla2xxx/qla_mbx.c | 20 +++++++++++++-------
>   drivers/scsi/qla2xxx/qla_mid.c | 25 +++++++++++++++++++++----
>   3 files changed, 64 insertions(+), 11 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 06/60] scsi: qla2xxx: Add FC operational firmware load for 29xx
  2026-06-12  9:52 ` [PATCH v2 06/60] scsi: qla2xxx: Add FC operational firmware load for 29xx Nilesh Javali
  2026-06-12 10:14   ` sashiko-bot
@ 2026-06-12 10:52   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 10:52 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Manish Rangankar <mrangankar@marvell.com>
> 
> Add support to load the 29xx FC operational firmware from the
> filesystem and to set up the corresponding firmware dump
> template.  This follows the same request_firmware / segment-load
> pattern used by earlier adapters.
> 
> Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_fw.h   |  36 +++
>   drivers/scsi/qla2xxx/qla_gbl.h  |   3 +-
>   drivers/scsi/qla2xxx/qla_init.c | 512 +++++++++++++++++++++++++++++++-
>   drivers/scsi/qla2xxx/qla_mbx.c  |  19 +-
>   drivers/scsi/qla2xxx/qla_nx.c   |   2 +-
>   drivers/scsi/qla2xxx/qla_os.c   |  47 ++-
>   drivers/scsi/qla2xxx/qla_sup.c  |   4 +-
>   7 files changed, 611 insertions(+), 12 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 31/60] scsi: qla2xxx: Enhance purex_entry handling for 29xx series
  2026-06-12  9:53 ` [PATCH v2 31/60] scsi: qla2xxx: Enhance purex_entry " Nilesh Javali
@ 2026-06-12 10:54   ` sashiko-bot
  2026-06-12 12:16   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:54 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

New issues:
- [High] The 9-bit `vp_idx` field extracted from QLA29XX extended IOCBs is silently truncated to 8 bits when assigned to a `uint8_t` local variable and other 8-bit struct fields.

Pre-existing issues:
- [Critical] The response queue polling logic overlaps the `signature` field with untrusted ELS payload data, allowing a remote attacker to wedge the queue or cause a kernel hard lockup.
- [High] Failure to correctly mark the head IOCB signature and over-consumption of IOCBs in `__qla_consume_iocb` leads to ring slot leaks and queue corruption.
--

commit 01f1d63d6b8d4fcc9af6e64914963d0a1cf5920b
Author: Nilesh Javali <njavali@marvell.com>
Subject: scsi: qla2xxx: Enhance purex_entry handling for 29xx series

This commit updates the QLogic qla2xxx driver to handle both standard and
extended 29xx series purex_entry structures. It uses a generic pointer to
process command and response data efficiently, branching only where field
encodings like vp_idx and els_frame_payload lengths differ.

> diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
> index b05f8e0b705ee..f8bc248e5d18e 100644
> --- a/drivers/scsi/qla2xxx/qla_edif.c
> +++ b/drivers/scsi/qla2xxx/qla_edif.c
> @@ -2544,26 +2544,58 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
>  	struct fc_port *fcport;
>  	struct qla_els_pt_arg a;
>  	be_id_t beid;
> +	__le16 nport_handle;
> +	__le32 rx_xchg_addr;
> +	__le16 ox_id;
> +	__le16 frame_size, status_flags, trunc_frame_size;
> +	uint8_t s_id[3], d_id[3];
> +	uint8_t vp_idx;
>  
>  	memset(&a, 0, sizeof(a));
>  
> +	/*
> +	 * purex_entry_24xx_ext (29xx) overlays purex_entry_24xx for every
> +	 * field touched here -- nport_handle, rx_xchg_addr, ox_id, frame_size,
> +	 * status_flags, trunc_frame_size, s_id[3], d_id[3] -- with only
> +	 * vp_idx differing in width (u8 at offset 6 vs __le16 at offsets 6-7,
> +	 * with reserved2 at offset 7 in the 24xx layout). So all reads but
> +	 * vp_idx go through a single struct purex_entry_24xx * view.
> +	 */
> +	{
> +		struct purex_entry_24xx *p = *pkt;
> +
> +		nport_handle = p->nport_handle;
> +		rx_xchg_addr = p->rx_xchg_addr;
> +		ox_id = p->ox_id;
> +		frame_size = p->frame_size;
> +		status_flags = p->status_flags;
> +		trunc_frame_size = p->trunc_frame_size;
> +		memcpy(s_id, p->s_id, sizeof(s_id));
> +		memcpy(d_id, p->d_id, sizeof(d_id));
> +		if (IS_QLA29XX(ha))
> +			vp_idx = le16_to_cpu(((struct purex_entry_24xx_ext *)
> +					      *pkt)->vp_idx);

[Severity: High]
Does this code inadvertently truncate the 16-bit vp_idx from QLA29XX extended
IOCBs to 8 bits?

The local variable vp_idx is declared as uint8_t, and it is later assigned
to a.vp_idx (which is a u8 in struct qla_els_pt_arg) and
purex->pur_info.vp_idx. For NPIV ports with an index of 256 or higher, could
this wrap around and direct ELS responses to the wrong virtual port?

> +		else
> +			vp_idx = p->vp_idx;
> +	}
> +

[ ... ]

> diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
> index f81cf70a0542c..76c66f060b7b4 100644
> --- a/drivers/scsi/qla2xxx/qla_isr.c
> +++ b/drivers/scsi/qla2xxx/qla_isr.c
> @@ -202,6 +202,11 @@ void __qla_consume_iocb(struct scsi_qla_host *vha,
>  	struct rsp_que *rsp_q = *rsp;
>  	response_t *new_pkt;
>  	uint16_t entry_count_remaining;
> +	/*
> +	 * entry_count is u8 at offset 1 in both purex_entry_24xx and
> +	 * purex_entry_24xx_ext, so the 24xx view is layout-compatible with
> +	 * either stride.
> +	 */
>  	struct purex_entry_24xx *purex = *pkt;
>  
>  	entry_count_remaining = purex->entry_count;

[Severity: High]
This is a pre-existing issue, but does __qla_consume_iocb() consume too many
IOCBs from the ring?

By the time this function is called, the main polling loop in
qla24xx_process_response_queue() has already advanced rsp->ring_ptr past the
head IOCB. Since this loop runs purex->entry_count times, doesn't it
start consuming from the second IOCB and steal one IOCB belonging to the
next hardware packet?

Additionally, does this mean the head IOCB's signature is never marked as
RESPONSE_PROCESSED, potentially causing queue corruption when the ring wraps
around?

[ ... ]

> @@ -914,6 +945,8 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
>  
>  	if (is_purls)
>  		memcpy(iocb_pkt, &purls->payload[0], no_bytes);
> +	else if (IS_QLA29XX(ha))
> +		memcpy(iocb_pkt, &purex_ext->els_frame_payload[0], no_bytes);
>  	else
>  		memcpy(iocb_pkt, &purex->els_frame_payload[0], no_bytes);
>  	buffer_copy_offset += no_bytes;
> @@ -922,6 +955,8 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
>  
>  	if (is_purls)
>  		((response_t *)purls)->signature = RESPONSE_PROCESSED;
> +	else if (IS_QLA29XX(ha))
> +		((struct response_ext *)purex_ext)->signature = RESPONSE_PROCESSED;
>  	else
>  		((response_t *)purex)->signature = RESPONSE_PROCESSED;

[Severity: Critical]
This is a pre-existing issue, but does the hardware polling logic here overlap
the signature field with untrusted ELS payload data?

In the purex_entry_24xx and purex_entry_24xx_ext structures, the payload
array physically overlaps the signature field at offset 60. Could a remote
FC port craft an unsolicited packet with the RESPONSE_PROCESSED byte sequence
(e.g., 0xDEADDEAD) at this offset, causing the response queue to be perceived
as already processed?

If so, would this lead to an infinite cpu_relax() soft-lockup loop in
qla27xx_copy_multiple_pkt() or otherwise wedge the queue?

>  	wmb();

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=31

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 28/60] scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters
  2026-06-12  9:53 ` [PATCH v2 28/60] scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters Nilesh Javali
@ 2026-06-12 10:54   ` sashiko-bot
  2026-06-12 11:47   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 10:54 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [Critical] An attacker can remotely hang the kernel CPU by sending a crafted FC packet (such as an FPIN, PUREX, or NVMe LS request) that contains the signature value 0xDEADDEAD at the offset corresponding to the continuation entry's signature field, causing the driver's polling loop to spin indefinitely.
- [High] `__qla_consume_iocb` over-consumes response queue entries by failing to account for the head IOCB, which leads to the silent dropping of an unrelated firmware response and potential corruption of the response ring.
--

commit b27f896ba52e64377e7afd0984134a443ff7ed05
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters
    
29xx adapters use 128-byte response queue entries
(sts_cont_entry_ext_t) instead of 64-byte (sts_cont_entry_t).  Update
all status continuation IOCB processing paths to branch on
IS_QLA29XX() and use the correct entry type and data payload size.

> diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
> index e95fb0e59f387..c18ee2459f5bd 100644
> --- a/drivers/scsi/qla2xxx/qla_isr.c
> +++ b/drivers/scsi/qla2xxx/qla_isr.c
> @@ -231,8 +231,15 @@ int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,

[Severity: High]
This is a pre-existing issue, but does __qla_consume_iocb() over-consume
response queue entries?

When skipping a multi-IOCB sequence, the function loops without accounting
for the head IOCB already being advanced:

void __qla_consume_iocb(...) {
    entry_count_remaining = purex->entry_count;
    while (entry_count_remaining > 0) {
        new_pkt = rsp_q->ring_ptr;
        ...
        qla_rsp_ring_advance(rsp_q);
        ...
        --entry_count_remaining;
    }
}

Since entry_count includes the head IOCB, but the caller already advanced
ring_ptr past it, this loop consumes exactly one extra, unrelated IOCB from
the response queue. Could this lead to silently dropping a legitimate
firmware response?

>  	void **pkt, struct rsp_que **rsp, u8 *buf, u32 buf_len)
>  {
>  	struct purex_entry_24xx *purex = *pkt;

[ ... ]

> @@ -906,28 +936,33 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
>  				continue;
>  			}

[Severity: Critical]
This is a pre-existing issue, but can this loop run infinitely if the
hardware DMA aliases payload data with the signature field?

In qla27xx_copy_multiple_pkt() (and qla27xx_copy_fpin_pkt()), the code
polls for continuation IOCBs:

    if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) {
        cpu_relax();
        continue;
    }

RESPONSE_PROCESSED is 0xDEADDEAD. Because the signature field in
sts_cont_entry_t and sts_cont_entry_ext aliases directly with raw payload
data, a received FC frame with 0xDEADDEAD at this offset could cause the
payload to overwrite the placeholder, resulting in a CPU lockup in interrupt
or DPC context.

Is this polling loop strictly necessary given qla_chk_cont_iocb_avail()
already validates the availability of continuation IOCBs?

> -			new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
> -			*pkt = new_pkt;
> +			*pkt = rsp_q->ring_ptr;
> +			if (IS_QLA29XX(ha)) {
> +				struct sts_cont_entry_ext *p = *pkt;
> +
> +				data = p->data;
> +				data_sz = sizeof(p->data);
> +			} else {
> +				sts_cont_entry_t *p = *pkt;
> +
> +				data = p->data;
> +				data_sz = sizeof(p->data);
> +			}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=28

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 07/60] scsi: qla2xxx: Add flash block read/write BSG support for 29xx
  2026-06-12  9:52 ` [PATCH v2 07/60] scsi: qla2xxx: Add flash block read/write BSG support " Nilesh Javali
  2026-06-12 10:11   ` sashiko-bot
@ 2026-06-12 10:55   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 10:55 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Manish Rangankar <mrangankar@marvell.com>
> 
> Introduce QL_VND_READ_FLASH_BLOCK and QL_VND_WRITE_FLASH_BLOCK
> BSG vendor commands so that userspace tools can perform flash
> block-level operations on 29xx adapters via the isp_ops
> interface.
> 
> Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_attr.c |   1 -
>   drivers/scsi/qla2xxx/qla_bsg.c  | 286 +++++++++++++++++++++++++++-----
>   drivers/scsi/qla2xxx/qla_bsg.h  |  16 ++
>   drivers/scsi/qla2xxx/qla_def.h  |   7 +
>   drivers/scsi/qla2xxx/qla_os.c   |  24 ++-
>   5 files changed, 292 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
> index 6a05ce195aa0..800751ab562a 100644
> --- a/drivers/scsi/qla2xxx/qla_attr.c
> +++ b/drivers/scsi/qla2xxx/qla_attr.c
> @@ -580,7 +580,6 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
>   	ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size);
>   	mutex_unlock(&ha->optrom_mutex);
>   
> -	ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size);
>   skip:
>   	return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
>   }

That looks like a bugfix; please separate it out such that it can have 
its own 'Fixes' tag and people don't need to include the entire patchset
to get this fix.

> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index 5e910b5ca670..0baf486e8fb8 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -1407,23 +1407,14 @@ qla24xx_iidma(struct bsg_job *bsg_job)
>   
>   static int
>   qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
> -	uint8_t is_update)
> +	uint32_t start, uint8_t is_update)
>   {
> -	struct fc_bsg_request *bsg_request = bsg_job->request;
> -	uint32_t start = 0;
>   	int valid = 0;
>   	struct qla_hw_data *ha = vha->hw;
>   
>   	if (unlikely(pci_channel_offline(ha->pdev)))
>   		return -EINVAL;
>   
> -	start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
> -	if (start > ha->optrom_size) {
> -		ql_log(ql_log_warn, vha, 0x7055,
> -		    "start %d > optrom_size %d.\n", start, ha->optrom_size);
> -		return -EINVAL;
> -	}
> -
>   	if (ha->optrom_state != QLA_SWAITING) {
>   		ql_log(ql_log_info, vha, 0x7056,
>   		    "optrom_state %d.\n", ha->optrom_state);
> @@ -1431,42 +1422,79 @@ qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
>   	}
>   
>   	ha->optrom_region_start = start;
> -	ql_dbg(ql_dbg_user, vha, 0x7057, "is_update=%d.\n", is_update);
> -	if (is_update) {
> -		if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
> -			valid = 1;
> -		else if (start == (ha->flt_region_boot * 4) ||
> -		    start == (ha->flt_region_fw * 4))
> -			valid = 1;
> -		else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
> -		    IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
> -		    IS_QLA28XX(ha))
> -			valid = 1;
> -		if (!valid) {
> -			ql_log(ql_log_warn, vha, 0x7058,
> -			    "Invalid start region 0x%x/0x%x.\n", start,
> -			    bsg_job->request_payload.payload_len);
> +
> +	if (IS_QLA29XX(ha)) {
> +		if (start > ha->optrom_size) {
> +			ql_log(ql_log_warn, vha, 0x7055,
> +			    "start %d > optrom_size %d.\n", start,
> +			    ha->optrom_size);
>   			return -EINVAL;
>   		}
>   
> -		ha->optrom_region_size = start +
> -		    bsg_job->request_payload.payload_len > ha->optrom_size ?
> -		    ha->optrom_size - start :
> -		    bsg_job->request_payload.payload_len;
> -		ha->optrom_state = QLA_SWRITING;
> +		if (is_update) {
> +			ha->optrom_region_size = start +
> +			    bsg_job->request_payload.payload_len >
> +			    ha->optrom_size ?
> +			    ha->optrom_size - start :
> +			    bsg_job->request_payload.payload_len;
> +			ha->optrom_state = QLA_SWRITING;
> +		} else {
> +			ha->optrom_region_size = start +
> +			    bsg_job->reply_payload.payload_len >
> +			    ha->optrom_size ?
> +			    ha->optrom_size - start :
> +			    bsg_job->reply_payload.payload_len;
> +			ha->optrom_state = QLA_SREADING;
> +		}
>   	} else {
> -		ha->optrom_region_size = start +
> -		    bsg_job->reply_payload.payload_len > ha->optrom_size ?
> -		    ha->optrom_size - start :
> -		    bsg_job->reply_payload.payload_len;
> -		ha->optrom_state = QLA_SREADING;
> +		if (start > ha->optrom_size) {
> +			ql_log(ql_log_warn, vha, 0x7055,
> +			    "start %d > optrom_size %d.\n", start,
> +			    ha->optrom_size);
> +			return -EINVAL;
> +		}
> +
> +		ql_dbg(ql_dbg_user, vha, 0x7057,
> +		    "is_update=%d.\n", is_update);
> +		if (is_update) {
> +			if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
> +				valid = 1;
> +			else if (start == (ha->flt_region_boot * 4) ||
> +			    start == (ha->flt_region_fw * 4))
> +				valid = 1;
> +			else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
> +			    IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) ||
> +			    IS_QLA27XX(ha) || IS_QLA28XX(ha))
> +				valid = 1;
> +			if (!valid) {
> +				ql_log(ql_log_warn, vha, 0x7058,
> +				    "Invalid start region 0x%x/0x%x.\n",
> +				    start,
> +				    bsg_job->request_payload.payload_len);
> +				return -EINVAL;
> +			}
> +
> +			ha->optrom_region_size = start +
> +			    bsg_job->request_payload.payload_len >
> +			    ha->optrom_size ?
> +			    ha->optrom_size - start :
> +			    bsg_job->request_payload.payload_len;
> +			ha->optrom_state = QLA_SWRITING;
> +		} else {
> +			ha->optrom_region_size = start +
> +			    bsg_job->reply_payload.payload_len >
> +			    ha->optrom_size ?
> +			    ha->optrom_size - start :
> +			    bsg_job->reply_payload.payload_len;
> +			ha->optrom_state = QLA_SREADING;
> +		}
>   	}
>   
>   	ha->optrom_buffer = vzalloc(ha->optrom_region_size);
>   	if (!ha->optrom_buffer) {
>   		ql_log(ql_log_warn, vha, 0x7059,
> -		    "Read: Unable to allocate memory for optrom retrieval "
> -		    "(%x)\n", ha->optrom_region_size);
> +		    "%s: Unable to allocate memory for optrom retrieval (%x)\n",
> +		    __func__, ha->optrom_region_size);
>   
>   		ha->optrom_state = QLA_SWAITING;
>   		return -ENOMEM;
> @@ -1478,17 +1506,25 @@ qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
>   static int
>   qla2x00_read_optrom(struct bsg_job *bsg_job)
>   {
> +	struct fc_bsg_request *bsg_request = bsg_job->request;
>   	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
>   	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
>   	scsi_qla_host_t *vha = shost_priv(host);
>   	struct qla_hw_data *ha = vha->hw;
> +	uint32_t start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
>   	int rval = 0;
>   
>   	if (ha->flags.nic_core_reset_hdlr_active)
>   		return -EBUSY;
>   
> +	if (IS_QLA29XX(ha)) {
> +		ql_log(ql_log_warn, vha, 0x7070,
> +		    "Legacy optrom read not supported on 29xx.\n");
> +		return -EINVAL;
> +	}
> +
>   	mutex_lock(&ha->optrom_mutex);
> -	rval = qla2x00_optrom_setup(bsg_job, vha, 0);
> +	rval = qla2x00_optrom_setup(bsg_job, vha, start, 0);
>   	if (rval) {
>   		mutex_unlock(&ha->optrom_mutex);
>   		return rval;
> @@ -1515,14 +1551,16 @@ qla2x00_read_optrom(struct bsg_job *bsg_job)
>   static int
>   qla2x00_update_optrom(struct bsg_job *bsg_job)
>   {
> +	struct fc_bsg_request *bsg_request = bsg_job->request;
>   	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
>   	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
>   	scsi_qla_host_t *vha = shost_priv(host);
>   	struct qla_hw_data *ha = vha->hw;
> +	uint32_t start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
>   	int rval = 0;
>   
>   	mutex_lock(&ha->optrom_mutex);
> -	rval = qla2x00_optrom_setup(bsg_job, vha, 1);
> +	rval = qla2x00_optrom_setup(bsg_job, vha, start, 1);
>   	if (rval) {
>   		mutex_unlock(&ha->optrom_mutex);
>   		return rval;
> @@ -1554,6 +1592,170 @@ qla2x00_update_optrom(struct bsg_job *bsg_job)
>   	return rval;
>   }
>   
> +/**
> + * qla29xx_bsg_flash_block_read - Read flash block for QLA29XX.
> + * @bsg_job: BSG job structure.
> + *
> + * Returns 0 on success, error code on failure.
> + */
> +static int qla29xx_bsg_flash_block_read(struct bsg_job *bsg_job)
> +{
> +	struct fc_bsg_request *bsg_req = bsg_job->request;
> +	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
> +	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
> +	scsi_qla_host_t *vha = shost_priv(host);
> +	struct qla_hw_data *ha = vha->hw;
> +	struct qla_block_rw *brcmd;
> +	void *buf;
> +	uint16_t opts = 0;
> +	int rval = 0;
> +
> +	if (bsg_job->request_len < sizeof(struct fc_bsg_request) +
> +	    2 * sizeof(uint32_t) + sizeof(struct qla_block_rw))
> +		return -EINVAL;
> +
> +	brcmd =
> +	(struct qla_block_rw *)&bsg_req->rqst_data.h_vendor.vendor_cmd[2];
> +
> +	ql_log(ql_log_info, vha, 0x7062,
> +	       "%s: region 0x%x options 0x%x rw_length 0x%x offset 0x%x chunk_length 0x%x\n",
> +		__func__, brcmd->region, brcmd->options, brcmd->rw_length,
> +		brcmd->region_offset, brcmd->chunk_length);
> +
> +	mutex_lock(&ha->optrom_mutex);
> +	rval = qla2x00_optrom_setup(bsg_job, vha, brcmd->region_offset, 0);
> +	if (rval) {
> +		mutex_unlock(&ha->optrom_mutex);
> +		return rval;
> +	}
> +
> +	check_and_set_mbc_bits(brcmd->options, opts, QLA_IS_TIM, BIT_15);
> +	check_and_set_mbc_bits(brcmd->options, opts, QLA_IS_SECURE, BIT_7);
> +	check_and_set_mbc_bits(brcmd->options, opts, QLA_UPDATE_MBR, BIT_8);
> +
> +	if (!ha->isp_ops->read_optrom_region) {
> +		vfree(ha->optrom_buffer);
> +		ha->optrom_buffer = NULL;
> +		ha->optrom_state = QLA_SWAITING;
> +		mutex_unlock(&ha->optrom_mutex);
> +		return -EINVAL;
> +	}
> +
> +	buf = ha->isp_ops->read_optrom_region(vha, brcmd->region, opts,
> +				ha->optrom_buffer, ha->optrom_region_start,
> +				ha->optrom_region_size);
> +	if (!buf) {
> +		ql_log(ql_log_warn, vha, 0x7063,
> +			"%s failed to read flash region 0x%x\n",
> +			__func__, brcmd->region);
> +		bsg_reply->result = -EINVAL;
> +		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
> +							EXT_STATUS_MAILBOX;
> +		bsg_reply->reply_payload_rcv_len = 0;
> +	} else {
> +		bsg_reply->result = DID_OK;
> +		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
> +			EXT_STATUS_OK;
> +
> +		ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x72a6,
> +			       ha->optrom_buffer, ha->optrom_region_size);
> +
> +		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
> +				    bsg_job->reply_payload.sg_cnt,
> +				    ha->optrom_buffer,
> +				    ha->optrom_region_size);
> +
> +		bsg_reply->reply_payload_rcv_len = ha->optrom_region_size;
> +	}
> +	vfree(ha->optrom_buffer);
> +	ha->optrom_buffer = NULL;
> +	ha->optrom_state = QLA_SWAITING;
> +	mutex_unlock(&ha->optrom_mutex);
> +	bsg_job_done(bsg_job, bsg_reply->result,
> +		     bsg_reply->reply_payload_rcv_len);
> +
> +	return rval;
> +}
> +
> +/**
> + * qla29xx_bsg_flash_block_write - Write flash block for QLA29XX.
> + * @bsg_job: BSG job structure.
> + *
> + * Returns 0 on success, error code on failure.
> + */
> +static int qla29xx_bsg_flash_block_write(struct bsg_job *bsg_job)
> +{
> +	struct fc_bsg_request *bsg_req = bsg_job->request;
> +	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
> +	struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
> +	scsi_qla_host_t *vha = shost_priv(host);
> +	struct qla_hw_data *ha = vha->hw;
> +	struct qla_block_rw *bwcmd;
> +	uint16_t opts = 0;
> +	int rval = 0;
> +
> +	if (bsg_job->request_len < sizeof(struct fc_bsg_request) +
> +	    2 * sizeof(uint32_t) + sizeof(struct qla_block_rw))
> +		return -EINVAL;
> +
> +	bwcmd =
> +	   (struct qla_block_rw *)&bsg_req->rqst_data.h_vendor.vendor_cmd[2];
> +
> +	ql_log(ql_log_info, vha, 0x7064,
> +	       "%s: region 0x%x options 0x%x rw_length 0x%x offset 0x%x chunk_length 0x%x\n",
> +		__func__, bwcmd->region, bwcmd->options, bwcmd->rw_length,
> +		bwcmd->region_offset, bwcmd->chunk_length);
> +
> +	mutex_lock(&ha->optrom_mutex);
> +	rval = qla2x00_optrom_setup(bsg_job, vha, bwcmd->region_offset, 1);
> +	if (rval) {
> +		mutex_unlock(&ha->optrom_mutex);
> +		return rval;
> +	}
> +
> +	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
> +			bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
> +			ha->optrom_region_size);
> +
> +	ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x73a6,
> +		       ha->optrom_buffer, ha->optrom_region_size);
> +
> +	check_and_set_mbc_bits(bwcmd->options, opts, QLA_IS_TIM, BIT_15);
> +	check_and_set_mbc_bits(bwcmd->options, opts, QLA_IS_SECURE, BIT_7);
> +	check_and_set_mbc_bits(bwcmd->options, opts, QLA_UPDATE_MBR, BIT_8);
> +
> +	if (!ha->isp_ops->write_optrom_region) {
> +		vfree(ha->optrom_buffer);
> +		ha->optrom_buffer = NULL;
> +		ha->optrom_state = QLA_SWAITING;
> +		mutex_unlock(&ha->optrom_mutex);
> +		return -EINVAL;
> +	}
> +
> +	rval = ha->isp_ops->write_optrom_region(vha, bwcmd->region, opts,
> +				ha->optrom_buffer, ha->optrom_region_start,
> +				ha->optrom_region_size);
> +	if (rval) {
> +		ql_log(ql_log_warn, vha, 0x7065,
> +			"%s failed to write flash %x\n", __func__, rval);
> +		bsg_reply->result = -EINVAL;
> +		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
> +							EXT_STATUS_MAILBOX;
> +	} else {
> +		bsg_reply->result = DID_OK;
> +		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
> +			EXT_STATUS_OK;
> +	}
> +	vfree(ha->optrom_buffer);
> +	ha->optrom_buffer = NULL;
> +	ha->optrom_state = QLA_SWAITING;
> +	mutex_unlock(&ha->optrom_mutex);
> +	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
> +	bsg_job_done(bsg_job, bsg_reply->result,
> +			bsg_reply->reply_payload_rcv_len);
> +	return 0;
> +}
> +
>   static int
>   qla2x00_update_fru_versions(struct bsg_job *bsg_job)
>   {
> @@ -3007,6 +3209,12 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_j
>   	case QL_VND_MBX_PASSTHRU:
>   		return qla2x00_mailbox_passthru(bsg_job);
>   
> +	case QL_VND_READ_FLASH_BLOCK:
> +		return qla29xx_bsg_flash_block_read(bsg_job);
> +
> +	case QL_VND_WRITE_FLASH_BLOCK:
> +		return qla29xx_bsg_flash_block_write(bsg_job);
> +
>   	default:
>   		return -ENOSYS;
>   	}
> diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
> index a920c8e482bc..ca0d83986b57 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.h
> +++ b/drivers/scsi/qla2xxx/qla_bsg.h
> @@ -40,6 +40,8 @@
>   #define QL_VND_MBX_PASSTHRU		0x2B
>   #define QL_VND_DPORT_DIAGNOSTICS_V2	0x2C
>   #define QL_VND_IMG_SET_VALID	0x30
> +#define QL_VND_READ_FLASH_BLOCK		0x33
> +#define QL_VND_WRITE_FLASH_BLOCK	0x34
>   
>   /* BSG Vendor specific subcode returns */
>   #define EXT_STATUS_OK			0
> @@ -83,6 +85,20 @@
>   #define ELS_OPCODE_BYTE			0x10
>   
>   /* BSG Vendor specific definations */
> +
> +#define QLA_IS_TIM	0x1
> +#define QLA_IS_SECURE	0x2
> +#define QLA_UPDATE_MBR	0x4
> +
> +struct qla_block_rw {
> +	uint32_t region;
> +	uint32_t rw_length;
> +	uint32_t options;
> +	uint32_t region_offset;
> +	uint32_t chunk_length;
> +	uint8_t  reserved[44];
> +} __packed;
> +
>   #define A84_ISSUE_WRITE_TYPE_CMD        0
>   #define A84_ISSUE_READ_TYPE_CMD         1
>   #define A84_CLEANUP_CMD                 2
> diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
> index 1ec7ee578e0c..719b6a1f9123 100644
> --- a/drivers/scsi/qla2xxx/qla_def.h
> +++ b/drivers/scsi/qla2xxx/qla_def.h
> @@ -3534,6 +3534,13 @@ struct isp_operations {
>   	int (*write_optrom)(struct scsi_qla_host *, void *, uint32_t,
>   		uint32_t);
>   
> +	void *(*read_optrom_region)(struct scsi_qla_host *vha,
> +		uint16_t reg_code, uint16_t opts, void *buf,
> +		uint32_t offset, uint32_t length);
> +	int (*write_optrom_region)(struct scsi_qla_host *vha,
> +		uint16_t reg_code, uint16_t opts, void *buf,
> +		uint32_t offset, uint32_t length);
> +
>   	int (*get_flash_version) (struct scsi_qla_host *, void *);
>   	int (*start_scsi) (srb_t *);
>   	int (*start_scsi_mq) (srb_t *);
> diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
> index 6560e58ad87c..948242f0088e 100644
> --- a/drivers/scsi/qla2xxx/qla_os.c
> +++ b/drivers/scsi/qla2xxx/qla_os.c
> @@ -2640,6 +2640,24 @@ static struct isp_operations qla27xx_isp_ops = {
>   	.initialize_adapter	= qla2x00_initialize_adapter,
>   };
>   
> +static void *
> +qla29xx_read_optrom_stub(struct scsi_qla_host *vha, void *buf,
> +			 uint32_t offset, uint32_t length)
> +{
> +	ql_dbg(ql_dbg_init, vha, 0x0191,
> +	    "read_optrom not supported on 29xx, use read_optrom_region.\n");
> +	return NULL;
> +}
> +
> +static int
> +qla29xx_write_optrom_stub(struct scsi_qla_host *vha, void *buf,
> +			  uint32_t offset, uint32_t length)
> +{
> +	ql_dbg(ql_dbg_init, vha, 0x0192,
> +	    "write_optrom not supported on 29xx, use write_optrom_region.\n");
> +	return QLA_FUNCTION_FAILED;
> +}
> +
>   static struct isp_operations qla29xx_isp_ops = {
>   	.pci_config		= qla25xx_pci_config,
>   	.reset_chip		= qla24xx_reset_chip,
> @@ -2670,8 +2688,10 @@ static struct isp_operations qla29xx_isp_ops = {
>   	.beacon_on		= qla24xx_beacon_on,
>   	.beacon_off		= qla24xx_beacon_off,
>   	.beacon_blink		= qla83xx_beacon_blink,
> -	.read_optrom		= qla25xx_read_optrom_data,
> -	.write_optrom		= qla24xx_write_optrom_data,
> +	.read_optrom		= qla29xx_read_optrom_stub,
> +	.write_optrom		= qla29xx_write_optrom_stub,
> +	.read_optrom_region	= qla29xx_read_optrom_data,
> +	.write_optrom_region	= qla29xx_write_optrom_data,
>   	.get_flash_version	= qla24xx_get_flash_version,
>   	.start_scsi_mq		= qla2xxx_dif_start_scsi_mq,
>   	.abort_isp		= qla2x00_abort_isp,

Otherwise looks good.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 08/60] scsi: qla2xxx: Add BSG MPI firmware load/dump for 29xx
  2026-06-12  9:52 ` [PATCH v2 08/60] scsi: qla2xxx: Add BSG MPI firmware load/dump " Nilesh Javali
  2026-06-12 10:14   ` sashiko-bot
@ 2026-06-12 10:57   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 10:57 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Manish Rangankar <mrangankar@marvell.com>
> 
> Add BSG vendor commands for loading and dumping MPI firmware on
> 29xx adapters.  This extends the existing BSG infrastructure with
> the necessary mailbox wrappers and flash helpers for MPI
> operations.
> 
> Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_bsg.c | 153 +++++++++++++++++++++++++++++++++
>   drivers/scsi/qla2xxx/qla_bsg.h |  18 ++++
>   drivers/scsi/qla2xxx/qla_def.h |   5 ++
>   drivers/scsi/qla2xxx/qla_gbl.h |   5 ++
>   drivers/scsi/qla2xxx/qla_mbx.c |  45 ++++++++++
>   drivers/scsi/qla2xxx/qla_sup.c | 117 +++++++++++++++++++++++++
>   6 files changed, 343 insertions(+)
> 
One wonders what 'MPI' stands for in this context...
But anyway.

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 09/60] scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx
  2026-06-12  9:52 ` [PATCH v2 09/60] scsi: qla2xxx: Add 128-byte IOCB definitions " Nilesh Javali
@ 2026-06-12 11:01   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:01 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Anil Gurumurthy <agurumurthy@marvell.com>
> 
> The 29xx series uses 128-byte IOCBs instead of the 64-byte IOCBs
> used by earlier adapters.  Add a new header (qla_fw29.h) with the
> extended IOCB structure definitions that match the 29xx firmware
> interface.
> 
> Signed-off-by: Anil Gurumurthy <agurumurthy@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_fw29.h | 725 ++++++++++++++++++++++++++++++++
>   1 file changed, 725 insertions(+)
>   create mode 100644 drivers/scsi/qla2xxx/qla_fw29.h
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 10/60] scsi: qla2xxx: Add extended status continuation and marker IOCBs
  2026-06-12  9:52 ` [PATCH v2 10/60] scsi: qla2xxx: Add extended status continuation and marker IOCBs Nilesh Javali
@ 2026-06-12 11:02   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:02 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Anil Gurumurthy <agurumurthy@marvell.com>
> 
> Add the 128-byte sts_cont_entry_ext_t and mrk_entry_ext_t
> structures required by 29xx firmware.  Include the qla_fw29.h
> header from qla_def.h so the new types are available throughout
> the driver.
> 
> Signed-off-by: Anil Gurumurthy <agurumurthy@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_def.h | 10 ++++++++++
>   1 file changed, 10 insertions(+)
> 

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 41/60] scsi: qla2xxx: Unify NVMe IOCB build path for 29xx and legacy adapters
  2026-06-12  9:53 ` [PATCH v2 41/60] scsi: qla2xxx: Unify NVMe IOCB build path for 29xx and legacy adapters Nilesh Javali
@ 2026-06-12 11:02   ` sashiko-bot
  2026-06-12 12:49   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:02 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The commit message claims to add a `reserved_end` field to `vp_rpt_id_entry_24xx_ext`, but the patch does not include this modification.
--

commit 2686364fecc2e5c624549321eb96a8c16ffc376c
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Unify NVMe IOCB build path for 29xx and legacy adapters

This commit unifies the IOCB build code for struct cmd_nvme and struct
cmd_nvme_ext by writing common header fields through a single view. It also
adds BUILD_BUG_ON checks to ensure the header layouts remain identical up
through the byte_count field.

> Also add a BUILD_BUG_ON size check for struct cmd_nvme_ext during
> module initialization and a reserved_end field to
> vp_rpt_id_entry_24xx_ext to ensure proper memory allocation and data
> integrity for 29xx series adapters.

[Severity: Medium]
The commit message mentions adding a reserved_end field to
vp_rpt_id_entry_24xx_ext, but I don't see any modifications to that
structure in the patch. Is this description leftover from a previous patch,
or is the structure modification missing from this commit?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=41

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 11/60] scsi: qla2xxx: Remove duplicate flash memo block definitions
  2026-06-12  9:52 ` [PATCH v2 11/60] scsi: qla2xxx: Remove duplicate flash memo block definitions Nilesh Javali
@ 2026-06-12 11:03   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:03 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Anil Gurumurthy <agurumurthy@marvell.com>
> 
> The qla_flash_memo_block and related structures in qla_fw29.h
> duplicate definitions already present elsewhere.  Remove the
> duplicates to avoid divergence and build warnings.
> 
> Signed-off-by: Anil Gurumurthy <agurumurthy@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_fw29.h | 39 ---------------------------------
>   1 file changed, 39 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_fw29.h b/drivers/scsi/qla2xxx/qla_fw29.h
> index e294b3f033db..efe1c60bee81 100644
> --- a/drivers/scsi/qla2xxx/qla_fw29.h
> +++ b/drivers/scsi/qla2xxx/qla_fw29.h
> @@ -683,43 +683,4 @@ struct vp_rpt_id_entry_24xx_ext {
>   		} f2;
>   	} u;
>   };
> -
> -struct qla_fmb_version {
> -	uint8_t major;
> -	uint8_t minor;
> -	uint8_t sub;
> -	uint8_t build;
> -};
> -
> -struct qla_fmb_upd_time {
> -	uint16_t year;
> -	uint8_t  month;
> -	uint8_t  day;
> -
> -	uint8_t  hour;
> -	uint8_t  minute;
> -	uint8_t  second;
> -	uint8_t  reserved;
> -};
> -
> -struct qla_flash_memo_block {
> -	int32_t  signature;	/* "FMBS" */
> -#define QLFC_FMB_SIG 0x464D4253
> -	uint32_t length;
> -	uint32_t version;
> -#define QLFC_FMB_VERSION 3
> -	uint32_t checksum;
> -	struct qla_fmb_version ffv_ver;
> -	struct qla_fmb_version mbi_ver;
> -	struct  {    /* offset 0x18: MBI package build time: YYYYMMDD */
> -		uint16_t year;
> -		uint8_t  month;
> -		uint8_t  day;
> -		uint8_t  reserve[4];
> -	} bld_time;
> -	uint8_t tool_id[4];
> -	struct qla_fmb_upd_time upd_time;	/* offset 0x24: flash update time stamp */
> -	struct qla_fmb_version  tool_version;	/* offset 0x2C: FW/tool version */
> -};
> -
>   #endif

So why did you define them in the first place?
Please merge it with patch #9.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 40/60] scsi: qla2xxx: Add size check for extended VP report ID entry
  2026-06-12  9:53 ` [PATCH v2 40/60] scsi: qla2xxx: Add size check for extended VP report ID entry Nilesh Javali
@ 2026-06-12 11:05   ` sashiko-bot
  2026-06-12 12:46   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:05 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Dangling pointer `fcport` is accessed after dropping `sess_lock`, and list traversal is performed entirely locklessly for Format 2 reports.
--

commit 4be1e7bdd8412a09686257ce5b4981203d404668
Author: Nilesh Javali <njavali@marvell.com>
scsi: qla2xxx: Add size check for extended VP report ID entry

This patch adds padding to the vp_rpt_id_entry_24xx_ext structure to match
the hardware IOCB stride. It also updates qla24xx_report_id_acquisition()
to extract vp_idx and vp_status from the extended structure on 29xx adapters.

> diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
> --- a/drivers/scsi/qla2xxx/qla_mbx.c
> +++ b/drivers/scsi/qla2xxx/qla_mbx.c
> @@ -4094,15 +4094,18 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
>  }
>  
>  void
> -qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
> -	struct vp_rpt_id_entry_24xx *rptid_entry)
> +qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt)
>  {

[Severity: High]
This is a pre-existing issue, but can this function trigger a use-after-free
or list corruption?

In the format 1 path, the sess_lock is dropped right before modifying the
fcport structure without acquiring a reference:

    spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
    ...
    fcport = qla2x00_find_fcport_by_wwpn(vha, rptid_entry->u.f1.port_name, 1);
    spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);

    if (fcport) {
        fcport->plogi_nack_done_deadline = jiffies + HZ;
        ...

Without a reference count being taken, could a concurrent thread remove
and free this fcport before it is modified here?

Additionally, in the format 2 path, the vha->vp_fcports list is iterated
locklessly, and then fcport is searched and dereferenced locklessly:

    list_for_each_entry(fcport, &vha->vp_fcports, list) {
        fcport->scan_state = QLA_FCPORT_SCAN;
        fcport->n2n_flag = 0;
    }

    fcport = qla2x00_find_fcport_by_wwpn(vha, rptid_entry->u.f2.port_name, 1);

    if (fcport) {
        fcport->login_retry = vha->hw->login_retry_count;
        ...

Could concurrent modifications to this list by the DPC thread or sysfs cause
list corruption panics or a use-after-free here?

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=40

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 12/60] scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx
  2026-06-12  9:52 ` [PATCH v2 12/60] scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx Nilesh Javali
  2026-06-12 10:29   ` sashiko-bot
@ 2026-06-12 11:12   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:12 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Anil Gurumurthy <agurumurthy@marvell.com>
> 
> Wire the 128-byte extended IOCB structures into the IO submission,
> completion, and queue-management paths.  On 29xx adapters the driver
> now builds cmd_type_6_ext / cmd_type_7_ext command IOCBs and processes
> the corresponding extended status entries, while falling back to the
> existing 64-byte IOCBs for earlier adapters.
> 
> Ring entry-size selection uses the qla_req_entry_size() /
> qla_rsp_entry_size() helpers and ring slot advancement uses
> qla_req_ring_advance() rather than open-coding IS_QLA29XX() branches
> at every call site.
> 
> Signed-off-by: Anil Gurumurthy <agurumurthy@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_dbg.c    |  31 +-
>   drivers/scsi/qla2xxx/qla_def.h    |  24 +
>   drivers/scsi/qla2xxx/qla_edif.c   |  18 +-
>   drivers/scsi/qla2xxx/qla_fw29.h   |  77 +++
>   drivers/scsi/qla2xxx/qla_gbl.h    |   4 +-
>   drivers/scsi/qla2xxx/qla_init.c   |  59 +-
>   drivers/scsi/qla2xxx/qla_inline.h | 174 +++++-
>   drivers/scsi/qla2xxx/qla_iocb.c   | 940 +++++++++++++++++++++++++-----
>   drivers/scsi/qla2xxx/qla_isr.c    |  48 +-
>   drivers/scsi/qla2xxx/qla_mid.c    |  31 +-
>   drivers/scsi/qla2xxx/qla_nvme.c   | 123 ++--
>   drivers/scsi/qla2xxx/qla_os.c     |  33 +-
>   drivers/scsi/qla2xxx/qla_target.c |  17 +-
>   13 files changed, 1323 insertions(+), 256 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 35/60] scsi: qla2xxx: Enhance task management IOCB handling for 29xx series
  2026-06-12  9:53 ` [PATCH v2 35/60] scsi: qla2xxx: Enhance task management IOCB handling for 29xx series Nilesh Javali
@ 2026-06-12 11:13   ` sashiko-bot
  2026-06-12 12:37   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:13 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] TOCTOU race in `qla24xx_abort_command` allows aborting the wrong command.
--

commit 4a66306dbd0c94dca32a3a10c1542df961832d3b
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Enhance task management IOCB handling for 29xx series

Update qla24xx_tm_iocb() and __qla24xx_issue_tmf() to support the
extended task management structure (tsk_mgmt_entry_ext) for 29xx
adapters.

> diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
> --- a/drivers/scsi/qla2xxx/qla_mbx.c
> +++ b/drivers/scsi/qla2xxx/qla_mbx.c

[ ... ]

> int
> qla24xx_abort_command(srb_t *sp)
> {
> 	int		rval;
> 	unsigned long   flags = 0;

[ ... ]

> 	spin_lock_irqsave(qpair->qp_lock_ptr, flags);
> 	for (handle = 1; handle < req->num_outstanding_cmds; handle++) {
> 		if (req->outstanding_cmds[handle] == sp)
> 			break;
> 	}
> 	spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
> 	if (handle == req->num_outstanding_cmds) {
> 		/* Command not found. */
> 		return QLA_ERR_NOT_FOUND;
> 	}
> 
> 	abt_buf = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &abt_dma);

[Severity: High]
This is a pre-existing issue, but can this sequence lead to aborting the
wrong command?

In qla24xx_abort_command() here, the qp_lock_ptr spinlock is released after
finding the hardware handle for the command. Then dma_pool_zalloc() is called
with GFP_KERNEL, which can sleep.

During this sleep window, could the original command complete, freeing the
handle for reuse by a newly submitted I/O request?

When qla24xx_abort_command() resumes, it uses the now-stale handle to
construct the abort IOCB:
abt->handle_to_abort = make_handle(req->id, handle);

Could this cause the firmware to incorrectly abort the newly submitted I/O
command instead of the intended one?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=35

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 13/60] scsi: qla2xxx: Replace IS_QLA29XX() size checks with entry-size helpers
  2026-06-12  9:52 ` [PATCH v2 13/60] scsi: qla2xxx: Replace IS_QLA29XX() size checks with entry-size helpers Nilesh Javali
@ 2026-06-12 11:14   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:14 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> From: Anil Gurumurthy <agurumurthy@marvell.com>
> 
> Replace scattered IS_QLA29XX() ternary expressions for request and
> response ring IOCB sizes with calls to qla_req_entry_size() and
> qla_rsp_entry_size() inline helpers and pre-computed local variables.
> 
> This consolidates the size selection in eight functions across
> qla_init.c (qla2x00_alloc_fw_dump), qla_mid.c (qla25xx_free_req_que,
> qla25xx_free_rsp_que, qla25xx_create_req_que, qla25xx_create_rsp_que),
> and qla_os.c (qla2x00_free_req_que, qla2x00_free_rsp_que,
> qla2x00_mem_alloc), improving readability and avoiding repeated
> conditionals in every allocation, free, and dump-size calculation.
> 
> Also extend the IS_QLA29XX() guard to the ring-index write path in
> qla2x00_start_iocbs() and the IOCB allocation read path in
> __qla2x00_alloc_iocbs().
> 
> No functional change.
> 
> Signed-off-by: Anil Gurumurthy <agurumurthy@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_init.c | 18 ++++++-----------
>   drivers/scsi/qla2xxx/qla_iocb.c |  5 +++--
>   drivers/scsi/qla2xxx/qla_mid.c  | 34 ++++++++++++---------------------
>   drivers/scsi/qla2xxx/qla_os.c   | 32 +++++++++++++++----------------
>   4 files changed, 36 insertions(+), 53 deletions(-)
> 
Why?
You just introduced 'IS_QLA29XX()' in one of the previous patches.

Please merge these patches.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 14/60] scsi: qla2xxx: Skip image-set-valid attribute for 29xx
  2026-06-12  9:52 ` [PATCH v2 14/60] scsi: qla2xxx: Skip image-set-valid attribute for 29xx Nilesh Javali
@ 2026-06-12 11:14   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:14 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> The 29xx adapter does not support the QLA_IMG_SET_VALID_SUPPORT
> driver attribute.  Gate the attribute behind an IS_QLA29XX()
> check so that userspace applications querying driver capabilities
> via BSG receive accurate information.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_bsg.c | 5 ++++-
>   1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index 92a0bc6dc7bc..00e980f0cd78 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -2904,11 +2904,14 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job)
>   static int
>   qla2x00_get_drv_attr(struct bsg_job *bsg_job)
>   {
> +	scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
>   	struct qla_drv_attr drv_attr;
>   	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
> +	struct qla_hw_data *ha = vha->hw;
>   
>   	memset(&drv_attr, 0, sizeof(struct qla_drv_attr));
> -	drv_attr.ext_attributes |= QLA_IMG_SET_VALID_SUPPORT;
> +	if (!IS_QLA29XX(ha))
> +		drv_attr.ext_attributes |= QLA_IMG_SET_VALID_SUPPORT;
>   
>   
>   	sg_copy_from_buffer(bsg_job->reply_payload.sg_list,

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 36/60] scsi: qla2xxx: Add abort command handling for 29xx series
  2026-06-12  9:53 ` [PATCH v2 36/60] scsi: qla2xxx: Add abort command " Nilesh Javali
@ 2026-06-12 11:15   ` sashiko-bot
  2026-06-12 12:38   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:15 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Type-bounds violation in memset() causes static analysis warnings.
--

commit 1b38e59bc3182cc17053adca01767c3b67880da0
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Add abort command handling for 29xx series

This commit extends the abort-IOCB code path to support the 29xx extended
abort_entry_24xx_ext structure alongside the existing abort_entry_24xx.
It widens function signatures to accept void pointers and updates memset
operations to use the appropriate ring-slot size.

> diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
> --- a/drivers/scsi/qla2xxx/qla_iocb.c
> +++ b/drivers/scsi/qla2xxx/qla_iocb.c
> @@ -3866,32 +3866,50 @@ qla82xx_start_scsi(srb_t *sp)
>  static void
> -qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb)
> +qla24xx_abort_iocb(srb_t *sp, void *pkt)
>  {
>  	struct srb_iocb *aio = &sp->u.iocb_cmd;
>  	scsi_qla_host_t *vha = sp->vha;
> +	struct qla_hw_data *ha = vha->hw;
>  	struct req_que *req = sp->qpair->req;
>  	srb_t *orig_sp = sp->cmd_sp;
> +	struct abort_entry_24xx *abt = pkt;
>  
> -	memset(abt_iocb, 0, sizeof(struct abort_entry_24xx));
> +	/*
> +	 * abort_entry_24xx_ext overlays abort_entry_24xx through
> +	 * req_que_no (offsets 0-17).  After that the layouts diverge:
> +	 * the 24xx variant has 30 bytes of reserved_1 followed by
> +	 * port_id[3] and a u8 vp_index at offsets 48-51, while the
> +	 * ext variant places a __le16 vp_index at offset 18 and has
> +	 * no port_id field.  Common-header writes go through one
> +	 * struct abort_entry_24xx * view; only port_id / vp_index
> +	 * branch on stride.
> +	 */
> +	memset(abt, 0, qla_req_entry_size(ha));

[Severity: Low]
Does this memset cause static analysis or compiler warnings regarding buffer
overflows?

The abt pointer is statically typed as struct abort_entry_24xx which is 64
bytes, but qla_req_entry_size(ha) can return 128 bytes for 29xx hardware.

While the underlying memory from pkt is correctly sized at 128 bytes and
won't cause a runtime memory safety issue, writing past the static type
bounds of abt can trigger -Wstringop-overflow warnings. Would it be better
to use the untyped pkt pointer for the memset instead?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=36

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 15/60] scsi: qla2xxx: Skip unsupported sysfs attributes for 29xx
  2026-06-12  9:52 ` [PATCH v2 15/60] scsi: qla2xxx: Skip unsupported sysfs attributes " Nilesh Javali
  2026-06-12 10:28   ` sashiko-bot
@ 2026-06-12 11:15   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:15 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> Not all sysfs attributes are applicable to the 29xx adapter.
> Return -EPERM for attributes that are meaningless on 29xx (gold
> firmware version, 84xx firmware version, flash block size, VLAN
> ID, VN-port MAC address, and CNA firmware dump toggle) so that
> userspace tools do not see stale or undefined values.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_attr.c | 21 +++++++++++++++++++++
>   1 file changed, 21 insertions(+)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 16/60] scsi: qla2xxx: Enable get_fw_version mailbox for 29xx
  2026-06-12  9:52 ` [PATCH v2 16/60] scsi: qla2xxx: Enable get_fw_version mailbox " Nilesh Javali
  2026-06-12 10:31   ` sashiko-bot
@ 2026-06-12 11:16   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:16 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> The serdes_version and several firmware capability fields were not
> populated for 29xx because the get_fw_version mailbox path
> excluded it from the 27xx/28xx checks.  Add IS_QLA29XX() to
> the relevant conditionals so that firmware version, EDIF, and
> serdes information are correctly retrieved on 29xx adapters.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_attr.c | 2 +-
>   drivers/scsi/qla2xxx/qla_mbx.c  | 8 ++++----
>   2 files changed, 5 insertions(+), 5 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 44/60] scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support
  2026-06-12  9:53 ` [PATCH v2 44/60] scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support Nilesh Javali
@ 2026-06-12 11:16   ` sashiko-bot
  2026-06-12 12:53   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:16 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] D-port diagnostics remain broken for QLA29xx due to a missing downstream feature check.
--

commit 8ffa642602cccd0180ae4aedb7562a144e25f71e
Author: Manish Rangankar <mrangankar@marvell.com>

scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support

This commit extends qla2xxx BSG command handling to recognize QLA29xx
adapters and align feature availability with hardware capabilities.
It updates several feature checks to allow QLA29xx in paths previously
restricted to QLA27xx/28xx.

> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index 00e980f0cd782..7f4558beee2c3 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -2741,7 +2741,7 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job)
>  	struct qla_dport_diag *dd;
>  
>  	if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
> -	    !IS_QLA28XX(vha->hw))
> +	    !IS_QLA28XX(vha->hw) && !IS_QLA29XX(vha->hw))

[Severity: Medium]
Does this change miss an update to the underlying mailbox execution function?

While qla2x00_do_dport_diagnostics() now allows QLA29xx adapters to proceed,
the lower-level function it calls, qla26xx_dport_diagnostics() in qla_mbx.c,
still appears to have the old hardware check:

drivers/scsi/qla2xxx/qla_mbx.c:qla26xx_dport_diagnostics() {
	...
	if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
	    !IS_QLA28XX(vha->hw))
		return QLA_FUNCTION_FAILED;
	...
}

Will this cause the diagnostic command to unconditionally fail with
EXT_STATUS_MAILBOX for QLA29xx adapters despite the wrapper permitting it?

>  		return -EPERM;
>  
>  	dd = kmalloc_obj(*dd);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=44

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 17/60] scsi: qla2xxx: Extend execute_fw mailbox to include 29xx
  2026-06-12  9:52 ` [PATCH v2 17/60] scsi: qla2xxx: Extend execute_fw mailbox to include 29xx Nilesh Javali
  2026-06-12 10:25   ` sashiko-bot
@ 2026-06-12 11:17   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:17 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> Add IS_QLA29XX() to the BPM capability macros and to the
> execute-firmware mailbox command so that NVMe enable, minimum
> speed negotiation, 128 Gbps speed reporting, EDIF hardware
> detection, and FW-semaphore retry logic all apply to 29xx
> adapters.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_attr.c | 12 ++++++++++--
>   drivers/scsi/qla2xxx/qla_def.h  |  5 +++--
>   drivers/scsi/qla2xxx/qla_gs.c   | 14 +++++++++++---
>   drivers/scsi/qla2xxx/qla_mbx.c  | 23 +++++++++++++----------
>   4 files changed, 37 insertions(+), 17 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 18/60] scsi: qla2xxx: Enable get_adapter_id mailbox for 29xx
  2026-06-12  9:52 ` [PATCH v2 18/60] scsi: qla2xxx: Enable get_adapter_id mailbox for 29xx Nilesh Javali
@ 2026-06-12 11:18   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:18 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> Add IS_QLA29XX() alongside the existing 27xx/28xx checks in
> qla2x00_get_adapter_id() so that the additional mailbox
> registers (buffer-to-buffer credit, SCM/EDC status) are read
> on 29xx adapters.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_mbx.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
> index 52d70b61654c..3fc08120fdf1 100644
> --- a/drivers/scsi/qla2xxx/qla_mbx.c
> +++ b/drivers/scsi/qla2xxx/qla_mbx.c
> @@ -1772,7 +1772,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
>   		mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
>   	if (IS_FWI2_CAPABLE(vha->hw))
>   		mcp->in_mb |= MBX_19|MBX_18|MBX_17|MBX_16;
> -	if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw))
> +	if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw) || IS_QLA29XX(vha->hw))
>   		mcp->in_mb |= MBX_15|MBX_21|MBX_22|MBX_23;
>   
>   	mcp->tov = MBX_TOV_SECONDS;
> @@ -1827,7 +1827,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
>   			}
>   		}
>   
> -		if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw)) {
> +		if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw) || IS_QLA29XX(vha->hw)) {
>   			vha->bbcr = mcp->mb[15];
>   			if (mcp->mb[7] & SCM_EDC_ACC_RECEIVED) {
>   				ql_log(ql_log_info, vha, 0x11a4,

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 19/60] scsi: qla2xxx: Enable init_firmware mailbox for 29xx
  2026-06-12  9:52 ` [PATCH v2 19/60] scsi: qla2xxx: Enable init_firmware " Nilesh Javali
@ 2026-06-12 11:18   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:18 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> The init_firmware mailbox command needs 29xx adapter support for reading
> back SFP information via mb3 and for validating SFP status on successful
> firmware initialization. Add IS_QLA29XX() checks alongside the existing
> 27xx/28xx checks.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_mbx.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 20/60] scsi: qla2xxx: Enable get_firmware_state for 29xx
  2026-06-12  9:52 ` [PATCH v2 20/60] scsi: qla2xxx: Enable get_firmware_state " Nilesh Javali
@ 2026-06-12 11:19   ` Hannes Reinecke
  2026-06-12 11:22   ` sashiko-bot
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:19 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> Enable get_firmware_state mailbox command for 29xx adapters by adding
> IS_QLA29XX() checks alongside existing IS_QLA27XX/IS_QLA28XX checks.
> This ensures MBX_12 (MPI state) is properly set up and reported for
> 29xx adapters.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_attr.c | 2 +-
>   drivers/scsi/qla2xxx/qla_mbx.c  | 6 +++---
>   2 files changed, 4 insertions(+), 4 deletions(-)
> Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 21/60] scsi: qla2xxx: Enable serdes, resource count and FCE trace for 29xx
  2026-06-12  9:52 ` [PATCH v2 21/60] scsi: qla2xxx: Enable serdes, resource count and FCE trace " Nilesh Javali
  2026-06-12 10:38   ` sashiko-bot
@ 2026-06-12 11:19   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:19 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> The 29xx adapters share the diagnostic and management interfaces
> already supported on ISP27xx/28xx, but several family capability
> gates still omitted IS_QLA29XX(), leaving these paths unreachable
> on 29xx.
> 
> Add IS_QLA29XX() to the relevant checks so the following work on
> 29xx adapters:
> 
>    - read/write SerDes word mailbox commands for PHY register access.
>    - get_resource_cnts requests MBX_12 to report the extended
>      firmware resource counts.
>    - FCE trace: the enable-FCE mailbox command, the "fce" and
>      "fw_resource_count" debugfs nodes in qla2x00_dfs_setup(), the
>      debugfs enable write in qla2x00_dfs_fce_write(), and the FCE DMA
>      buffer allocation in qla2x00_alloc_fce_trace().
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_dfs.c  |  4 ++--
>   drivers/scsi/qla2xxx/qla_init.c |  2 +-
>   drivers/scsi/qla2xxx/qla_mbx.c  | 11 +++++++----
>   3 files changed, 10 insertions(+), 7 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 22/60] scsi: qla2xxx: Enable set_els_cmds and echo_test for 29xx
  2026-06-12  9:52 ` [PATCH v2 22/60] scsi: qla2xxx: Enable set_els_cmds and echo_test " Nilesh Javali
@ 2026-06-12 11:20   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:20 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> Add IS_QLA29XX() checks to qla25xx_set_els_cmds_supported() and
> qla2x00_echo_test() so that ELS command support and echo test
> diagnostics are available on 29xx series adapters.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_mbx.c | 7 ++++---
>   1 file changed, 4 insertions(+), 3 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 23/60] scsi: qla2xxx: Add support for QLA29XX in data rate functions
  2026-06-12  9:52 ` [PATCH v2 23/60] scsi: qla2xxx: Add support for QLA29XX in data rate functions Nilesh Javali
@ 2026-06-12 11:20   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:20 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> Enhance the qla2x00_set_data_rate and qla2x00_get_data_rate
> functions to include checks for the QLA29XX series adapters.
> This modification ensures that the mailbox commands are correctly
> configured for the 29xx series, improving functionality and
> compatibility.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_attr.c | 2 +-
>   drivers/scsi/qla2xxx/qla_mbx.c  | 6 +++---
>   2 files changed, 4 insertions(+), 4 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 24/60] scsi: qla2xxx: Enable qla2x00_shutdown for 29xx
  2026-06-12  9:52 ` [PATCH v2 24/60] scsi: qla2xxx: Enable qla2x00_shutdown for 29xx Nilesh Javali
@ 2026-06-12 11:21   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:21 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> Enable qla2x00_shutdown for 29xx adapter by adding IS_QLA29XX check
> to the shutdown path that performs firmware abort cleanup.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_os.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
> index ef105ae6af41..a3e2c0a95a99 100644
> --- a/drivers/scsi/qla2xxx/qla_os.c
> +++ b/drivers/scsi/qla2xxx/qla_os.c
> @@ -3840,7 +3840,7 @@ qla2x00_shutdown(struct pci_dev *pdev)
>   		qla2x00_disable_eft_trace(vha);
>   
>   	if (IS_QLA25XX(ha) ||  IS_QLA2031(ha) || IS_QLA27XX(ha) ||
> -	    IS_QLA28XX(ha)) {
> +	    IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
>   		if (ha->flags.fw_started)
>   			qla2x00_abort_isp_cleanup(vha);
>   	} else {
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 25/60] scsi: qla2xxx: Use ring-slot helpers in __qla2x00_alloc_iocbs
  2026-06-12  9:52 ` [PATCH v2 25/60] scsi: qla2xxx: Use ring-slot helpers in __qla2x00_alloc_iocbs Nilesh Javali
  2026-06-12 10:41   ` sashiko-bot
@ 2026-06-12 11:21   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:21 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> __qla2x00_alloc_iocbs() open-codes ring pointer selection and entry
> size based on IS_QLA29XX(ha): 29xx reaches the slot via ring_ext_ptr
> and zeroes REQUEST_ENTRY_SIZE_EXT bytes, while other adapters use
> ring_ptr with REQUEST_ENTRY_SIZE bytes.
> 
> Replace the two branches with the qla_req_ring_slot() and
> qla_req_entry_size() helpers, and initialise pkt at declaration.
> The IS_QLAFX00 register-mapped writes remain guarded because
> IS_QLAFX00 and IS_QLA29XX cannot be true simultaneously.
> 
> No functional change: the bytes written to the firmware-visible IOCB
> are identical.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_iocb.c | 12 +++---------
>   1 file changed, 3 insertions(+), 9 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 26/60] scsi: qla2xxx: Add support for QLA29XX in memory allocation
  2026-06-12  9:52 ` [PATCH v2 26/60] scsi: qla2xxx: Add support for QLA29XX in memory allocation Nilesh Javali
  2026-06-12 10:40   ` sashiko-bot
@ 2026-06-12 11:22   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:22 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:52, Nilesh Javali wrote:
> Enhance the qla2x00_mem_alloc function to include checks for
> QLA29XX adapters.  This modification updates the conditions for
> memory allocation and cleanup, ensuring proper handling of the
> new adapter series alongside existing QLA27XX and QLA28XX checks.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_os.c | 10 ++++++----
>   1 file changed, 6 insertions(+), 4 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 20/60] scsi: qla2xxx: Enable get_firmware_state for 29xx
  2026-06-12  9:52 ` [PATCH v2 20/60] scsi: qla2xxx: Enable get_firmware_state " Nilesh Javali
  2026-06-12 11:19   ` Hannes Reinecke
@ 2026-06-12 11:22   ` sashiko-bot
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:22 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Kernel stack memory is leaked to userspace because `qla2x00_get_firmware_state()` copies uninitialized stack variables into the `states` array on error, which is then exposed via sysfs.
- [High] The `qla2x00_fw_state_show()` function attempts to bypass retrieving the firmware state when the chip is down or EEH is busy, but due to a logic flaw, it unconditionally executes the command anyway outside the safety lock.
--

commit 9c27dc0c2250c56e44cb02cf37c800f20ca12033
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Enable get_firmware_state for 29xx

This commit enables the get_firmware_state mailbox command for 29xx
adapters. It adds IS_QLA29XX() checks to ensure MBX_12 is properly
set up and reported.

> diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
> index 742becc0dadf7..ee6bf83029911 100644
> --- a/drivers/scsi/qla2xxx/qla_attr.c
> +++ b/drivers/scsi/qla2xxx/qla_attr.c
> @@ -2436,7 +2436,7 @@ qla2x00_mpi_fw_state_show(struct device *dev, struct device_attribute *attr,
>  	u16 mpi_state;
>  	struct qla_hw_data *ha = vha->hw;
>  
> -	if (!(IS_QLA27XX(ha) || IS_QLA28XX(ha)))
> +	if (!(IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)))
>  		return scnprintf(buf, PAGE_SIZE,
>  				"MPI state reporting is not supported for this HBA.\n");

[Severity: High]
This isn't a bug introduced by this patch, but I noticed a logic flaw in
qla2x00_fw_state_show() in this same file. When the chip is down, it unlocks
the mutex and jumps to the out label, but then unconditionally executes the
mailbox command again outside the lock:

qla2x00_fw_state_show()
    if (qla2x00_chip_is_down(vha)) {
        mutex_unlock(&vha->hw->optrom_mutex);
        ql_log(ql_log_warn, vha, 0x707c, "ISP reset active.\n");
        goto out;
    }
    ...
out:
    if (rval != QLA_SUCCESS) {
        memset(state, -1, sizeof(state));
        rval = qla2x00_get_firmware_state(vha, state);
    }

Since rval is initialized to QLA_FUNCTION_FAILED, does this bypass the safety
checks and execute qla2x00_get_firmware_state() anyway, potentially causing a
firmware hang?

> diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
> index 9c78aa66e12b3..a91ac59dd9c06 100644
> --- a/drivers/scsi/qla2xxx/qla_mbx.c
> +++ b/drivers/scsi/qla2xxx/qla_mbx.c
[ ... ]
> @@ -2301,7 +2301,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
>  		states[3] = mcp->mb[4];
>  		states[4] = mcp->mb[5];
>  		states[5] = mcp->mb[6];  /* DPORT status */
> -		if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
> +		if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
>  			states[11] = mcp->mb[12]; /* MPI state. */
>  	}

[Severity: High]
This is a pre-existing issue, but it looks like there is a kernel stack memory
leak in qla2x00_get_firmware_state() affecting the states array.

The mailbox command structure mbx_cmd_t mc is allocated on the stack but not
zero-initialized. If qla2x00_mailbox_command() fails early and returns
without modifying mc.mb, the code unconditionally copies the uninitialized
variables into the states array:

    states[0] = mcp->mb[1];
    if (IS_FWI2_CAPABLE(vha->hw)) {
        states[1] = mcp->mb[2];
        ...

The sysfs handler then formats this state array directly into its output and
ignores the error return value.

Could this expose uninitialized kernel stack memory to userspace?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=20

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 56/60] scsi: qla2xxx: Initialize NVMe abort_work once at submission
  2026-06-12  9:53 ` [PATCH v2 56/60] scsi: qla2xxx: Initialize NVMe abort_work once at submission Nilesh Javali
@ 2026-06-12 11:34   ` sashiko-bot
  2026-06-12 13:11   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:34 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Unbalanced kref increment when schedule_work() returns false, leading to a permanent command resource leak and NVMe FC transport hang.
--

commit d400422c8159891ac0e43b19f4d841502d8f3491
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Initialize NVMe abort_work once at submission

This commit initializes NVMe abort_work once at command submission
instead of immediately before schedule_work(). This prevents workqueue
corruption when an abort is issued multiple times for the same command.

> diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
> index 0038b6274d444..3b2f255a5d7d4 100644
> --- a/drivers/scsi/qla2xxx/qla_nvme.c
> +++ b/drivers/scsi/qla2xxx/qla_nvme.c
> @@ -463,7 +463,6 @@ static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport,
>  	}
>  	spin_unlock_irqrestore(&priv->cmd_lock, flags);
>  
> -	INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
>  	schedule_work(&priv->abort_work);

[Severity: High]
Does this code leak the kref when schedule_work() returns false?

Because INIT_WORK() was removed, schedule_work() will now correctly return
false if the work item is already pending (for instance, during concurrent
aborts).

However, qla_nvme_ls_abort() calls kref_get_unless_zero(&priv->sp->cmd_kref)
before schedule_work(). If schedule_work() returns false, the work function
qla_nvme_abort_work() will only execute once and therefore call kref_put()
only once. 

Doesn't this leave the extra kref leaked, preventing the command from ever
completing and potentially hanging the NVMe FC transport?

[ ... ]

> @@ -545,7 +545,6 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport,
>  	}
>  	spin_unlock_irqrestore(&priv->cmd_lock, flags);
>  
> -	INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
>  	schedule_work(&priv->abort_work);

[Severity: High]
Similarly in qla_nvme_fcp_abort(), does this code also leak the kref if
schedule_work() returns false?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=56

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 53/60] scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size
  2026-06-12  9:53 ` [PATCH v2 53/60] scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size Nilesh Javali
@ 2026-06-12 11:35   ` sashiko-bot
  2026-06-12 13:09   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:35 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

New issues:
- [High] The patch prevents out-of-bounds memory accesses by rejecting `vp_index > 128` during VP disable, but fails to clamp the maximum number of advertised VPs to 128. This creates an asymmetry where VPs > 128 can still be created and enabled, but their deletion will silently fail to disable the VP in firmware, leading to a permanent firmware resource leak.

Pre-existing issues:
- [High] A race condition between the async IOCB timeout handler and the ISR completion path can result in double completion executions and use-after-free of the SRB and on-stack completion variable.
--

commit efb150f1a60ba57983eb9491ce05b1ecf81e2b1b
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size

This commit fixes an out-of-bounds write in qla25xx_ctrlvp_iocb() by adding
bounds checking for vp_index against the fixed 128-bit vp_idx_map bitmap.
It also adds a check in qla24xx_control_vp() to reject requests with
vp_index > 128.

> diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
> index 7072af5b42178..b7d9c1a53f3ce 100644
> --- a/drivers/scsi/qla2xxx/qla_mid.c
> +++ b/drivers/scsi/qla2xxx/qla_mid.c
> @@ -987,6 +987,14 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
>  	if (vp_index == 0 || vp_index >= ha->max_npiv_vports)
>  		return QLA_PARAMETER_ERROR;
>  
> +	/*
> +	 * The VP_CTRL IOCB selects the target VP through a fixed 128-bit
> +	 * (16-byte) vp_idx_map bitmap, so vp_index must fit within it even
> +	 * if firmware advertises more NPIV vports.
> +	 */
> +	if (vp_index > sizeof_field(struct vp_ctrl_entry_24xx, vp_idx_map) * 8)
> +		return QLA_PARAMETER_ERROR;
> +

[Severity: High]
If firmware advertises up to 255 VPs (since ha->max_npiv_vports is parsed from
mcp->mb[11] in qla2x00_get_fw_version()), does this new bounds check introduce
a firmware resource leak during VP deletion?

While this prevents the out-of-bounds write, VPs with vp_index > 128 can still
be successfully created because the maximum advertised limit is not clamped.
When deleting such a VP, qla24xx_vport_delete() calls qla24xx_disable_vp(),
which will now fail and return QLA_PARAMETER_ERROR due to this check.

Because the deletion process ignores this failure and continues fully freeing
the kernel's local data structures, won't the firmware still consider the VP
active, resulting in a permanent leak? Is it possible to clamp
ha->max_npiv_vports to 128 during initialization to prevent creating these
VPs in the first place?

>  	/* ref: INIT */
>  	sp = qla2x00_get_sp(base_vha, NULL, GFP_KERNEL);
>  	if (!sp)

[Severity: High]
This is a pre-existing issue, but does the on-stack completion variable used
alongside this SRB introduce a use-after-free risk due to a race condition
in the async IOCB timeout handler?

If qla2x00_async_iocb_timeout() executes and the abort fails, it attempts to
remove the SRB from the outstanding_cmds array, but unconditionally calls
sp->done(sp, QLA_FUNCTION_TIMEOUT) without verifying if the SRB was actually
found and removed:

drivers/scsi/qla2xxx/qla_init.c:qla2x00_async_iocb_timeout() {
    ...
    spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags);
    sp->done(sp, QLA_FUNCTION_TIMEOUT);
    ...
}

If the normal ISR completes the command concurrently, it will remove the SRB
and also call sp->done(). This causes qla_ctrlvp_sp_done() to execute twice.

The first execution wakes up the submitter thread here, causing it to free
sp and destroy the on-stack comp variable. Won't the second execution then
call complete() on a dangling comp pointer, leading to a stack use-after-free?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=53

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 27/60] scsi: qla2xxx: Refactor marker IOCB handling for 29xx series
  2026-06-12  9:53 ` [PATCH v2 27/60] scsi: qla2xxx: Refactor marker IOCB handling for 29xx series Nilesh Javali
@ 2026-06-12 11:36   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:36 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Rework __qla2x00_marker() and qla_marker_iocb() for QLA29XX extended
> marker IOCB (128-byte) support.  The extended layout (mrk_entry_24xx_ext)
> overlays mrk_entry_24xx through 'lun', so the common header fields
> (entry_type, modifier, nport_handle, lun, handle) are written through a
> single struct mrk_entry_24xx pointer; only vp_index, which differs in
> width (u8 in 24xx vs __le16 in the ext layout), needs a stride-aware
> IS_QLA29XX() branch.
> 
>   - Allocate the IOCB once via __qla2x00_alloc_iocbs() and cast to
>     struct mrk_entry_24xx, eliminating duplicated alloc/error paths.
>   - Branch only on vp_index assignment where layout diverges.
>   - Update qla_marker_iocb_entry() in qla_isr.c to accept void *pkt
>     so it handles both 64-byte and 128-byte marker completions.
>   - Add BUILD_BUG_ON size checks for mrk_entry_ext_t (128) and
>     struct mrk_entry_24xx_ext (128).
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_def.h  |  2 +-
>   drivers/scsi/qla2xxx/qla_iocb.c | 84 ++++++++++++++++-----------------
>   drivers/scsi/qla2xxx/qla_isr.c  |  7 +--
>   drivers/scsi/qla2xxx/qla_os.c   |  1 +
>   4 files changed, 48 insertions(+), 46 deletions(-)
> 
Why do you need to refactor code which you just have submitted?

Please merge with patch #12.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 59/60] scsi: qla2xxx: Fix BSG job leak on validate flash image error path
  2026-06-12  9:53 ` [PATCH v2 59/60] scsi: qla2xxx: Fix BSG job leak on validate flash image error path Nilesh Javali
@ 2026-06-12 11:38   ` sashiko-bot
  2026-06-12 13:12   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:38 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing bounds check on `job->request_len` leads to out-of-bounds heap reads of the BSG request payload.
--

commit 39e37aaaa21d29987eb2a2358ad4f2e41418684a
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Fix BSG job leak on validate flash image error path

This commit fixes a BSG job leak in the validate flash image error path.
By calling bsg_job_done() unconditionally, it ensures the transport
completes the job and frees resources even if the validation fails.

> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -3734,9 +3734,8 @@ static int qla28xx_validate_flash_image(struct bsg_job *bsg_job)

[Severity: High]
This is a pre-existing issue, but does this BSG job handling path lack
sufficient bounds checking on job->request_len?

The BSG infrastructure allocates job->request using memdup_user() with the
exact user-supplied length. In fc_bsg_host_dispatch(), the transport only
verifies that request_len >= sizeof(uint32_t) before inspecting the msgcode.

When dispatching a vendor command, it appears to read out of bounds if the
request is too small:

drivers/scsi/scsi_transport_fc.c:fc_bsg_host_dispatch() {
    ...
    if ((shost->hostt->vendor_id == 0L) ||
        (bsg_request->rqst_data.h_vendor.vendor_id !=
            shost->hostt->vendor_id)) {
    ...
}

If the access accidentally matches the host's vendor_id, the driver then
reads further without validating the length:

drivers/scsi/qla2xxx/qla_bsg.c:qla2x00_process_vendor_specific() {
    ...
    switch (bsg_request->rqst_data.h_vendor.vendor_cmd[0]) {
    ...
}

This validation path then continues to read the command index directly
from the request without length validation:

drivers/scsi/qla2xxx/qla_bsg.c:qla28xx_do_validate_flash_image() {
    ...
    img_idx = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
    ...
}

Can an attacker with the sys_rawio capability submit a malformed request
that triggers out-of-bounds heap reads across these functions, potentially
causing a panic or leaking uninitialized data?

>  	bsg_reply->result = DID_OK << 16;
>  	bsg_reply->reply_payload_rcv_len = 0;
>  	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
> -	if (!rval)
> -		bsg_job_done(bsg_job, bsg_reply->result,
> -			     bsg_reply->reply_payload_rcv_len);
> +	bsg_job_done(bsg_job, bsg_reply->result,
> +		     bsg_reply->reply_payload_rcv_len);
>  
>  	return QLA_SUCCESS;
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=59

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 55/60] scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition()
  2026-06-12  9:53 ` [PATCH v2 55/60] scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition() Nilesh Javali
@ 2026-06-12 11:38   ` sashiko-bot
  2026-06-12 13:10   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:38 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:

New issues:
- [High] The decrement of `vp->vref_count` lacks a release memory barrier and breaks the driver's locking idiom, potentially leading to a use-after-free write on weakly ordered architectures.

Pre-existing issues:
- [High] The exact same use-after-free vulnerability fixed by this patch in `qla24xx_report_id_acquisition` is present in the NVMe FC path via `qla2xxx_get_vha_from_vp_idx`.
- [High] Target mode processing uses `qla_find_host_by_vp_idx` which returns an unreferenced `vha` pointer, opening a race condition for UAF during vport teardown.
- [High] btree operations on `ha->host_map` via `qla_update_host_map()` are performed without holding `vport_slock`.
- [High] Missing `sess_lock` during `vp_fcports` list traversal in Format 2 branch.
- [High] Invalid use of list_for_each_entry_safe across dropped spinlocks in DPC and alert handlers.
- [High] `qla24xx_report_id_acquisition` ignores `VPORT_DELETE` and can resurrect a deleted vport.
--

commit 95ed94124983f94c25ebc87bace3b12cf63aa94f
Author: Nilesh Javali <njavali@marvell.com>
scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition()

This commit fixes a use-after-free by taking a vport reference
(vref_count) while holding vport_slock when finding a virtual port,
and dropping it after use. This ensures the vport isn't freed by a
concurrent qla24xx_deallocate_vp_id().

Cc: stable@vger.kernel.org

> diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
> index 8a001b489fc0e..bfb931eb14f61 100644
> --- a/drivers/scsi/qla2xxx/qla_mbx.c
> +++ b/drivers/scsi/qla2xxx/qla_mbx.c
> @@ -4275,6 +4275,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt)
>  			list_for_each_entry(vp, &ha->vp_list, list) {
>  				if (vp_idx == vp->vp_idx) {
>  					found = 1;
> +					atomic_inc(&vp->vref_count);

[Severity: High]
This is a pre-existing issue, but does this loop need to check if the vport
is actively being deleted?

If qla24xx_vport_delete() is concurrently removing the vport and has already
taken it out of the host_map, would we resurrect it here?

We take a reference and later re-register it without checking for
VPORT_DELETE on vp->dpc_flags, which might lead to a use-after-free when the
system later queries the map.

>  					break;
>  				}
>  			}
> @@ -4292,6 +4293,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt)
>  			set_bit(VP_IDX_ACQUIRED, &vp->vp_flags);
>  			set_bit(REGISTER_FC4_NEEDED, &vp->dpc_flags);
>  			set_bit(REGISTER_FDMI_NEEDED, &vp->dpc_flags);
> +
> +			atomic_dec(&vp->vref_count);

[Severity: High]
Could the weakly ordered nature of atomic_dec() allow the preceding set_bit()
operations to be reordered after the decrement?

In the kernel, set_bit() and atomic_dec() do not imply memory barriers.
On weakly ordered architectures, the atomic_dec() could become visible
before the stores to vp->vp_flags and vp->dpc_flags.

If qla24xx_deallocate_vp_id() polls vref_count concurrently, could it
observe vref_count == 0 early, proceeding to unlink the vport before the
flags are fully updated?

Would it be safer to enclose the atomic_dec() within vport_slock, matching
how the reference is acquired?

>  		}
>  		set_bit(VP_DPC_NEEDED, &vha->dpc_flags);

[Severity: High]
This is a pre-existing issue, but are we modifying the host_map without
holding the required lock in this same function?

Just before the snippet above, qla_update_host_map() evaluates to
qla_update_vp_map() which inserts the vp into the ha->host_map btree. The
documentation for qla_update_vp_map() states it requires vport_slock:

drivers/scsi/qla2xxx/qla_mid.c:qla_update_vp_map() {
    /* vport_slock to be held by the caller */
    ...
    btree_insert32(&ha->host_map, ...);
}

Since we dropped ha->vport_slock before this call, could concurrent
modifications corrupt the btree?


[Severity: High]
This isn't a bug introduced by this patch, but should we be holding
sess_lock while iterating vp_fcports in the Format 2 path of
qla24xx_report_id_acquisition()?

In the Format 1 path, the list is traversed with sess_lock held.
However, in the Format 2 path, we traverse the list and call
qla2x00_find_fcport_by_wwpn() without holding vha->hw->tgt.sess_lock:

drivers/scsi/qla2xxx/qla_mbx.c:qla24xx_report_id_acquisition() {
    ...
    list_for_each_entry(fcport, &vha->vp_fcports, list) {
        fcport->scan_state = QLA_FCPORT_SCAN;
        fcport->n2n_flag = 0;
    }

    fcport = qla2x00_find_fcport_by_wwpn(vha,
        rptid_entry->u.f2.port_name, 1);
    ...
}

Could this lack of locking lead to list corruption or use-after-free if
vp_fcports is modified concurrently?


[Severity: High]
This is a pre-existing issue, but does the NVMe FC path suffer from a similar
use-after-free vulnerability as the one fixed in this patch?

When calling qla2xxx_get_vha_from_vp_idx() in qla_nvme.c, the lock is dropped
and the vha pointer is returned without incrementing vref_count:

drivers/scsi/qla2xxx/qla_nvme.c:qla2xxx_get_vha_from_vp_idx() {
    if (vha->vp_idx == vp_index) {
        spin_unlock_irqrestore(&ha->vport_slock, flags);
        return vha;
    }
}

The caller, qla2xxx_process_purls_iocb(), then heavily uses this unreferenced
pointer. Could a concurrent qla24xx_deallocate_vp_id() tear down the vport
and free it, causing a use-after-free in the NVMe response path?


[Severity: High]
This is a pre-existing issue, but does qla_find_host_by_vp_idx() also leak
unreferenced pointers in target mode?

drivers/scsi/qla2xxx/qla_mid.c:qla_find_host_by_vp_idx() {
    if (likely(test_bit(vp_idx, ha->vp_idx_map)))
        return ha->vp_map[vp_idx].vha;
}

Various target mode functions route commands to the vport returned by this
lookup. Since no reference is taken, couldn't qla24xx_deallocate_vp_id()
free the vha concurrently?


[Severity: High]
This is a pre-existing issue, but is it safe to use list_for_each_entry_safe()
when dropping the spinlock in DPC and alert handlers?

In qla2x00_do_dpc_all_vps(), the lock is dropped inside the safe iteration
loop:

drivers/scsi/qla2xxx/qla_mid.c:qla2x00_do_dpc_all_vps() {
    spin_lock_irqsave(&ha->vport_slock, flags);
    list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
        if (vp->vp_idx) {
            atomic_inc(&vp->vref_count);
            spin_unlock_irqrestore(&ha->vport_slock, flags);
            ...
            spin_lock_irqsave(&ha->vport_slock, flags);
}

Since list_for_each_entry_safe() caches the next element (tvp), if a
concurrent deletion removes tvp from the list and frees it while the lock
is dropped, won't resuming the loop result in a use-after-free?
A similar pattern exists in qla2x00_alert_all_vps().

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=55

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 57/60] scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject
  2026-06-12  9:53 ` [PATCH v2 57/60] scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject Nilesh Javali
@ 2026-06-12 11:39   ` sashiko-bot
  2026-06-12 13:11   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:39 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing `list_del()` before `kfree()` on the error path of `qla_nvme_xmt_ls_rsp()` causes use-after-free list corruption.
- [High] Concurrent and unsynchronized operations on the `fcport->unsol_ctx_head` linked list.
- [High] `qla_nvme_ls_reject_iocb()` unconditionally writes to the hardware doorbell even when the firmware is not started or the device is offline.
--

commit d9117eaeb87a4e4531b8933ba8f285e5c93c354a
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject

This commit addresses an issue where qla_nvme_ls_reject_iocb() is called
without holding the producer lock from two paths, which can corrupt the ring
producer state. It takes the qp_lock_ptr around the two unlocked callers and
documents the helper as caller-locked.

> diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
> index 3b2f255a5d7d4..8dc6df6c2e1c5 100644
> --- a/drivers/scsi/qla2xxx/qla_nvme.c
> +++ b/drivers/scsi/qla2xxx/qla_nvme.c
> @@ -374,6 +374,7 @@ static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport,
>  	srb_t *sp;
>  	int rval = QLA_FUNCTION_FAILED;
>  	uint8_t cnt = 0;
> +	unsigned long flags;
>  
>  	if (!fcport || fcport->deleted)
>  		goto out;

[ ... ]

> @@ -440,7 +441,9 @@ static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport,
>  	a.vp_idx = vha->vp_idx;
>  	a.nport_handle = uctx->nport_handle;
>  	a.xchg_address = uctx->exchange_address;
> +	spin_lock_irqsave(ha->base_qpair->qp_lock_ptr, flags);
>  	qla_nvme_ls_reject_iocb(vha, ha->base_qpair, &a, true);
> +	spin_unlock_irqrestore(ha->base_qpair->qp_lock_ptr, flags);

[Severity: High]
This isn't a bug introduced by this patch, but does the call to
qla_nvme_ls_reject_iocb() here write to the hardware doorbell even when the
firmware is not started?

If qla_nvme_xmt_ls_rsp() bails out early because !ha->flags.fw_started, it
jumps to the out label and executes qla_nvme_ls_reject_iocb(). Inside that
function, qla2x00_start_iocbs() unconditionally writes to the doorbell ring.

Could accessing MMIO registers when the firmware is stopped or in reset lead
to PCIe bus errors or adapter hangs?

>  	kfree(uctx);

[Severity: High]
This is a pre-existing issue, but does this error path leave a dangling
pointer in the unsol_ctx_head list?

If uctx was previously linked into fcport->unsol_ctx_head (such as in
qla2xxx_process_purls_iocb()), freeing it here without first calling
list_del(&uctx->elem) leaves the freed memory in the list.

Will the next operation on this list access freed memory and cause list
corruption?

>  	return rval;
>  }

[ ... ]

> @@ -1299,6 +1306,7 @@ qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item)
>  {
>  	struct qla_nvme_unsol_ctx *uctx = item->purls_context;
>  	struct qla_nvme_lsrjt_pt_arg a;
> +	unsigned long flags;
>  	int ret = 1;
>  
>  #if (IS_ENABLED(CONFIG_NVME_FC))
> @@ -1311,7 +1319,9 @@ qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item)
>  		a.vp_idx = vha->vp_idx;
>  		a.nport_handle = uctx->nport_handle;
>  		a.xchg_address = uctx->exchange_address;
> +		spin_lock_irqsave(vha->hw->base_qpair->qp_lock_ptr, flags);
>  		qla_nvme_ls_reject_iocb(vha, vha->hw->base_qpair, &a, true);
> +		spin_unlock_irqrestore(vha->hw->base_qpair->qp_lock_ptr, flags);
>  		list_del(&uctx->elem);

[Severity: High]
This isn't a bug introduced by this patch, but does this list deletion race
with other contexts?

This list_del(&uctx->elem) is executed in a workqueue context without
acquiring any locks to protect the list. Since elements are added to the list
in qla2xxx_process_purls_iocb() while holding a per-queue hardware response
lock, could concurrent unsynchronized operations corrupt the list pointers?

>  		kfree(uctx);
>  	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=57

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 58/60] scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak
  2026-06-12  9:53 ` [PATCH v2 58/60] scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak Nilesh Javali
@ 2026-06-12 11:40   ` sashiko-bot
  2026-06-12 13:12   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:40 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Pre-existing issues:
- [High] Functions using a stack-allocated `bsg[DMA_POOL_SIZE]` buffer leak uninitialized kernel stack memory to user space and the device hardware.
- [High] The CPU zero-initializes a DMA mapped buffer with `memset()` after ownership has been transferred to the device via `dma_map_single()`, which can silently overwrite device DMA data on non-coherent architectures.
- [High] The mapped DMA buffer `dd->buf` is embedded inside a `__packed` structure, forcing an unaligned address mapping that violates cacheline isolation and risks DMA hardware errors.
--

commit db26a0928e61a1d01c807ef436263bd6ea60d8b1
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak

The qla2x00_do_dport_diagnostics function previously allocated the response
buffer without zeroing it. If the user request payload was short, the unused
fields would leak uninitialized kernel heap contents to user space. This patch
fixes the info leak by switching to kzalloc_obj.

> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index 7f4558beee2c3..b57c55964f9e2 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -2744,7 +2744,7 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job)
>  	    !IS_QLA28XX(vha->hw) && !IS_QLA29XX(vha->hw))
>  		return -EPERM;
>  
> -	dd = kmalloc_obj(*dd);
> +	dd = kzalloc_obj(*dd);

[Severity: High]
This isn't a bug introduced by this patch, but does allocating this __packed
structure lead to unaligned DMA mappings?

Looking at struct qla_dport_diag in drivers/scsi/qla2xxx/qla_bsg.h, the
__packed attribute forces the buf array to an unaligned 2-byte offset:

struct qla_dport_diag {
    uint16_t options;
    uint32_t buf[16];
    uint8_t  unused[62];
} __packed;

When dd->buf is later passed to dma_map_single() inside
qla26xx_dport_diagnostics(), wouldn't this violate the DMA API alignment
constraints and risk cacheline sharing or hardware DMA failures?

>  	if (!dd) {
>  		ql_log(ql_log_warn, vha, 0x70db,
>  		    "Failed to allocate memory for dport.\n");
>  		return -ENOMEM;
>  	}
>  
>  	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
>  	    bsg_job->request_payload.sg_cnt, dd, sizeof(*dd));
>  
>  	rval = qla26xx_dport_diagnostics(
>  	    vha, dd->buf, sizeof(dd->buf), dd->options);

[Severity: High]
This is a pre-existing issue, but does the hardware diagnostics function
clobber its own DMA buffers?

Inside qla26xx_dport_diagnostics() in drivers/scsi/qla2xxx/qla_mbx.c, the code
does this:

qla26xx_dport_diagnostics(...) {
    ...
    dd_dma = dma_map_single(&vha->hw->pdev->dev, dd_buf, size, DMA_FROM_DEVICE);
    ...
    memset(dd_buf, 0, size);
    ...
}

Since ownership has already been transferred to the device via dma_map_single(),
could this memset() overwrite the hardware's DMA data on non-coherent
architectures when the CPU cache lines are evicted or written back?

[Severity: High]
This is a pre-existing issue, but do other functions in this file suffer from
a similar stack-based info leak?

Functions like qla2x00_read_fru_status() allocate an uninitialized stack
buffer:

qla2x00_read_fru_status(...) {
    uint8_t bsg[DMA_POOL_SIZE];
    struct qla_status_reg *sr = (void *)bsg;
    ...
    sg_copy_to_buffer(..., sr, sizeof(*sr));
    ...
    sg_copy_from_buffer(..., sr, sizeof(*sr));
}

If the user provides a payload smaller than the structure size,
sg_copy_to_buffer() leaves the remainder of the buffer uninitialized.

When sg_copy_from_buffer() copies the entire structure size back to the
user's reply payload, couldn't this leak uninitialized kernel stack memory
to user space, much like the heap leak fixed in this patch?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=58

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 51/60] scsi: qla2xxx: edif: Fix NULL pointer deref in RX SA delete check
  2026-06-12  9:53 ` [PATCH v2 51/60] scsi: qla2xxx: edif: Fix NULL pointer deref in RX SA delete check Nilesh Javali
@ 2026-06-12 11:43   ` sashiko-bot
  2026-06-12 13:04   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:43 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] The patch adds a NULL check for `cmd` to prevent a crash when a late firmware status completion arrives for an already returned command, but it fails to account for handle re-use by non-SCSI commands (e.g., BSG or ELS commands), which will bypass the check and still cause an out-of-bounds read or crash due to union aliasing.
--

commit 8ccf27493c42b83e13fc3d263bc951bcaddb4472
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: edif: Fix NULL pointer deref in RX SA delete check

This commit fixes a NULL pointer dereference in
qla_chk_edif_rx_sa_delete_pending() by adding an early return if the command
pointer is NULL. This prevents a crash when firmware posts a late status
completion for a command that has already been returned or aborted.

> diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
> index f8bc248e5d18e..c8889ea199d33 100644
> --- a/drivers/scsi/qla2xxx/qla_edif.c
> +++ b/drivers/scsi/qla2xxx/qla_edif.c
> @@ -3543,6 +3543,9 @@ void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
>  	uint32_t handle;
>  	uint16_t sa_index;
>  
> +	if (!cmd)
> +		return;
> +

[Severity: High]
This isn't a bug introduced by this patch, but does this function safely
handle non-SCSI commands?

In qla2x00_status_entry(), if the firmware sends an unexpected STATUS_TYPE
IOCB for a non-SCSI handle (such as a BSG or ELS command), this function is
called without verifying if sp->type is SRB_SCSI_CMD.

Because GET_CMD_SP(sp) expands to sp->u.scmd.cmd, accessing this union field
for a non-SCSI command could yield a non-NULL garbage pointer. This would
bypass the new check and potentially cause an out-of-bounds read or crash
when dereferencing cmd->sc_data_direction immediately after.

Could this be protected by validating sp->type == SRB_SCSI_CMD before trying
to evaluate the SCSI command pointer?

>  	handle = (uint32_t)LSW(sts24->handle);
>  
>  	/* find out if this status iosb is for a scsi read */

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=51

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 60/60] scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions()
  2026-06-12  9:53 ` [PATCH v2 60/60] scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions() Nilesh Javali
@ 2026-06-12 11:45   ` sashiko-bot
  2026-06-12 13:13   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 11:45 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

Pre-existing issues:
- [Critical] Lack of bounds checking on `i2c->length` leads to severe kernel stack and DMA heap buffer overflows.
- [High] The patch bounds-checks `count` but fails to verify that the user's request payload actually contains enough data for the requested `count`. This allows the function to use uninitialized kernel stack memory.
- [High] Short user payloads leak uninitialized kernel stack memory directly to user space in FRU status handlers.
- [High] The DMA pool buffer `sfp` is allocated without being zeroed, leaking uninitialized kernel DMA memory to the SFP device due to a user-controlled length override.
--

commit 5c0e5610a345e0804d665fbbbd2f23719341a171
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions()

qla2x00_update_fru_versions() copies the user-supplied BSG request into
a fixed 256-byte stack buffer (bsg[DMA_POOL_SIZE]) and then iterates
list->count times over the qla_image_version array embedded in that
buffer, advancing the image pointer each iteration. count is taken
directly from user input with no upper bound, while only
(DMA_POOL_SIZE - sizeof(list->count)) / sizeof(struct qla_image_version)
= 6 entries actually fit. A larger count walks the image pointer off the
end of the stack buffer, reading adjacent kernel stack memory and
sending it to the device via qla2x00_write_sfp().

Reject requests whose declared count does not fit in the buffer.

> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index 22be6c822ddae..bcca4ef3c23e1 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -1929,6 +1929,13 @@ qla2x00_update_fru_versions(struct bsg_job *bsg_job)
>  
>  	image = list->version;
>  	count = list->count;
> +
> +	if (struct_size(list, version, count) > sizeof(bsg)) {

[Severity: High]
This isn't a bug introduced by this patch, but the patch fails to properly
prevent uninitialized stack memory use.

If the user provides a short payload, sg_copy_to_buffer() leaves the trailing
portions of the uninitialized bsg array untouched:

	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
	    bsg_job->request_payload.sg_cnt, list, sizeof(bsg));

Because struct_size(list, version, count) is only checked against
sizeof(bsg), not the actual payload length, does this still allow the loop to
read uninitialized stack memory and write it to the SFP flash?

[Severity: High]
This is a pre-existing issue, but while we are looking at
qla2x00_update_fru_versions(), the sfp buffer is allocated without zeroing:

	void *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);

If the user sets BIT_0 in image->field_address.option, qla2x00_write_sfp()
overrides the transfer length to the first byte of sfp (which is user
controlled):

drivers/scsi/qla2xxx/qla_mbx.c:qla2x00_write_sfp() {
...
	if (opt & BIT_0)
		len = *sfp;
...
}

Could this cause the hardware to read past the initialized 36 bytes and leak
up to 219 bytes of uninitialized DMA heap memory to the device flash?

> +		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
> +		    EXT_STATUS_INVALID_PARAM;
> +		goto dealloc;
> +	}
> +
>  	while (count--) {
>  		memcpy(sfp, &image->field_info, sizeof(image->field_info));
>  		rval = qla2x00_write_sfp(vha, sfp_dma, sfp,

[Severity: Critical]
This isn't a bug introduced by this patch, but looking at the same file, there
appears to be a severe bounds checking issue in qla2x00_write_i2c() and
qla2x00_read_i2c().

The user-controlled i2c->length is an unbounded 16-bit integer passed directly
to memcpy():

drivers/scsi/qla2xxx/qla_bsg.c:qla2x00_write_i2c() {
...
	memcpy(sfp, i2c->buffer, i2c->length);
...
}

drivers/scsi/qla2xxx/qla_bsg.c:qla2x00_read_i2c() {
...
	memcpy(i2c->buffer, sfp, i2c->length);
...
}

Since sfp is a 256-byte buffer and i2c->buffer points to the 256-byte bsg
stack array, doesn't this cause a massive out-of-bounds read and stack/heap
buffer overflow if a large length up to 65535 is provided?

[Severity: High]
This is a pre-existing issue, but similar to the short payload issue above,
qla2x00_read_fru_status() also seems to leak uninitialized stack memory.

If the user provides a short payload, sg_copy_to_buffer() leaves the sr
buffer uninitialized:

drivers/scsi/qla2xxx/qla_bsg.c:qla2x00_read_fru_status() {
...
	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
	    bsg_job->request_payload.sg_cnt, sr, sizeof(*sr));
...
}

Then sg_copy_from_buffer() blindly copies it back to the user's reply payload:

	sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
	    bsg_job->reply_payload.sg_cnt, sr, sizeof(*sr));

Does this directly leak kernel stack memory to userspace?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=60

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 28/60] scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters
  2026-06-12  9:53 ` [PATCH v2 28/60] scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters Nilesh Javali
  2026-06-12 10:54   ` sashiko-bot
@ 2026-06-12 11:47   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 11:47 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> 29xx adapters use 128-byte response queue entries
> (sts_cont_entry_ext_t) instead of 64-byte (sts_cont_entry_t).  Update
> all status continuation IOCB processing paths to branch on
> IS_QLA29XX() and use the correct entry type and data payload size.
> 
> The affected functions are __qla_copy_purex_to_buffer(),
> qla27xx_copy_multiple_pkt(), qla2x00_status_cont_entry(), and their
> call sites in qla2x00_process_response_entry() and
> qla24xx_process_response_queue().
> 
> Change qla2x00_status_cont_entry() to accept void * so callers no
> longer need an explicit cast and the function can internally select the
> right structure based on the adapter type.
> 
> Add BUILD_BUG_ON for sts_cont_entry_ext_t size (128 bytes).
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_isr.c | 192 +++++++++++++++++++++++----------
>   drivers/scsi/qla2xxx/qla_os.c  |   1 +
>   2 files changed, 139 insertions(+), 54 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
> index e95fb0e59f38..c18ee2459f5b 100644
> --- a/drivers/scsi/qla2xxx/qla_isr.c
> +++ b/drivers/scsi/qla2xxx/qla_isr.c
> @@ -19,7 +19,7 @@
>   
>   static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
>   static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
> -static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
> +static void qla2x00_status_cont_entry(struct rsp_que *, void *);
>   static int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
>   	sts_entry_t *);
>   static void qla27xx_process_purex_fpin(struct scsi_qla_host *vha,

Using a void pointer is always awkward as it doesn't allow for an 
out-of-bounds check.

I would rather add a 'size' field, too, as then the size of 'void' 
pointer would be known and one doesn't need to sprinkle the code with
IS_QLA29XX() calls.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 29/60] scsi: qla2xxx: Update handling of status entries for 29xx series
  2026-06-12  9:53 ` [PATCH v2 29/60] scsi: qla2xxx: Update handling of status entries for 29xx series Nilesh Javali
  2026-06-12 10:44   ` sashiko-bot
@ 2026-06-12 12:12   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:12 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Modify the handling of status entries in the qla2xxx driver to
> accommodate the extended structure for the 29xx series. Changes include
> updating function signatures to accept a generic pointer for status
> packets, and adjusting the logic to differentiate between the standard
> and extended status entries. This ensures proper processing of
> completion statuses and error handling for the new hardware
> capabilities.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_edif.c   |  15 ++--
>   drivers/scsi/qla2xxx/qla_gbl.h    |   2 +-
>   drivers/scsi/qla2xxx/qla_inline.h |  45 ++++++++++++
>   drivers/scsi/qla2xxx/qla_isr.c    | 111 +++++++++++++++++++-----------
>   drivers/scsi/qla2xxx/qla_mbx.c    |  28 ++++----
>   drivers/scsi/qla2xxx/qla_os.c     |   1 +
>   6 files changed, 143 insertions(+), 59 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 30/60] scsi: qla2xxx: Enhance ct_entry_24xx_ext iocb handling for 29xx series
  2026-06-12  9:53 ` [PATCH v2 30/60] scsi: qla2xxx: Enhance ct_entry_24xx_ext iocb handling " Nilesh Javali
@ 2026-06-12 12:14   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:14 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Refine the handling of I/O control blocks (IOCBs) for the 29xx series
> by introducing support for the extended structure ct_entry_24xx_ext.
> Update function signatures to accept a generic pointer for IOCB packets,
> differentiating between standard and extended structures, and ensuring
> proper initialization and processing of command and response data.
> Additionally, the size check for the extended structure is added to
> maintain integrity.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_gs.c   | 156 ++++++++++++++++++++++++--------
>   drivers/scsi/qla2xxx/qla_iocb.c |  78 ++++++++++------
>   drivers/scsi/qla2xxx/qla_os.c   |   1 +
>   3 files changed, 168 insertions(+), 67 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 31/60] scsi: qla2xxx: Enhance purex_entry handling for 29xx series
  2026-06-12  9:53 ` [PATCH v2 31/60] scsi: qla2xxx: Enhance purex_entry " Nilesh Javali
  2026-06-12 10:54   ` sashiko-bot
@ 2026-06-12 12:16   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:16 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Update function signatures and internal logic across qla_edif.c,
> qla_isr.c, and qla_os.c to accept a generic pointer for packet data and
> differentiate between standard purex_entry_24xx and the extended
> purex_entry_24xx_ext structures based on IS_QLA29XX().
> 
> This ensures proper initialization and processing of command and response
> data for both 64-byte and 128-byte PUREX IOCBs across all ELS paths
> including auth_els, RDP, copy_std_pkt, copy_multiple_pkt, consume_iocb,
> and copy_purex_to_buffer.
> 
> Where the two layouts overlap at byte-identical offsets (entry_count,
> frame_size, nport_handle, rx_xchg_addr, ox_id, status_flags,
> trunc_frame_size, s_id, d_id, els_frame_payload base, and
> response_t::signature), use a single struct purex_entry_24xx * view to
> avoid duplicating read paths.  Branch only where field encoding differs:
> vp_idx (u8 at offset 6 in 24xx vs __le16 at offsets 6-7 in 29xx) and
> els_frame_payload[] array length (20 vs 84 bytes, handled via a
> sizeof_field()-based payload_size local).
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_def.h  |  3 +-
>   drivers/scsi/qla2xxx/qla_edif.c | 68 +++++++++++++++++-------
>   drivers/scsi/qla2xxx/qla_isr.c  | 94 ++++++++++++++++++++++++++-------
>   drivers/scsi/qla2xxx/qla_os.c   | 24 +++++++--
>   4 files changed, 145 insertions(+), 44 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
> index 0bbe2bae7101..3e2f1d8ba904 100644
> --- a/drivers/scsi/qla2xxx/qla_def.h
> +++ b/drivers/scsi/qla2xxx/qla_def.h
> @@ -5000,6 +5000,7 @@ struct active_regions {
>   #define QLA_SET_DATA_RATE_LR	2 /* Set speed and initiate LR */
>   
>   #define QLA_DEFAULT_PAYLOAD_SIZE	64
> +#define QLA_MAX_IOCB_SIZE		128
>   /*
>    * This item might be allocated with a size > sizeof(struct purex_item).
>    * The "size" variable gives the size of the payload (which
> @@ -5014,7 +5015,7 @@ struct purex_item {
>   	atomic_t in_use;
>   	uint16_t size;
>   	struct {
> -		uint8_t iocb[64];
> +		u8 iocb[QLA_MAX_IOCB_SIZE];
>   	} iocb;
>   };
>   
> diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
> index b05f8e0b705e..f8bc248e5d18 100644
> --- a/drivers/scsi/qla2xxx/qla_edif.c
> +++ b/drivers/scsi/qla2xxx/qla_edif.c
> @@ -2534,7 +2534,7 @@ qla24xx_sa_replace_iocb(srb_t *sp, struct sa_update_28xx *sa_update_iocb)
>   
>   void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
>   {
> -	struct purex_entry_24xx *p = *pkt;
> +	struct qla_hw_data *ha = vha->hw;
>   	struct enode		*ptr;
>   	int		sid;
>   	u16 totlen;
> @@ -2544,26 +2544,58 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
>   	struct fc_port *fcport;
>   	struct qla_els_pt_arg a;
>   	be_id_t beid;
> +	__le16 nport_handle;
> +	__le32 rx_xchg_addr;
> +	__le16 ox_id;
> +	__le16 frame_size, status_flags, trunc_frame_size;
> +	uint8_t s_id[3], d_id[3];
> +	uint8_t vp_idx;
>   
>   	memset(&a, 0, sizeof(a));
>   
> +	/*
> +	 * purex_entry_24xx_ext (29xx) overlays purex_entry_24xx for every
> +	 * field touched here -- nport_handle, rx_xchg_addr, ox_id, frame_size,
> +	 * status_flags, trunc_frame_size, s_id[3], d_id[3] -- with only
> +	 * vp_idx differing in width (u8 at offset 6 vs __le16 at offsets 6-7,
> +	 * with reserved2 at offset 7 in the 24xx layout). So all reads but
> +	 * vp_idx go through a single struct purex_entry_24xx * view.
> +	 */
> +	{
> +		struct purex_entry_24xx *p = *pkt;
> +
> +		nport_handle = p->nport_handle;
> +		rx_xchg_addr = p->rx_xchg_addr;
> +		ox_id = p->ox_id;
> +		frame_size = p->frame_size;
> +		status_flags = p->status_flags;
> +		trunc_frame_size = p->trunc_frame_size;
> +		memcpy(s_id, p->s_id, sizeof(s_id));
> +		memcpy(d_id, p->d_id, sizeof(d_id));
> +		if (IS_QLA29XX(ha))
> +			vp_idx = le16_to_cpu(((struct purex_entry_24xx_ext *)
> +					      *pkt)->vp_idx);
> +		else
> +			vp_idx = p->vp_idx;
> +	}
> +

And these braces are here ... why?

Please drop them.

Otherwise looks okay.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 32/60] scsi: qla2xxx: Update handling of ELS IOCBs for 29xx series
  2026-06-12  9:53 ` [PATCH v2 32/60] scsi: qla2xxx: Update handling of ELS IOCBs " Nilesh Javali
@ 2026-06-12 12:33   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:33 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Update ELS IOCB handling to support the extended 128-byte
> els_entry_24xx_ext structure used by 29xx series adapters.
> 
> Change the signatures of qla24xx_els_logo_iocb(), qla_els_pt_iocb(),
> and qla24xx_els_iocb() to accept a generic void pointer, enabling
> differentiation between standard and extended ELS structures at
> runtime.
> 
> Introduce a static inline helper qla_els_set_vp_sof() in qla_inline.h
> that centralises the 24xx-vs-29xx vp_index/sof_type encoding: the 24xx
> layout uses separate u8 vp_index + u8 sof_type (EST_SOFI3), while
> 29xx uses a __le16 with bitfields (vp_index:9 / sof_type:4 /
> ELS_EXT_EST_SOFI3).  All ELS issue paths now call this helper instead
> of open-coding the branch, including the RDP response path in qla_os.c.
> 
> In qla2x00_start_sp(), collapse the IS_QLA29XX() branch for the
> handle assignment in SRB_ELS_CMD_HST_NOLOGIN: els_entry_24xx::handle
> and els_entry_24xx_ext::handle are both u32 at offset 4, so a single
> 24xx-view write is layout-compatible with both strides.
> 
> DMA allocations in qla24xx_process_abts() and
> qla24xx_process_purex_rdp() are updated to use the correct size for
> the adapter type.  A BUILD_BUG_ON is added to verify the extended
> structure size.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_gbl.h    |  2 +-
>   drivers/scsi/qla2xxx/qla_inline.h | 28 ++++++++++++++++++++++++++++
>   drivers/scsi/qla2xxx/qla_iocb.c   | 28 ++++++++++++++++++----------
>   drivers/scsi/qla2xxx/qla_isr.c    | 26 ++++++++++++++++++--------
>   drivers/scsi/qla2xxx/qla_os.c     | 31 ++++++++++++++++++++-----------
>   5 files changed, 85 insertions(+), 30 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 33/60] scsi: qla2xxx: Add size check for ELS status entry layout on 29xx
  2026-06-12  9:53 ` [PATCH v2 33/60] scsi: qla2xxx: Add size check for ELS status entry layout on 29xx Nilesh Javali
@ 2026-06-12 12:34   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:34 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Add a BUILD_BUG_ON in qla2x00_module_init() to validate that struct
> els_sts_entry_24xx_ext is 128 bytes, matching the 29xx firmware IOCB
> size.
> 
> The extended layout (29xx) overlays the base els_sts_entry_24xx for
> every field read in qla24xx_els_ct_entry(): comp_status,
> total_byte_count, error_subcode_1/2, d_id[], s_id[], and
> control_flags all sit at byte-identical offsets in both structs.  Only
> vp_index/sof_type at offset 14-15 differs (bit-packed differently in
> the ext variant), but that field is write-only on the issue path and
> never read in this completion handler.
> 
> Add a docblock at the top of qla24xx_els_ct_entry() documenting this
> layout property.  Improve a few log messages for clarity.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_isr.c | 31 +++++++++++++++++++++++--------
>   drivers/scsi/qla2xxx/qla_os.c  |  1 +
>   2 files changed, 24 insertions(+), 8 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 34/60] scsi: qla2xxx: Add 29xx extended logio IOCB support
  2026-06-12  9:53 ` [PATCH v2 34/60] scsi: qla2xxx: Add 29xx extended logio IOCB support Nilesh Javali
@ 2026-06-12 12:36   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:36 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> The 29xx series uses a wider IOCB stride (128 bytes vs 64 bytes).
> The logio_entry_24xx_ext layout extends logio_entry_24xx with a
> wider vp_index field (__le16 vs u8) while keeping all other
> read-side fields (comp_status, io_parameter[0..10], entry_status)
> at identical offsets and widths.
> 
> Update the logio IOCB builder functions (qla24xx_login_iocb,
> qla24xx_logout_iocb, qla24xx_prli_iocb, qla24xx_prlo_iocb,
> qla24xx_adisc_iocb) to accept a void pointer and dispatch the
> vp_index write through IS_QLA29XX(), using an inline cast to the
> extended layout at the single write site.
> 
> In the completion handler qla24xx_logio_entry(), accept a void
> pointer and read through a single logio_entry_24xx view since all
> accessed fields sit at the same offsets in both layouts.  Use the
> qla_req_entry_size() helper for the dump buffer size.
> 
> In qla24xx_login_fabric() and qla24xx_fabric_logout(), allocate
> through a void pointer from the DMA pool and dispatch vp_index
> via the same inline-cast pattern.
> 
> Add a BUILD_BUG_ON for logio_entry_24xx_ext to enforce the 128-byte
> size invariant at compile time.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_iocb.c | 48 ++++++++++++++++++++++++++-------
>   drivers/scsi/qla2xxx/qla_isr.c  | 41 ++++++++++++++++------------
>   drivers/scsi/qla2xxx/qla_mbx.c  | 35 ++++++++++++++++--------
>   drivers/scsi/qla2xxx/qla_os.c   |  1 +
>   4 files changed, 87 insertions(+), 38 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
> index 45d6837100ad..d0d3a56affdc 100644
> --- a/drivers/scsi/qla2xxx/qla_iocb.c
> +++ b/drivers/scsi/qla2xxx/qla_iocb.c
> @@ -2488,8 +2488,9 @@ qla2x00_alloc_iocbs(struct scsi_qla_host *vha, srb_t *sp)
>   }
>   
>   static void
> -qla24xx_prli_iocb(srb_t *sp, struct logio_entry_24xx *logio)
> +qla24xx_prli_iocb(srb_t *sp, void *pkt)
>   {
> +	struct logio_entry_24xx *logio = pkt;
>   	struct srb_iocb *lio = &sp->u.iocb_cmd;
>   
>   	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
> @@ -2516,12 +2517,17 @@ qla24xx_prli_iocb(srb_t *sp, struct logio_entry_24xx *logio)
>   	logio->port_id[0] = sp->fcport->d_id.b.al_pa;
>   	logio->port_id[1] = sp->fcport->d_id.b.area;
>   	logio->port_id[2] = sp->fcport->d_id.b.domain;
> -	logio->vp_index = sp->vha->vp_idx;
> +	if (IS_QLA29XX(sp->vha->hw))
> +		((struct logio_entry_24xx_ext *)pkt)->vp_index =
> +		    cpu_to_le16(sp->vha->vp_idx);
> +	else
> +		logio->vp_index = sp->vha->vp_idx;
>   }
>   

This really cries out for a helper; the same code snippet is used 
throughout the patch.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 35/60] scsi: qla2xxx: Enhance task management IOCB handling for 29xx series
  2026-06-12  9:53 ` [PATCH v2 35/60] scsi: qla2xxx: Enhance task management IOCB handling for 29xx series Nilesh Javali
  2026-06-12 11:13   ` sashiko-bot
@ 2026-06-12 12:37   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:37 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Update qla24xx_tm_iocb() and __qla24xx_issue_tmf() to support the
> extended task management structure (tsk_mgmt_entry_ext) for 29xx
> adapters.
> 
> tsk_mgmt_entry_ext overlays tsk_mgmt_entry through control_flags
> (offsets 0-27 are byte-identical): entry_type, entry_count, handle,
> nport_handle, timeout, lun and control_flags sit at the same offsets
> and widths.  The layouts diverge only after that point:
> 
>    - the 24xx layout has port_id[3] + u8 vp_index;
>    - the ext layout has __le16 vp_index and no port_id.
> 
> Factor the common IOCB header writes through a single tsk_mgmt_entry *
> view and branch on IS_QLA29XX() only for the diverging port_id /
> vp_index assignments.  Change qla24xx_tm_iocb() to accept void *pkt
> to allow casting to either structure type.
> 
> Add tsk_ext member to the tsk_mgmt_cmd union and a BUILD_BUG_ON size
> check for the 128-byte extended structure.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_iocb.c | 31 ++++++++++++++++++++++---------
>   drivers/scsi/qla2xxx/qla_mbx.c  | 18 ++++++++++++++----
>   drivers/scsi/qla2xxx/qla_os.c   |  1 +
>   3 files changed, 37 insertions(+), 13 deletions(-)
> 

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 36/60] scsi: qla2xxx: Add abort command handling for 29xx series
  2026-06-12  9:53 ` [PATCH v2 36/60] scsi: qla2xxx: Add abort command " Nilesh Javali
  2026-06-12 11:15   ` sashiko-bot
@ 2026-06-12 12:38   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:38 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Extend the abort-IOCB code path to support the 29xx extended
> abort_entry_24xx_ext structure alongside the existing
> abort_entry_24xx.
> 
> The two layouts overlay byte-for-byte through req_que_no
> (offsets 0-17): entry_status (offset 3), the
> nport_handle/comp_status union (offset 8), and options (offset 10)
> sit at identical positions in both.  After that they diverge: the
> 24xx variant carries reserved_1[30], port_id[3], and a u8 vp_index
> at offsets 48-51, while the ext variant places a __le16 vp_index at
> offset 18 and drops port_id.  The drv / fw unions live at offset 56
> in the 24xx layout but offset 24 in ext.
> 
> Leverage this overlap by using a single struct abort_entry_24xx *
> view for the common header writes (entry_type, count, handle,
> nport_handle, handle_to_abort, req_que_no) and completion-status
> reads (entry_status, comp_status), branching on IS_QLA29XX() only
> where the layouts genuinely diverge:
> 
>    - port_id (24xx-only) and vp_index width on the issue path
>      (qla24xx_abort_iocb in qla_iocb.c, qla24xx_abort_command in
>      qla_mbx.c);
>    - drv / fw union access in qla_nvme_abort_set_option /
>      qla_nvme_abort_process_comp_status (qla_nvme.c);
>    - completion comp_status read in qla24xx_abort_iocb_entry
>      (qla_isr.c) is stride-agnostic -- no IS_QLA29XX dispatch
>      needed.
> 
> Function signatures in qla_nvme_abort_set_option(),
> qla_nvme_abort_process_comp_status(), qla24xx_abort_iocb(), and
> qla24xx_abort_iocb_entry() are widened to accept void * so both
> struct variants can be passed through.  memset() uses
> qla_req_entry_size(ha) to match the ring-slot size.  Response
> status checking now reads comp_status instead of nport_handle.  A
> BUILD_BUG_ON verifies abort_entry_24xx_ext is 128 bytes.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_gbl.h  |  6 ++--
>   drivers/scsi/qla2xxx/qla_iocb.c | 52 ++++++++++++++++++++-----------
>   drivers/scsi/qla2xxx/qla_isr.c  | 14 ++++++---
>   drivers/scsi/qla2xxx/qla_mbx.c  | 45 ++++++++++++++++++---------
>   drivers/scsi/qla2xxx/qla_nvme.c | 54 +++++++++++++++++++++++++--------
>   drivers/scsi/qla2xxx/qla_os.c   |  1 +
>   6 files changed, 120 insertions(+), 52 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 37/60] scsi: qla2xxx: Enhance ABTS processing for 29xx series
  2026-06-12  9:53 ` [PATCH v2 37/60] scsi: qla2xxx: Enhance ABTS processing " Nilesh Javali
@ 2026-06-12 12:41   ` Hannes Reinecke
  2026-06-12 15:12   ` sashiko-bot
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:41 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Use extended ABTS entry structures (abts_entry_24xx_ext) for 29xx
> series adapters to properly handle the larger 128-byte IOCB format.
> 
> Introduce type-generic macros (QLA_LOG_ABTS_RCV, QLA_BUILD_ABTS_BA_ACC,
> QLA_LOG_ISSUE_ABTS_RSP) that leverage the shared field names between
> abts_entry_24xx and abts_entry_24xx_ext to avoid code duplication.
> Branch on IS_QLA29XX() for receive logging, exchange termination, and
> BA_ACC response construction, with each path passing the correctly
> typed pointer to the shared macros. The sof_type handling difference
> (direct for 29xx bitfield vs & 0xf0 mask for legacy) is parameterized
> through the sof_val macro argument.
> 
> Add BUILD_BUG_ON size check for struct abts_entry_24xx_ext.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_isr.c | 167 ++++++++++++++++++++-------------
>   drivers/scsi/qla2xxx/qla_os.c  |   1 +
>   2 files changed, 104 insertions(+), 64 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 38/60] scsi: qla2xxx: Update VP control IOCB handling for 29xx series
  2026-06-12  9:53 ` [PATCH v2 38/60] scsi: qla2xxx: Update VP control IOCB handling " Nilesh Javali
@ 2026-06-12 12:45   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:45 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Update VP control IOCB command and response handling to support the
> 29xx series adapters, which use the 128-byte vp_ctrl_entry_24xx_ext
> layout.
> 
> Change the qla25xx_ctrlvp_iocb() and qla_ctrlvp_completed() function
> signatures from typed struct pointers to void *, since callers already
> pass a generic ring-slot pointer.  Both the standard 64-byte
> vp_ctrl_entry_24xx and the 128-byte vp_ctrl_entry_24xx_ext are
> layout-identical for every field touched in these helpers (entry_type,
> handle, entry_count, command, vp_count, vp_idx_map, entry_status,
> comp_status, vp_idx_failed), so a single struct vp_ctrl_entry_24xx *
> view handles both adapter families without an IS_QLA29XX() branch.
> 
> Add a BUILD_BUG_ON size check for the extended structure.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_iocb.c | 23 ++++++++++++++++-------
>   drivers/scsi/qla2xxx/qla_isr.c  | 13 +++++++++----
>   drivers/scsi/qla2xxx/qla_os.c   |  1 +
>   3 files changed, 26 insertions(+), 11 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 39/60] scsi: qla2xxx: Add build-time size check for VP config IOCB layout
  2026-06-12  9:53 ` [PATCH v2 39/60] scsi: qla2xxx: Add build-time size check for VP config IOCB layout Nilesh Javali
@ 2026-06-12 12:45   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:45 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Add a BUILD_BUG_ON for struct vp_config_entry_24xx_ext to verify its
> 128-byte size at compile time alongside the existing 64-byte check for
> struct vp_config_entry_24xx.
> 
> Document in qla24xx_modify_vp_config() that the ext variant overlays
> the base 24xx layout for the first 64 bytes (all fields this helper
> reads and writes), so the IOCB can be built through a single struct
> vp_config_entry_24xx pointer regardless of the adapter's IOCB stride.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_mbx.c | 8 +++++++-
>   drivers/scsi/qla2xxx/qla_os.c  | 1 +
>   2 files changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
> index ea39f3793296..bdf03d92e552 100644
> --- a/drivers/scsi/qla2xxx/qla_mbx.c
> +++ b/drivers/scsi/qla2xxx/qla_mbx.c
> @@ -4372,6 +4372,13 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
>   		return QLA_MEMORY_ALLOC_FAILED;
>   	}
>   
> +	/*
> +	 * vp_config_entry_24xx_ext overlays vp_config_entry_24xx for the
> +	 * full 64-byte 24xx layout (the ext variant merely appends fields
> +	 * at offset 64+ which this helper never touches), so the IOCB is
> +	 * built and inspected through a single struct vp_config_entry_24xx
> +	 * pointer regardless of adapter stride.
> +	 */
>   	vpmod->entry_type = VP_CONFIG_IOCB_TYPE;
>   	vpmod->entry_count = 1;
>   	vpmod->command = VCT_COMMAND_MOD_ENABLE_VPS;
> @@ -4400,7 +4407,6 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
>   		    le16_to_cpu(vpmod->comp_status));
>   		rval = QLA_FUNCTION_FAILED;
>   	} else {
> -		/* EMPTY */
>   		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10c0,
>   		    "Done %s.\n", __func__);
>   		fc_vport_set_state(vha->fc_vport, FC_VPORT_INITIALIZING);
> diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
> index bf5f3b16bdae..397f2ffa56d1 100644
> --- a/drivers/scsi/qla2xxx/qla_os.c
> +++ b/drivers/scsi/qla2xxx/qla_os.c
> @@ -8435,6 +8435,7 @@ qla2x00_module_init(void)
>   	BUILD_BUG_ON(sizeof(struct verify_chip_rsp_84xx) != 52);
>   	BUILD_BUG_ON(sizeof(struct vf_evfp_entry_24xx) != 56);
>   	BUILD_BUG_ON(sizeof(struct vp_config_entry_24xx) != 64);
> +	BUILD_BUG_ON(sizeof(struct vp_config_entry_24xx_ext) != 128);
>   	BUILD_BUG_ON(sizeof(struct vp_ctrl_entry_24xx) != 64);
>   	BUILD_BUG_ON(sizeof(struct vp_ctrl_entry_24xx_ext) != 128);
>   	BUILD_BUG_ON(sizeof(struct vp_rpt_id_entry_24xx) != 64);

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 40/60] scsi: qla2xxx: Add size check for extended VP report ID entry
  2026-06-12  9:53 ` [PATCH v2 40/60] scsi: qla2xxx: Add size check for extended VP report ID entry Nilesh Javali
  2026-06-12 11:05   ` sashiko-bot
@ 2026-06-12 12:46   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:46 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Add reserved_end[64] padding to bring the struct to 128 bytes, matching
> the hardware IOCB stride.  Change qla24xx_report_id_acquisition() to
> accept a void pointer and extract vp_idx and vp_status from the extended
> structure on 29xx series adapters, maintaining data integrity for the
> larger IOCB format.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_fw29.h |  1 +
>   drivers/scsi/qla2xxx/qla_gbl.h  |  3 +--
>   drivers/scsi/qla2xxx/qla_isr.c  |  3 +--
>   drivers/scsi/qla2xxx/qla_mbx.c  | 32 +++++++++++++++++++++-----------
>   drivers/scsi/qla2xxx/qla_os.c   |  1 +
>   5 files changed, 25 insertions(+), 15 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 41/60] scsi: qla2xxx: Unify NVMe IOCB build path for 29xx and legacy adapters
  2026-06-12  9:53 ` [PATCH v2 41/60] scsi: qla2xxx: Unify NVMe IOCB build path for 29xx and legacy adapters Nilesh Javali
  2026-06-12 11:02   ` sashiko-bot
@ 2026-06-12 12:49   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:49 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> The cmd_nvme and cmd_nvme_ext structs share an identical header layout
> through byte_count, so the IOCB build code in qla2x00_start_nvme_mq()
> need not duplicate all common-field writes in separate IS_QLA29XX(ha)
> and legacy blocks.
> 
> Initialize the cmd_pkt and cmd_pkt_ext pointers to NULL, then write
> common header fields through a single cmd_pkt (struct cmd_nvme *) view,
> branching on IS_QLA29XX(ha) only where the layouts genuinely diverge:
> 
>    - port_id[] vs __le16 vp_index
>    - single inline DSD vs NUM_NVME_DSDS DSD array
> 
> Add BUILD_BUG_ON checks that enforce the layout contract at compile
> time so any future struct change that breaks the common-header overlap
> fails the build rather than silently corrupting IOCBs.
> 
> Also add a BUILD_BUG_ON size check for struct cmd_nvme_ext during
> module initialization and a reserved_end field to
> vp_rpt_id_entry_24xx_ext to ensure proper memory allocation and data
> integrity for 29xx series adapters.
> 
> No functional change.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_nvme.c | 58 ++++++++++++++++++++++++---------
>   drivers/scsi/qla2xxx/qla_os.c   |  1 +
>   2 files changed, 43 insertions(+), 16 deletions(-)
> 
Please merge it with the patch introducing the change.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 42/60] scsi: qla2xxx: Add LS4 pass-through IOCB handling for 29xx series
  2026-06-12  9:53 ` [PATCH v2 42/60] scsi: qla2xxx: Add LS4 pass-through IOCB handling for 29xx series Nilesh Javali
@ 2026-06-12 12:50   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:50 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> From: Manish Rangankar <mrangankar@marvell.com>
> 
> Extend the LS4 pass-through IOCB handling to support the 128-byte
> pt_ls4_request_ext layout used by 29xx series adapters.  The extension
> grows inline DSD capacity from 2 to 5 entries.  Function signatures are
> widened to void * so both layouts can be passed without casts.
> 
> pt_ls4_request_ext overlays pt_ls4_request through exchange_address
> (offsets 0-27 are byte-identical), so common-header writes go through a
> single struct pt_ls4_request * view; only the divergent fields
> (vp_index width, tx_/rx_byte_count offset, dsd[] base) are branched.
> 
> Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_fw29.h | 37 +++++++++++++++++
>   drivers/scsi/qla2xxx/qla_iocb.c | 73 ++++++++++++++++++++++-----------
>   drivers/scsi/qla2xxx/qla_isr.c  |  9 ++--
>   drivers/scsi/qla2xxx/qla_nvme.c | 64 +++++++++++++++++++----------
>   drivers/scsi/qla2xxx/qla_nvme.h |  4 +-
>   drivers/scsi/qla2xxx/qla_os.c   |  1 +
>   6 files changed, 137 insertions(+), 51 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 43/60] scsi: qla2xxx: Convert NVMe ring advance to use qla_req_ring_advance()
  2026-06-12  9:53 ` [PATCH v2 43/60] scsi: qla2xxx: Convert NVMe ring advance to use qla_req_ring_advance() Nilesh Javali
@ 2026-06-12 12:52   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:52 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> Replace the open-coded IS_QLA29XX() ring_ext_ptr/ring_ptr advancement
> in qla2x00_start_nvme_mq() with the qla_req_ring_advance() helper,
> removing 16 lines of duplicated logic.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_nvme.c | 17 +----------------
>   1 file changed, 1 insertion(+), 16 deletions(-)
> 
???

Why didn't you do that initially?

Please merge with the patch introducing the change.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 44/60] scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support
  2026-06-12  9:53 ` [PATCH v2 44/60] scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support Nilesh Javali
  2026-06-12 11:16   ` sashiko-bot
@ 2026-06-12 12:53   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:53 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> From: Manish Rangankar <mrangankar@marvell.com>
> 
> Extend qla2xxx BSG command handling to recognize QLA29xx adapters and
> align feature availability with hardware capabilities.
> 
> Allow QLA29xx in paths previously restricted to QLA27xx/28xx:
>    - Flash update capability queries (get/set)
>    - BBCR data retrieval
>    - D-port diagnostics
>    - MPI and PEP version sysfs attributes
> 
> Restrict unsupported operations on QLA29xx:
>    - Reject flash image status query (no active image tracking)
>    - Block qla28xx_validate_flash_image()
> 
> Guard the qla27xx_get_active_image() call with an explicit IS_QLA27XX
> || IS_QLA28XX check so it is not reached from adapters that lack the
> legacy active-image layout.
> 
> Signed-off-by: Manish Rangankar <mrangankar@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_attr.c |  4 ++--
>   drivers/scsi/qla2xxx/qla_bsg.c  | 19 ++++++++++++-------
>   drivers/scsi/qla2xxx/qla_def.h  |  2 +-
>   drivers/scsi/qla2xxx/qla_fw.h   |  2 +-
>   4 files changed, 16 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
> index 37478af9cdec..fd3c8c207535 100644
> --- a/drivers/scsi/qla2xxx/qla_attr.c
> +++ b/drivers/scsi/qla2xxx/qla_attr.c
> @@ -1542,7 +1542,7 @@ qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr,
>   	struct qla_hw_data *ha = vha->hw;
>   
>   	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha) &&
> -	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
> +	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
>   		return scnprintf(buf, PAGE_SIZE, "\n");
>   
>   	return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
> @@ -1770,7 +1770,7 @@ qla2x00_pep_version_show(struct device *dev, struct device_attribute *attr,
>   	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
>   	struct qla_hw_data *ha = vha->hw;
>   
> -	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
> +	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
>   		return scnprintf(buf, PAGE_SIZE, "\n");
>   
>   	return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index 00e980f0cd78..7f4558beee2c 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -1900,7 +1900,7 @@ static int qla2900_bsg_load_mpi(struct bsg_job *bsg_job)
>   	bsg_job_done(bsg_job, bsg_reply->result,
>   		     bsg_reply->reply_payload_rcv_len);
>   
> -	return rval;
> +	return 0;
>   }
>   
>   static int
> @@ -2544,7 +2544,7 @@ qla27xx_get_flash_upd_cap(struct bsg_job *bsg_job)
>   	struct qla_hw_data *ha = vha->hw;
>   	struct qla_flash_update_caps cap;
>   
> -	if (!(IS_QLA27XX(ha)) && !IS_QLA28XX(ha))
> +	if (!(IS_QLA27XX(ha)) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
>   		return -EPERM;
>   
>   	memset(&cap, 0, sizeof(cap));
> @@ -2577,7 +2577,7 @@ qla27xx_set_flash_upd_cap(struct bsg_job *bsg_job)
>   	uint64_t online_fw_attr = 0;
>   	struct qla_flash_update_caps cap;
>   
> -	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
> +	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
>   		return -EPERM;
>   
>   	memset(&cap, 0, sizeof(cap));
> @@ -2625,7 +2625,7 @@ qla27xx_get_bbcr_data(struct bsg_job *bsg_job)
>   	uint8_t domain, area, al_pa, state;
>   	int rval;
>   
> -	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
> +	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
>   		return -EPERM;
>   
>   	memset(&bbcr, 0, sizeof(bbcr));
> @@ -2741,7 +2741,7 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job)
>   	struct qla_dport_diag *dd;
>   
>   	if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
> -	    !IS_QLA28XX(vha->hw))
> +	    !IS_QLA28XX(vha->hw) && !IS_QLA29XX(vha->hw))
>   		return -EPERM;
>   
>   	dd = kmalloc_obj(*dd);
> @@ -2867,8 +2867,13 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job)
>   	struct qla_active_regions regions = { };
>   	struct active_regions active_regions = { };
>   
> -	qla27xx_get_active_image(vha, &active_regions);
> -	regions.global_image = active_regions.global;
> +	if (IS_QLA29XX(ha))
> +		return -EPERM;
> +
> +	if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
> +		qla27xx_get_active_image(vha, &active_regions);
> +		regions.global_image = active_regions.global;
> +	}
>   
>   	if (IS_QLA27XX(ha))
>   		regions.nvme_params = QLA27XX_PRIMARY_IMAGE;
> diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
> index 3e2f1d8ba904..4fd2a28af7e4 100644
> --- a/drivers/scsi/qla2xxx/qla_def.h
> +++ b/drivers/scsi/qla2xxx/qla_def.h
> @@ -4454,7 +4454,7 @@ struct qla_hw_data {
>   #define IS_QLA27XX(ha)  (IS_QLA2071(ha) || IS_QLA2271(ha) || IS_QLA2261(ha))
>   #define IS_QLA28XX(ha)	(IS_QLA2081(ha) || IS_QLA2281(ha))
>   #define IS_QLA29XX(ha)	(IS_QLA2099(ha) || IS_QLA2299(ha) || \
> -			 IS_QLA2091(ha) || IS_QLA2291(ha))
> +				IS_QLA2091(ha) || IS_QLA2291(ha))
>   
>   #define IS_QLA24XX_TYPE(ha)     (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
>   				IS_QLA84XX(ha))
> diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
> index 050986c6217f..4d6f8b1a36d1 100644
> --- a/drivers/scsi/qla2xxx/qla_fw.h
> +++ b/drivers/scsi/qla2xxx/qla_fw.h
> @@ -2360,7 +2360,7 @@ struct qla_fmb_upd_time {
>   
>   struct qla_flash_memo_block {
>   	__le32   signature;	/* "FMBS" */
> -#define QLFC_FMB_SIG	cpu_to_le32(0x464D4253)
> +#define QLFC_FMB_SIG	cpu_to_le32(0x53424D46)

Huh?
What happens here?
Simply exchanging a magic number for a new HBA?
And what happens with the old HBAs?

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 45/60] scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking
  2026-06-12  9:53 ` [PATCH v2 45/60] scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking Nilesh Javali
@ 2026-06-12 12:56   ` Hannes Reinecke
  2026-06-12 13:23   ` sashiko-bot
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:56 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> qla25xx_free_req_que() and qla25xx_free_rsp_que() have two pre-existing
> bugs exposed on the error path of qla25xx_create_{req,rsp}_que():
> 
> 1. When dma_alloc_coherent() fails during queue creation, the error path
>     calls the free function with req->ring / rsp->ring still NULL (from
>     kzalloc).  The unconditional dma_free_coherent() with a NULL cpu_addr
>     is undefined behavior and can panic.
> 
> 2. The free functions clear req_qid_map / rsp_qid_map under vport_lock,
>     but the create functions protect the same bitmaps with mq_lock.  This
>     provides no mutual exclusion.  Additionally, the create error path
>     clears the bit and releases mq_lock before calling the free function,
>     creating a window where another thread can allocate the same que_id
>     and have its ha->req_q_map entry clobbered by the subsequent lockless
>     NULL assignment in the free function.
> 
> Fix by:
>   - Guarding dma_free_coherent() with a NULL check on the ring pointer.
>   - Using mq_lock (the lock held by all creators) in the free functions
>     to atomically NULL the map entry and clear the bitmap bit.
>   - Removing the now-redundant clear_bit blocks from the create error
>     paths since the free functions handle it atomically.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_mid.c | 28 ++++++++++++----------------
>   1 file changed, 12 insertions(+), 16 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 46/60] scsi: qla2xxx: Replace __le16 bitfields with scalar and accessors
  2026-06-12  9:53 ` [PATCH v2 46/60] scsi: qla2xxx: Replace __le16 bitfields with scalar and accessors Nilesh Javali
@ 2026-06-12 12:57   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:57 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> C bitfield packing order is implementation-defined: GCC packs LSB-first
> on little-endian targets and MSB-first on big-endian targets.  The
> __le16 bitfield declarations for vp_index/sof_type in the 29xx extended
> IOCB structures produce incorrect bit positions on big-endian hosts,
> and Sparse cannot enforce endianness checks on bitfield members.
> 
> Replace the three sets of __le16 bitfields (in els_entry_24xx_ext,
> els_sts_entry_24xx_ext, and abts_entry_24xx_ext) with a single __le16
> scalar field and provide inline accessor functions that use proper
> le16_to_cpu()/cpu_to_le16() with shift-and-mask operations.
> 
> Fixes: 1b923fdfaeb5 ("scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx")
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_fw29.h   | 39 ++++++++++++++++++++++++-------
>   drivers/scsi/qla2xxx/qla_inline.h |  8 +++----
>   drivers/scsi/qla2xxx/qla_isr.c    | 15 ++++++------
>   3 files changed, 42 insertions(+), 20 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 47/60] scsi: qla2xxx: Fix endianness annotations in vp_rpt_id_entry structures
  2026-06-12  9:53 ` [PATCH v2 47/60] scsi: qla2xxx: Fix endianness annotations in vp_rpt_id_entry structures Nilesh Javali
@ 2026-06-12 12:59   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 12:59 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> The vp_rpt_id_entry_24xx and vp_rpt_id_entry_24xx_ext DMA structures
> use plain uint16_t for fip_flags and bbcr fields that the firmware
> writes in little-endian format.  On big-endian hosts, reading bbcr
> without le16_to_cpu() produces an incorrect value, breaking the
> buffer-to-buffer credit enable detection.
> 
> Additionally, the 29xx ext struct uses __le16 bitfields for
> vp_idx:9/vp_status:7 which suffer from architecture-dependent
> bit packing order (same class of bug fixed in the ELS/ABTS
> extended IOCBs).
> 
> Fix by:
>    - Changing uint16_t fip_flags/bbcr to __le16 in both qla_fw.h
>      and qla_fw29.h (enables Sparse endianness checking)
>    - Replacing the __le16 bitfields with a scalar __le16 vp_idx_status
>      and defined shift/mask constants
>    - Adding le16_to_cpu() at the bbcr and vp_idx_status access sites
>      in qla_mbx.c
> 
> Fixes: 1b923fdfaeb5 ("scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx")
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_fw.h   |  8 ++++----
>   drivers/scsi/qla2xxx/qla_fw29.h | 20 ++++++++++++++------
>   drivers/scsi/qla2xxx/qla_mbx.c  |  9 ++++++---
>   3 files changed, 24 insertions(+), 13 deletions(-)
> 

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 48/60] scsi: qla2xxx: Use 64-bit FPM word counters for 29xx host stats
  2026-06-12  9:53 ` [PATCH v2 48/60] scsi: qla2xxx: Use 64-bit FPM word counters for 29xx host stats Nilesh Javali
@ 2026-06-12 13:00   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:00 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> 29xx provides the 64-bit FPM transmit/receive word counters in the link
> statistics block, like 83xx/27xx/28xx.  qla2x00_get_fc_host_stats()
> only consumed those counters for the older families and fell back to the
> software approximation (input/output bytes >> 2) on 29xx, reporting less
> accurate rx_words/tx_words.
> 
> Add IS_QLA29XX() to the high-speed branch so 29xx reports the hardware
> word counters.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_attr.c | 3 ++-
>   1 file changed, 2 insertions(+), 1 deletion(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 49/60] scsi: qla2xxx: Add 64G/128G port speed setting support
  2026-06-12  9:53 ` [PATCH v2 49/60] scsi: qla2xxx: Add 64G/128G port speed setting support Nilesh Javali
@ 2026-06-12 13:02   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:02 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> The port speed setting paths topped out at 32G: qla2x00_port_speed_store()
> only mapped sysfs inputs up to 32 (and their no-loss-of-sync forms up to
> 320), and qla2x00_set_data_rate() only accepted PORT_SPEED_AUTO/4/8/16/32
> in its switch.  A user request for 64G or 128G therefore hit the default
> arm and was silently downgraded to auto-negotiation.
> 
> Map the 64 and 128 sysfs inputs (and their /10 no-loss-of-sync forms 640
> and 1280) to PORT_SPEED_64GB and PORT_SPEED_128GB, and accept those
> values in qla2x00_set_data_rate().  The firmware validates the requested
> rate against the adapter's actual capability.
> 
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_attr.c | 8 +++++++-
>   drivers/scsi/qla2xxx/qla_mbx.c  | 2 ++
>   2 files changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
> index 308b85e04f26..4c1812c4b420 100644
> --- a/drivers/scsi/qla2xxx/qla_attr.c
> +++ b/drivers/scsi/qla2xxx/qla_attr.c
> @@ -1835,7 +1835,7 @@ qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
>   		return rval;
>   	speed = type;
>   	if (type == 40 || type == 80 || type == 160 ||
> -	    type == 320) {
> +	    type == 320 || type == 640 || type == 1280) {
>   		ql_dbg(ql_dbg_user, vha, 0x70d9,
>   		    "Setting will be affected after a loss of sync\n");
>   		type = type/10;
> @@ -1860,6 +1860,12 @@ qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
>   	case 32:
>   		ha->set_data_rate = PORT_SPEED_32GB;
>   		break;
> +	case 64:
> +		ha->set_data_rate = PORT_SPEED_64GB;
> +		break;
> +	case 128:
> +		ha->set_data_rate = PORT_SPEED_128GB;
> +		break;
>   	default:
>   		ql_log(ql_log_warn, vha, 0x1199,
>   		    "Unrecognized speed setting:%lx. Setting Autoneg\n",
> diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
> index 7c0cc3e9c738..5a5d33e8ee7f 100644
> --- a/drivers/scsi/qla2xxx/qla_mbx.c
> +++ b/drivers/scsi/qla2xxx/qla_mbx.c
> @@ -5728,6 +5728,8 @@ qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode)
>   	case PORT_SPEED_8GB:
>   	case PORT_SPEED_16GB:
>   	case PORT_SPEED_32GB:
> +	case PORT_SPEED_64GB:
> +	case PORT_SPEED_128GB:
>   		val = ha->set_data_rate;
>   		break;
>   	default:

I'd rather merge it with the patch introducing these speeds, but that
may be a matter of taste.

Otherwise:

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 50/60] scsi: qla2xxx: Fix 64G link speed reporting in get_data_rate
  2026-06-12  9:53 ` [PATCH v2 50/60] scsi: qla2xxx: Fix 64G link speed reporting in get_data_rate Nilesh Javali
@ 2026-06-12 13:03   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:03 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> qla2x00_get_data_rate() skips updating ha->link_data_rate when the
> firmware returns mcp->mb[1] == 0x7.  That value was a legacy sentinel
> from before 64G hardware existed, but PORT_SPEED_64GB is now defined as
> 0x07 and ha->link_data_rate is decoded with the PORT_SPEED_* encoding.
> On a 64G-capable adapter a genuine 64G link is therefore dropped, and
> the port speed is misreported (port_speed sysfs, fc_host speed, FDMI).
> 
> Only 28xx and 29xx support 64G, so accept 0x07 on those adapters while
> keeping the legacy filter for older ones.  Also drop the duplicate
> copy of the check at the end of the success branch; it repeated the
> first assignment with no intervening change.
> 
> Fixes: ecc89f25e225 ("scsi: qla2xxx: Add Device ID for ISP28XX")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_mbx.c | 7 +++----
>   1 file changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
> index 5a5d33e8ee7f..d661662aed26 100644
> --- a/drivers/scsi/qla2xxx/qla_mbx.c
> +++ b/drivers/scsi/qla2xxx/qla_mbx.c
> @@ -5793,10 +5793,11 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
>   		ql_dbg(ql_dbg_mbx, vha, 0x1107,
>   		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
>   	} else {
> -		if (mcp->mb[1] != 0x7)
> +		if (mcp->mb[1] != 0x7 || IS_QLA28XX(ha) || IS_QLA29XX(ha))
>   			ha->link_data_rate = mcp->mb[1];
>   
> -		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
> +		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
> +		    IS_QLA29XX(ha)) {
>   			if (mcp->mb[4] & BIT_0)
>   				ql_log(ql_log_info, vha, 0x11a2,
>   				    "FEC=enabled (data rate).\n");
> @@ -5804,8 +5805,6 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
>   
>   		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1108,
>   		    "Done %s.\n", __func__);
> -		if (mcp->mb[1] != 0x7)
> -			ha->link_data_rate = mcp->mb[1];
>   	}
>   
>   	return rval;

Please merge with the patch introducing the IS_QLA29XX() checks here.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 51/60] scsi: qla2xxx: edif: Fix NULL pointer deref in RX SA delete check
  2026-06-12  9:53 ` [PATCH v2 51/60] scsi: qla2xxx: edif: Fix NULL pointer deref in RX SA delete check Nilesh Javali
  2026-06-12 11:43   ` sashiko-bot
@ 2026-06-12 13:04   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:04 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> qla_chk_edif_rx_sa_delete_pending() obtains the SCSI command via
> GET_CMD_SP(sp) and immediately dereferences cmd->sc_data_direction.
> That command pointer can be NULL: the firmware may post a status
> completion for a command that has already been returned or aborted.
> The caller qla2x00_status_entry() acknowledges this on the very same
> status path, re-fetching GET_CMD_SP(sp) and bailing out with the
> "Command already returned" message when it is NULL -- but that check
> runs only after qla_chk_edif_rx_sa_delete_pending() has already
> dereferenced the pointer, so a NULL cmd crashes the kernel in
> interrupt context.
> 
> Return early when cmd is NULL, before touching cmd->sc_data_direction.
> 
> Fixes: dd30706e73b7 ("scsi: qla2xxx: edif: Add key update")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_edif.c | 3 +++
>   1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
> index f8bc248e5d18..c8889ea199d3 100644
> --- a/drivers/scsi/qla2xxx/qla_edif.c
> +++ b/drivers/scsi/qla2xxx/qla_edif.c
> @@ -3543,6 +3543,9 @@ void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
>   	uint32_t handle;
>   	uint16_t sa_index;
>   
> +	if (!cmd)
> +		return;
> +
>   	handle = (uint32_t)LSW(sts24->handle);
>   
>   	/* find out if this status iosb is for a scsi read */

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 52/60] scsi: qla2xxx: Fix Name Server logout detection on FWI2 adapters
  2026-06-12  9:53 ` [PATCH v2 52/60] scsi: qla2xxx: Fix Name Server logout detection on FWI2 adapters Nilesh Javali
@ 2026-06-12 13:08   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:08 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> In the CS_PORT_LOGGED_OUT case of qla2x00_chk_ms_status(), the
> FWI2-capable branch compared ms_pkt->loop_id.extended against NPH_SNS
> to decide whether the Name Server had logged out. On FWI2 and later
> adapters the response is a ct_entry_24xx / ct_entry_24xx_ext, where
> loop_id.extended (via the legacy ms_iocb_entry_t view) aliases offset 8,
> which is comp_status, not nport_handle (offset 10). As this code runs
> under CS_PORT_LOGGED_OUT, the field read back 0x29 (CS_PORT_LOGGED_OUT)
> and the comparison against NPH_SNS (0x7fc) was always false.
> 
> As a result the driver never recognized a Name Server logout on FWI2/
> 29xx adapters: it returned the generic QLA_FUNCTION_FAILED instead of
> QLA_NOT_LOGGED_IN and skipped setting LOOP_RESYNC_NEEDED /
> LOCAL_LOOP_UPDATE, so the fabric rediscovery triggered by an SNS logout
> did not happen.
> 
> Read nport_handle from the ct_entry_24xx layout (offset 10) instead.
> nport_handle is at the same offset in ct_entry_24xx and
> ct_entry_24xx_ext, so a single cast covers 24xx-class and 29xx. The
> non-FWI2 branch keeps using loop_id.extended, which is correct for the
> ms_iocb_entry_t response on those adapters.
> 
> Fixes: b98ae0d748db ("scsi: qla2xxx: Fix name server relogin")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_gs.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
> index eefd1440d197..0d345009732a 100644
> --- a/drivers/scsi/qla2xxx/qla_gs.c
> +++ b/drivers/scsi/qla2xxx/qla_gs.c
> @@ -192,8 +192,8 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
>   			break;
>   		case CS_PORT_LOGGED_OUT:
>   			if (IS_FWI2_CAPABLE(ha)) {
> -				if (le16_to_cpu(ms_pkt->loop_id.extended) ==
> -				    NPH_SNS)
> +				if (le16_to_cpu(((struct ct_entry_24xx *)
> +				    ms_pkt)->nport_handle) == NPH_SNS)
>   					lid_is_sns = true;
>   			} else {
>   				if (le16_to_cpu(ms_pkt->loop_id.extended) ==

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 53/60] scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size
  2026-06-12  9:53 ` [PATCH v2 53/60] scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size Nilesh Javali
  2026-06-12 11:35   ` sashiko-bot
@ 2026-06-12 13:09   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:09 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> The VP control IOCB selects its target virtual port by setting one bit
> in vp_idx_map, a fixed 16-byte (128-bit) array in both
> vp_ctrl_entry_24xx and vp_ctrl_entry_24xx_ext. qla25xx_ctrlvp_iocb()
> computes map = (vp_index - 1) / 8 and writes vce->vp_idx_map[map]
> without checking that map stays within the array.
> 
> max_npiv_vports is taken from firmware and only sanitized to a
> MIN_MULTI_ID_FABRIC-aligned boundary, so it can legitimately be 191 or
> 255, and qla24xx_control_vp() only rejects vp_index >= max_npiv_vports.
> A vp_index above 128 therefore yields map >= 16 and an out-of-bounds
> write of up to 16 bytes past vp_idx_map, corrupting the trailing IOCB
> fields (or the adjacent request-ring slot on the 64-byte layout).
> 
> Reject a vp_index that cannot be represented in the IOCB bitmap in
> qla24xx_control_vp(), and add a defensive ARRAY_SIZE() guard in
> qla25xx_ctrlvp_iocb() before the write. Adapters that report the usual
> 63 or 127 NPIV vports are unaffected.
> 
> Fixes: 2853192e154b ("scsi: qla2xxx: Use IOCB path to submit Control VP MBX command")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_iocb.c | 6 ++++++
>   drivers/scsi/qla2xxx/qla_mid.c  | 8 ++++++++
>   2 files changed, 14 insertions(+)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
> index a103be30fddb..8b5a13823b3d 100644
> --- a/drivers/scsi/qla2xxx/qla_iocb.c
> +++ b/drivers/scsi/qla2xxx/qla_iocb.c
> @@ -4068,6 +4068,12 @@ qla25xx_ctrlvp_iocb(srb_t *sp, void *pkt)
>   	vce->entry_count = 1;
>   	vce->command = cpu_to_le16(sp->u.iocb_cmd.u.ctrlvp.cmd);
>   	vce->vp_count = cpu_to_le16(1);
> +	if (map >= ARRAY_SIZE(vce->vp_idx_map)) {
> +		ql_log(ql_log_warn, sp->vha, 0x307c,
> +		       "ctrlvp: vp_index %u exceeds vp_idx_map capacity\n",
> +		       sp->u.iocb_cmd.u.ctrlvp.vp_index);
> +		return;
> +	}
>   	vce->vp_idx_map[map] |= 1 << pos;
>   }
>   
> diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
> index 7072af5b4217..b7d9c1a53f3c 100644
> --- a/drivers/scsi/qla2xxx/qla_mid.c
> +++ b/drivers/scsi/qla2xxx/qla_mid.c
> @@ -987,6 +987,14 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
>   	if (vp_index == 0 || vp_index >= ha->max_npiv_vports)
>   		return QLA_PARAMETER_ERROR;
>   
> +	/*
> +	 * The VP_CTRL IOCB selects the target VP through a fixed 128-bit
> +	 * (16-byte) vp_idx_map bitmap, so vp_index must fit within it even
> +	 * if firmware advertises more NPIV vports.
> +	 */
> +	if (vp_index > sizeof_field(struct vp_ctrl_entry_24xx, vp_idx_map) * 8)
> +		return QLA_PARAMETER_ERROR;
> +
>   	/* ref: INIT */
>   	sp = qla2x00_get_sp(base_vha, NULL, GFP_KERNEL);
>   	if (!sp)

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 54/60] scsi: qla2xxx: Check entry_status in qla24xx_modify_vp_config()
  2026-06-12  9:53 ` [PATCH v2 54/60] scsi: qla2xxx: Check entry_status in qla24xx_modify_vp_config() Nilesh Javali
@ 2026-06-12 13:10   ` Hannes Reinecke
  0 siblings, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:10 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> The Modify VP Config completion handler labelled its first error branch
> "error status" but tested vpmod->comp_status instead of
> vpmod->entry_status. Because CS_COMPLETE is 0, the following
> "comp_status != CS_COMPLETE" branch duplicated that test and was dead
> code, and entry_status was never examined at all.
> 
> When firmware rejects the IOCB early it sets entry_status while leaving
> comp_status zero. As the IOCB is allocated with dma_pool_zalloc(), both
> comp_status branches evaluate false and the handler falls through to the
> success path, calling fc_vport_set_state(FC_VPORT_INITIALIZING) for a
> configuration the firmware never accepted. This can leave the virtual
> port enabled on top of an invalid config and surface later as login
> timeouts or follow-on firmware errors.
> 
> Test entry_status in the first branch, matching qla_ctrlvp_completed()
> and the login/logout/abort/reset IOCB handlers; the comp_status branch
> then becomes the live completion-status check.
> 
> Fixes: 2c3dfe3f6ad8 ("[SCSI] qla2xxx: add support for NPIV")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_mbx.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
> index d661662aed26..8a001b489fc0 100644
> --- a/drivers/scsi/qla2xxx/qla_mbx.c
> +++ b/drivers/scsi/qla2xxx/qla_mbx.c
> @@ -4409,10 +4409,10 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
>   	if (rval != QLA_SUCCESS) {
>   		ql_dbg(ql_dbg_mbx, vha, 0x10bd,
>   		    "Failed to issue VP config IOCB (%x).\n", rval);
> -	} else if (vpmod->comp_status != 0) {
> +	} else if (vpmod->entry_status != 0) {
>   		ql_dbg(ql_dbg_mbx, vha, 0x10be,
>   		    "Failed to complete IOCB -- error status (%x).\n",
> -		    vpmod->comp_status);
> +		    vpmod->entry_status);
>   		rval = QLA_FUNCTION_FAILED;
>   	} else if (vpmod->comp_status != cpu_to_le16(CS_COMPLETE)) {
>   		ql_dbg(ql_dbg_mbx, vha, 0x10bf,

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 55/60] scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition()
  2026-06-12  9:53 ` [PATCH v2 55/60] scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition() Nilesh Javali
  2026-06-12 11:38   ` sashiko-bot
@ 2026-06-12 13:10   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:10 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> In the format 1 path, the virtual port is located on ha->vp_list while
> holding vport_slock, but the lock is dropped before vp is used:
> qla_update_host_map() is called and VP_IDX_ACQUIRED/REGISTER_FC4_NEEDED/
> REGISTER_FDMI_NEEDED are set on vp. No reference is taken across that
> window, so a concurrent qla24xx_deallocate_vp_id() can tear the vport
> down and free it, leading to a use-after-free.
> 
> Take a vport reference (vref_count) under vport_slock when the matching
> vp is found, and drop it after the last use of vp. qla24xx_deallocate_vp_id()
> waits for vref_count to reach zero before unlinking and freeing the vport,
> so the pointer stays valid. This matches the reference idiom already used
> by the other ha->vp_list traversals.
> 
> Fixes: 2c3dfe3f6ad8 ("[SCSI] qla2xxx: add support for NPIV")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_mbx.c | 3 +++
>   1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
> index 8a001b489fc0..bfb931eb14f6 100644
> --- a/drivers/scsi/qla2xxx/qla_mbx.c
> +++ b/drivers/scsi/qla2xxx/qla_mbx.c
> @@ -4275,6 +4275,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt)
>   			list_for_each_entry(vp, &ha->vp_list, list) {
>   				if (vp_idx == vp->vp_idx) {
>   					found = 1;
> +					atomic_inc(&vp->vref_count);
>   					break;
>   				}
>   			}
> @@ -4292,6 +4293,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt)
>   			set_bit(VP_IDX_ACQUIRED, &vp->vp_flags);
>   			set_bit(REGISTER_FC4_NEEDED, &vp->dpc_flags);
>   			set_bit(REGISTER_FDMI_NEEDED, &vp->dpc_flags);
> +
> +			atomic_dec(&vp->vref_count);
>   		}
>   		set_bit(VP_DPC_NEEDED, &vha->dpc_flags);
>   		qla2xxx_wake_dpc(vha);

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 56/60] scsi: qla2xxx: Initialize NVMe abort_work once at submission
  2026-06-12  9:53 ` [PATCH v2 56/60] scsi: qla2xxx: Initialize NVMe abort_work once at submission Nilesh Javali
  2026-06-12 11:34   ` sashiko-bot
@ 2026-06-12 13:11   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:11 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> qla_nvme_fcp_abort() and qla_nvme_ls_abort() ran INIT_WORK() on
> priv->abort_work immediately before schedule_work(). INIT_WORK()
> reinitializes the work_struct, resetting its list head and clearing the
> pending bit. If an abort is issued more than once for the same command
> (for example, concurrent transport teardown and a timeout-driven abort),
> the second INIT_WORK() reinitializes a work item that is already queued,
> which can corrupt the workqueue list and lead to crashes or a looping
> worker.
> 
> Initialize priv->abort_work once at command submission, next to the
> existing per-command spin_lock_init(&priv->cmd_lock), and leave only
> schedule_work() in the abort paths. schedule_work() already does nothing
> when the work item is still pending, so a repeated abort no longer
> disturbs an in-flight work item. The command is not returned to the
> transport until the final kref_put()/release callback runs after
> abort_work has completed, so the work item is idle before priv is
> reused and the single submission-time INIT_WORK() is safe.
> 
> Fixes: e473b3074104 ("scsi: qla2xxx: Add FC-NVMe abort processing")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_nvme.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
> index 0038b6274d44..3b2f255a5d7d 100644
> --- a/drivers/scsi/qla2xxx/qla_nvme.c
> +++ b/drivers/scsi/qla2xxx/qla_nvme.c
> @@ -463,7 +463,6 @@ static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport,
>   	}
>   	spin_unlock_irqrestore(&priv->cmd_lock, flags);
>   
> -	INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
>   	schedule_work(&priv->abort_work);
>   }
>   
> @@ -501,6 +500,7 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
>   	priv->sp = sp;
>   	kref_init(&sp->cmd_kref);
>   	spin_lock_init(&priv->cmd_lock);
> +	INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
>   	nvme = &sp->u.iocb_cmd;
>   	priv->fd = fd;
>   	nvme->u.nvme.desc = fd;
> @@ -545,7 +545,6 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport,
>   	}
>   	spin_unlock_irqrestore(&priv->cmd_lock, flags);
>   
> -	INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
>   	schedule_work(&priv->abort_work);
>   }
>   
> @@ -877,6 +876,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
>   
>   	kref_init(&sp->cmd_kref);
>   	spin_lock_init(&priv->cmd_lock);
> +	INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
>   	sp->priv = priv;
>   	priv->sp = sp;
>   	sp->type = SRB_NVME_CMD;

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 57/60] scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject
  2026-06-12  9:53 ` [PATCH v2 57/60] scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject Nilesh Javali
  2026-06-12 11:39   ` sashiko-bot
@ 2026-06-12 13:11   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:11 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> qla_nvme_ls_reject_iocb() allocates from and advances the request ring
> through __qla2x00_alloc_iocbs() (which assumes the hardware_lock is held)
> and qla2x00_start_iocbs() (which advances the ring and rings the
> request-in doorbell), but takes no lock itself. Two of its callers invoke
> it without the producer lock held:
> 
>    - qla_nvme_xmt_ls_rsp(), the NVMe-FC .xmt_ls_rsp transport callback, on
>      its error path, and
>    - qla2xxx_process_purls_pkt(), run from the purex work/DPC context.
> 
> Both use ha->base_qpair, whose qp_lock_ptr is hardware_lock, so they can
> run concurrently with normal I/O submission on the base ring and corrupt
> the ring producer state, leading to duplicated or dropped commands. The
> third caller, qla2xxx_process_purls_iocb(), runs inside
> qla24xx_process_response_queue() with the qpair lock already held and is
> safe; that is also why the lock cannot be taken inside the helper itself
> (it would recursively re-acquire hardware_lock on the response path).
> 
> Take qp_lock_ptr around the two unlocked callers and document the helper
> as caller-locked. Both run in process context, so spin_lock_irqsave() is
> used and nothing in the locked region sleeps.
> 
> Fixes: 875386b98857 ("scsi: qla2xxx: Add Unsolicited LS Request and Response Support for NVMe")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_nvme.c | 10 ++++++++++
>   1 file changed, 10 insertions(+)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
> index 3b2f255a5d7d..8dc6df6c2e1c 100644
> --- a/drivers/scsi/qla2xxx/qla_nvme.c
> +++ b/drivers/scsi/qla2xxx/qla_nvme.c
> @@ -374,6 +374,7 @@ static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport,
>   	srb_t *sp;
>   	int rval = QLA_FUNCTION_FAILED;
>   	uint8_t cnt = 0;
> +	unsigned long flags;
>   
>   	if (!fcport || fcport->deleted)
>   		goto out;
> @@ -440,7 +441,9 @@ static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport,
>   	a.vp_idx = vha->vp_idx;
>   	a.nport_handle = uctx->nport_handle;
>   	a.xchg_address = uctx->exchange_address;
> +	spin_lock_irqsave(ha->base_qpair->qp_lock_ptr, flags);
>   	qla_nvme_ls_reject_iocb(vha, ha->base_qpair, &a, true);
> +	spin_unlock_irqrestore(ha->base_qpair->qp_lock_ptr, flags);
>   	kfree(uctx);
>   	return rval;
>   }
> @@ -1243,6 +1246,10 @@ static void qla_nvme_lsrjt_pt_iocb(struct scsi_qla_host *vha,
>   	}
>   }
>   
> +/*
> + * Allocates from and advances the request ring, so the caller must hold
> + * qp->qp_lock_ptr (the response-queue caller already holds it).
> + */
>   static int
>   qla_nvme_ls_reject_iocb(struct scsi_qla_host *vha, struct qla_qpair *qp,
>   			struct qla_nvme_lsrjt_pt_arg *a, bool is_xchg_terminate)
> @@ -1299,6 +1306,7 @@ qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item)
>   {
>   	struct qla_nvme_unsol_ctx *uctx = item->purls_context;
>   	struct qla_nvme_lsrjt_pt_arg a;
> +	unsigned long flags;
>   	int ret = 1;
>   
>   #if (IS_ENABLED(CONFIG_NVME_FC))
> @@ -1311,7 +1319,9 @@ qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item)
>   		a.vp_idx = vha->vp_idx;
>   		a.nport_handle = uctx->nport_handle;
>   		a.xchg_address = uctx->exchange_address;
> +		spin_lock_irqsave(vha->hw->base_qpair->qp_lock_ptr, flags);
>   		qla_nvme_ls_reject_iocb(vha, vha->hw->base_qpair, &a, true);
> +		spin_unlock_irqrestore(vha->hw->base_qpair->qp_lock_ptr, flags);
>   		list_del(&uctx->elem);
>   		kfree(uctx);
>   	}

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 58/60] scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak
  2026-06-12  9:53 ` [PATCH v2 58/60] scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak Nilesh Javali
  2026-06-12 11:40   ` sashiko-bot
@ 2026-06-12 13:12   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:12 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> qla2x00_do_dport_diagnostics() allocates the qla_dport_diag response
> buffer with kmalloc_obj() (non-zeroing) and, on success, copies the
> full sizeof(*dd) back to user space via sg_copy_from_buffer(). The
> inbound sg_copy_to_buffer() only fills as many bytes as the user
> request payload provides, and qla26xx_dport_diagnostics() zeroes only
> dd->buf. The options and unused[] fields are therefore copied out
> uninitialized, leaking kernel heap contents to user space.
> 
> Allocate with kzalloc_obj(), matching qla2x00_do_dport_diagnostics_v2().
> 
> Fixes: ec89146215d1 ("qla2xxx: Add bsg interface to support D_Port Diagnostics.")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_bsg.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index 7f4558beee2c..b57c55964f9e 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -2744,7 +2744,7 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job)
>   	    !IS_QLA28XX(vha->hw) && !IS_QLA29XX(vha->hw))
>   		return -EPERM;
>   
> -	dd = kmalloc_obj(*dd);
> +	dd = kzalloc_obj(*dd);
>   	if (!dd) {
>   		ql_log(ql_log_warn, vha, 0x70db,
>   		    "Failed to allocate memory for dport.\n");

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 59/60] scsi: qla2xxx: Fix BSG job leak on validate flash image error path
  2026-06-12  9:53 ` [PATCH v2 59/60] scsi: qla2xxx: Fix BSG job leak on validate flash image error path Nilesh Javali
  2026-06-12 11:38   ` sashiko-bot
@ 2026-06-12 13:12   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:12 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> qla28xx_validate_flash_image() returns QLA_SUCCESS (0) unconditionally,
> telling the FC BSG transport (fc_bsg_host_dispatch()) that the driver
> owns and will complete the request. But bsg_job_done() is guarded by
> "if (!rval)", so on the error path (rval == -EINVAL) neither the driver
> nor the transport completes the job. The request dangles until it times
> out, leaking block layer resources.
> 
> Commit c2c68225b145 ("scsi: qla2xxx: Fix bsg_done() causing double
> free") added the "if (!rval)" guard to a batch of BSG handlers. That is
> correct for handlers that also return the error code (the transport then
> completes the job once via fail_host_msg), but this function returns
> QLA_SUCCESS unconditionally, so the guard turned a correct single
> completion into a leak.
> 
> Always call bsg_job_done(): bsg_reply->result is DID_OK and the error is
> reported in vendor_rsp[0], and since the function returns 0 the transport
> will not complete the job a second time.
> 
> Fixes: c2c68225b145 ("scsi: qla2xxx: Fix bsg_done() causing double free")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_bsg.c | 5 ++---
>   1 file changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index b57c55964f9e..22be6c822dda 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -3734,9 +3734,8 @@ static int qla28xx_validate_flash_image(struct bsg_job *bsg_job)
>   	bsg_reply->result = DID_OK << 16;
>   	bsg_reply->reply_payload_rcv_len = 0;
>   	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
> -	if (!rval)
> -		bsg_job_done(bsg_job, bsg_reply->result,
> -			     bsg_reply->reply_payload_rcv_len);
> +	bsg_job_done(bsg_job, bsg_reply->result,
> +		     bsg_reply->reply_payload_rcv_len);
>   
>   	return QLA_SUCCESS;
>   }

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 60/60] scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions()
  2026-06-12  9:53 ` [PATCH v2 60/60] scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions() Nilesh Javali
  2026-06-12 11:45   ` sashiko-bot
@ 2026-06-12 13:13   ` Hannes Reinecke
  1 sibling, 0 replies; 154+ messages in thread
From: Hannes Reinecke @ 2026-06-12 13:13 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen
  Cc: linux-scsi, GR-FC-Storage-Upstream, agurumurthy, emilne, jmeneghi

On 6/12/26 11:53, Nilesh Javali wrote:
> qla2x00_update_fru_versions() copies the user-supplied BSG request into
> a fixed 256-byte stack buffer (bsg[DMA_POOL_SIZE]) and then iterates
> list->count times over the qla_image_version array embedded in that
> buffer, advancing the image pointer each iteration. count is taken
> directly from user input with no upper bound, while only
> (DMA_POOL_SIZE - sizeof(list->count)) / sizeof(struct qla_image_version)
> = 6 entries actually fit. A larger count walks the image pointer off the
> end of the stack buffer, reading adjacent kernel stack memory and
> sending it to the device via qla2x00_write_sfp().
> 
> Reject requests whose declared count does not fit in the buffer.
> 
> Fixes: 697a4bc69159 ("[SCSI] qla2xxx: Provide method for updating I2C attached VPD.")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
>   drivers/scsi/qla2xxx/qla_bsg.c | 7 +++++++
>   1 file changed, 7 insertions(+)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index 22be6c822dda..bcca4ef3c23e 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -1929,6 +1929,13 @@ qla2x00_update_fru_versions(struct bsg_job *bsg_job)
>   
>   	image = list->version;
>   	count = list->count;
> +
> +	if (struct_size(list, version, count) > sizeof(bsg)) {
> +		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
> +		    EXT_STATUS_INVALID_PARAM;
> +		goto dealloc;
> +	}
> +
>   	while (count--) {
>   		memcpy(sfp, &image->field_info, sizeof(image->field_info));
>   		rval = qla2x00_write_sfp(vha, sfp_dma, sfp,

Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.com                               +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 45/60] scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking
  2026-06-12  9:53 ` [PATCH v2 45/60] scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking Nilesh Javali
  2026-06-12 12:56   ` Hannes Reinecke
@ 2026-06-12 13:23   ` sashiko-bot
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 13:23 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing cancel_work_sync() for qpair->q_work in qla2xxx_delete_qpair() leads to a Use-After-Free condition of the qpair structure.
- [High] Incorrect teardown ordering in qla2xxx_delete_qpair() leaves the response queue IRQ active while freeing the request queue, risking a Use-After-Free.
- [High] Time-of-check to time-of-use (TOCTOU) race when locklessly reading `ha->req_q_map` in `qla2x00_error_entry()`.
--

commit 39ad14d24efefe86744d37bc2d46a853a7de6d76
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking

This commit fixes undefined behavior caused by calling dma_free_coherent()
with a NULL pointer during request and response queue teardown. It also
addresses a concurrency issue by protecting bitmap and map clear operations
with the mq_lock instead of vport_lock.

> diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
> index bb2521c052bf8..7072af5b42178 100644
> --- a/drivers/scsi/qla2xxx/qla_mid.c
> +++ b/drivers/scsi/qla2xxx/qla_mid.c
> @@ -576,16 +576,17 @@ qla25xx_free_req_que(struct scsi_qla_host *vha, struct req_que *req)
>  	uint16_t que_id = req->id;
>  	size_t req_entry_size = qla_req_entry_size(ha);
>  
> -	dma_free_coherent(&ha->pdev->dev,
> -			  (req->length + 1) * req_entry_size,
> -			  req->ring, req->dma);
> +	if (req->ring)
> +		dma_free_coherent(&ha->pdev->dev,
> +				  (req->length + 1) * req_entry_size,
> +				  req->ring, req->dma);
>  	req->ring = NULL;
>  	req->dma = 0;
>  	if (que_id) {
> +		mutex_lock(&ha->mq_lock);
>  		ha->req_q_map[que_id] = NULL;

[Severity: High]
This is a pre-existing issue, but modifying ha->req_q_map here under mq_lock
exposes a Time-of-check to time-of-use (TOCTOU) race in qla2x00_error_entry().

In drivers/scsi/qla2xxx/qla_isr.c:qla2x00_error_entry():
    if (que >= ha->max_req_queues || !ha->req_q_map[que])
        goto fatal;

    req = ha->req_q_map[que];

Since ha->req_q_map is read locklessly in the ISR, could it become NULL
between the check and the assignment, leading to a NULL pointer dereference?

> -		mutex_lock(&ha->vport_lock);
>  		clear_bit(que_id, ha->req_qid_map);
> -		mutex_unlock(&ha->vport_lock);
> +		mutex_unlock(&ha->mq_lock);
>  	}
>  	kfree(req->outstanding_cmds);
>  	kfree(req);
> @@ -605,16 +606,17 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
>  		rsp->msix->handle = NULL;
>  	}
>  
> -	dma_free_coherent(&ha->pdev->dev,
> -			  (rsp->length + 1) * rsp_entry_size,
> -			  rsp->ring, rsp->dma);
> +	if (rsp->ring)
> +		dma_free_coherent(&ha->pdev->dev,
> +				  (rsp->length + 1) * rsp_entry_size,
> +				  rsp->ring, rsp->dma);
>  	rsp->ring = NULL;
>  	rsp->dma = 0;

[Severity: High]
This isn't a bug introduced by this patch, but does the queue teardown sequence
in qla2xxx_delete_qpair() have a use-after-free risk during queue cleanup?

In drivers/scsi/qla2xxx/qla_init.c:qla2xxx_delete_qpair():
    ret = qla25xx_delete_req_que(vha, qpair->req);
    if (ret != QLA_SUCCESS)
        goto fail;

    ret = qla25xx_delete_rsp_que(vha, qpair->rsp);

The request queue memory is freed before the response queue IRQ is disabled.

Does this leave a race window where an interrupt firing on another CPU could
cause the ISR (qla24xx_process_response_queue) to access the already freed
request queue?

[Severity: High]
This is also a pre-existing issue, but does qla2xxx_delete_qpair() safely
teardown the qpair workqueue?

In drivers/scsi/qla2xxx/qla_init.c:qla2xxx_delete_qpair():
    ret = qla25xx_delete_rsp_que(vha, qpair->rsp);
    ...
    kfree(qpair);

Since qla25xx_delete_rsp_que() disables the MSI-X interrupt via free_irq(), but
free_irq() doesn't wait for asynchronous work to complete, could the queued
work function still execute?

In drivers/scsi/qla2xxx/qla_mid.c:qla_do_work():
    struct qla_qpair *qpair = container_of(work, struct qla_qpair, q_work);
    ...
    spin_lock_irqsave(&qpair->qp_lock, flags);

If the interrupt fired just before free_irq() and scheduled qpair->q_work,
could qla_do_work() dereference the qpair structure after it has been freed?

>  	if (que_id) {
> +		mutex_lock(&ha->mq_lock);
>  		ha->rsp_q_map[que_id] = NULL;
> -		mutex_lock(&ha->vport_lock);
>  		clear_bit(que_id, ha->rsp_qid_map);
> -		mutex_unlock(&ha->vport_lock);
> +		mutex_unlock(&ha->mq_lock);
>  	}
>  	kfree(rsp);
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=45

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v2 37/60] scsi: qla2xxx: Enhance ABTS processing for 29xx series
  2026-06-12  9:53 ` [PATCH v2 37/60] scsi: qla2xxx: Enhance ABTS processing " Nilesh Javali
  2026-06-12 12:41   ` Hannes Reinecke
@ 2026-06-12 15:12   ` sashiko-bot
  1 sibling, 0 replies; 154+ messages in thread
From: sashiko-bot @ 2026-06-12 15:12 UTC (permalink / raw)
  To: Nilesh Javali; +Cc: linux-scsi

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Releasing and reusing the `rsp_pkt` DMA buffer immediately after a hardware timeout can lead to a use-after-free and memory corruption by the device.
--

commit 95311a058967d0d565bd44ef588d75babbb03f6f
Author: Nilesh Javali <njavali@marvell.com>

scsi: qla2xxx: Enhance ABTS processing for 29xx series

This commit introduces extended ABTS entry structures to properly
handle the 128-byte IOCB format for the 29xx series adapters. It also
adds type-generic macros to reduce code duplication in the ABTS
processing path.

> diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
> index 5b5ccf2075353..284d874392fd5 100644
> --- a/drivers/scsi/qla2xxx/qla_isr.c
> +++ b/drivers/scsi/qla2xxx/qla_isr.c
[ ... ]
> @@ -140,60 +212,27 @@ qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
>  	}
>  
>  	/* send ABTS response */
> -	abts_rsp = rsp_pkt;
> -	memset(abts_rsp, 0, sizeof(*abts_rsp));
[ ... ]
> -	rval = qla2x00_issue_iocb(vha, abts_rsp, dma, 0);
> -	if (rval) {
[ ... ]
> +	if (IS_QLA29XX(ha)) {
> +		struct abts_entry_24xx_ext *rsp_ext = rsp_pkt;
> +
> +		QLA_BUILD_ABTS_BA_ACC(rsp_ext, abts_ext,
> +		    abts_ext->sof_type, fctl);
> +		QLA_LOG_ISSUE_ABTS_RSP(vha, rsp_ext, dma, rval);
>  	} else {
> -		ql_dbg(ql_dbg_init, vha, 0x028ea,
> -		    "%s: done.\n", __func__);
> +		struct abts_entry_24xx *abts_rsp = rsp_pkt;
> +
> +		QLA_BUILD_ABTS_BA_ACC(abts_rsp, abts,
> +		    abts->sof_type & 0xf0, fctl);
> +		QLA_LOG_ISSUE_ABTS_RSP(vha, abts_rsp, dma, rval);
>  	}
>  
>  	dma_free_coherent(&ha->pdev->dev, rsp_sz, rsp_pkt, dma);
>  }

[Severity: High]
This is a pre-existing issue, but could this code lead to a use-after-free
and memory corruption?

Earlier in qla24xx_process_abts(), qla2x00_issue_iocb() is called to send an
ELS response using the same rsp_pkt buffer:

    rval = qla2x00_issue_iocb(vha, rsp_pkt, dma, 0);
    if (rval) {
        ql_log(ql_log_warn, vha, 0x0288,
            "%s: iocb failed to execute -> %x\n", __func__, rval);
    } else if ...

If the command times out, qla2x00_issue_iocb() returns a non-zero rval, but
execution continues. The code then reuses rsp_pkt to send an ABTS response
and unconditionally frees it via dma_free_coherent() right after.

If the firmware is still holding the physical DMA address and completes the
delayed command later, wouldn't it perform a DMA write to the freed physical
address?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612095333.1666592-1-njavali@marvell.com?part=37

^ permalink raw reply	[flat|nested] 154+ messages in thread

end of thread, other threads:[~2026-06-12 15:12 UTC | newest]

Thread overview: 154+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-12  9:52 [PATCH v2 00/60] scsi: qla2xxx: Add QLA29xx series adapter support Nilesh Javali
2026-06-12  9:52 ` [PATCH v2 01/60] scsi: qla2xxx: Add 29xx series PCI device ID support Nilesh Javali
2026-06-12 10:30   ` sashiko-bot
2026-06-12 10:40   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 02/60] scsi: qla2xxx: Add flash read/write interface for 29xx Nilesh Javali
2026-06-12 10:16   ` sashiko-bot
2026-06-12 10:43   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 03/60] scsi: qla2xxx: Add NVRAM config support for 29xx adapters Nilesh Javali
2026-06-12 10:46   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 04/60] scsi: qla2xxx: Add get_flash_version " Nilesh Javali
2026-06-12 10:18   ` sashiko-bot
2026-06-12 10:48   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 05/60] scsi: qla2xxx: Add 29xx support in queue initialisation path Nilesh Javali
2026-06-12 10:17   ` sashiko-bot
2026-06-12 10:49   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 06/60] scsi: qla2xxx: Add FC operational firmware load for 29xx Nilesh Javali
2026-06-12 10:14   ` sashiko-bot
2026-06-12 10:52   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 07/60] scsi: qla2xxx: Add flash block read/write BSG support " Nilesh Javali
2026-06-12 10:11   ` sashiko-bot
2026-06-12 10:55   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 08/60] scsi: qla2xxx: Add BSG MPI firmware load/dump " Nilesh Javali
2026-06-12 10:14   ` sashiko-bot
2026-06-12 10:57   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 09/60] scsi: qla2xxx: Add 128-byte IOCB definitions " Nilesh Javali
2026-06-12 11:01   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 10/60] scsi: qla2xxx: Add extended status continuation and marker IOCBs Nilesh Javali
2026-06-12 11:02   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 11/60] scsi: qla2xxx: Remove duplicate flash memo block definitions Nilesh Javali
2026-06-12 11:03   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 12/60] scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx Nilesh Javali
2026-06-12 10:29   ` sashiko-bot
2026-06-12 11:12   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 13/60] scsi: qla2xxx: Replace IS_QLA29XX() size checks with entry-size helpers Nilesh Javali
2026-06-12 11:14   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 14/60] scsi: qla2xxx: Skip image-set-valid attribute for 29xx Nilesh Javali
2026-06-12 11:14   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 15/60] scsi: qla2xxx: Skip unsupported sysfs attributes " Nilesh Javali
2026-06-12 10:28   ` sashiko-bot
2026-06-12 11:15   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 16/60] scsi: qla2xxx: Enable get_fw_version mailbox " Nilesh Javali
2026-06-12 10:31   ` sashiko-bot
2026-06-12 11:16   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 17/60] scsi: qla2xxx: Extend execute_fw mailbox to include 29xx Nilesh Javali
2026-06-12 10:25   ` sashiko-bot
2026-06-12 11:17   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 18/60] scsi: qla2xxx: Enable get_adapter_id mailbox for 29xx Nilesh Javali
2026-06-12 11:18   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 19/60] scsi: qla2xxx: Enable init_firmware " Nilesh Javali
2026-06-12 11:18   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 20/60] scsi: qla2xxx: Enable get_firmware_state " Nilesh Javali
2026-06-12 11:19   ` Hannes Reinecke
2026-06-12 11:22   ` sashiko-bot
2026-06-12  9:52 ` [PATCH v2 21/60] scsi: qla2xxx: Enable serdes, resource count and FCE trace " Nilesh Javali
2026-06-12 10:38   ` sashiko-bot
2026-06-12 11:19   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 22/60] scsi: qla2xxx: Enable set_els_cmds and echo_test " Nilesh Javali
2026-06-12 11:20   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 23/60] scsi: qla2xxx: Add support for QLA29XX in data rate functions Nilesh Javali
2026-06-12 11:20   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 24/60] scsi: qla2xxx: Enable qla2x00_shutdown for 29xx Nilesh Javali
2026-06-12 11:21   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 25/60] scsi: qla2xxx: Use ring-slot helpers in __qla2x00_alloc_iocbs Nilesh Javali
2026-06-12 10:41   ` sashiko-bot
2026-06-12 11:21   ` Hannes Reinecke
2026-06-12  9:52 ` [PATCH v2 26/60] scsi: qla2xxx: Add support for QLA29XX in memory allocation Nilesh Javali
2026-06-12 10:40   ` sashiko-bot
2026-06-12 11:22   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 27/60] scsi: qla2xxx: Refactor marker IOCB handling for 29xx series Nilesh Javali
2026-06-12 11:36   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 28/60] scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters Nilesh Javali
2026-06-12 10:54   ` sashiko-bot
2026-06-12 11:47   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 29/60] scsi: qla2xxx: Update handling of status entries for 29xx series Nilesh Javali
2026-06-12 10:44   ` sashiko-bot
2026-06-12 12:12   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 30/60] scsi: qla2xxx: Enhance ct_entry_24xx_ext iocb handling " Nilesh Javali
2026-06-12 12:14   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 31/60] scsi: qla2xxx: Enhance purex_entry " Nilesh Javali
2026-06-12 10:54   ` sashiko-bot
2026-06-12 12:16   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 32/60] scsi: qla2xxx: Update handling of ELS IOCBs " Nilesh Javali
2026-06-12 12:33   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 33/60] scsi: qla2xxx: Add size check for ELS status entry layout on 29xx Nilesh Javali
2026-06-12 12:34   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 34/60] scsi: qla2xxx: Add 29xx extended logio IOCB support Nilesh Javali
2026-06-12 12:36   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 35/60] scsi: qla2xxx: Enhance task management IOCB handling for 29xx series Nilesh Javali
2026-06-12 11:13   ` sashiko-bot
2026-06-12 12:37   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 36/60] scsi: qla2xxx: Add abort command " Nilesh Javali
2026-06-12 11:15   ` sashiko-bot
2026-06-12 12:38   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 37/60] scsi: qla2xxx: Enhance ABTS processing " Nilesh Javali
2026-06-12 12:41   ` Hannes Reinecke
2026-06-12 15:12   ` sashiko-bot
2026-06-12  9:53 ` [PATCH v2 38/60] scsi: qla2xxx: Update VP control IOCB handling " Nilesh Javali
2026-06-12 12:45   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 39/60] scsi: qla2xxx: Add build-time size check for VP config IOCB layout Nilesh Javali
2026-06-12 12:45   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 40/60] scsi: qla2xxx: Add size check for extended VP report ID entry Nilesh Javali
2026-06-12 11:05   ` sashiko-bot
2026-06-12 12:46   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 41/60] scsi: qla2xxx: Unify NVMe IOCB build path for 29xx and legacy adapters Nilesh Javali
2026-06-12 11:02   ` sashiko-bot
2026-06-12 12:49   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 42/60] scsi: qla2xxx: Add LS4 pass-through IOCB handling for 29xx series Nilesh Javali
2026-06-12 12:50   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 43/60] scsi: qla2xxx: Convert NVMe ring advance to use qla_req_ring_advance() Nilesh Javali
2026-06-12 12:52   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 44/60] scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support Nilesh Javali
2026-06-12 11:16   ` sashiko-bot
2026-06-12 12:53   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 45/60] scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking Nilesh Javali
2026-06-12 12:56   ` Hannes Reinecke
2026-06-12 13:23   ` sashiko-bot
2026-06-12  9:53 ` [PATCH v2 46/60] scsi: qla2xxx: Replace __le16 bitfields with scalar and accessors Nilesh Javali
2026-06-12 12:57   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 47/60] scsi: qla2xxx: Fix endianness annotations in vp_rpt_id_entry structures Nilesh Javali
2026-06-12 12:59   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 48/60] scsi: qla2xxx: Use 64-bit FPM word counters for 29xx host stats Nilesh Javali
2026-06-12 13:00   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 49/60] scsi: qla2xxx: Add 64G/128G port speed setting support Nilesh Javali
2026-06-12 13:02   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 50/60] scsi: qla2xxx: Fix 64G link speed reporting in get_data_rate Nilesh Javali
2026-06-12 13:03   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 51/60] scsi: qla2xxx: edif: Fix NULL pointer deref in RX SA delete check Nilesh Javali
2026-06-12 11:43   ` sashiko-bot
2026-06-12 13:04   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 52/60] scsi: qla2xxx: Fix Name Server logout detection on FWI2 adapters Nilesh Javali
2026-06-12 13:08   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 53/60] scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size Nilesh Javali
2026-06-12 11:35   ` sashiko-bot
2026-06-12 13:09   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 54/60] scsi: qla2xxx: Check entry_status in qla24xx_modify_vp_config() Nilesh Javali
2026-06-12 13:10   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 55/60] scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition() Nilesh Javali
2026-06-12 11:38   ` sashiko-bot
2026-06-12 13:10   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 56/60] scsi: qla2xxx: Initialize NVMe abort_work once at submission Nilesh Javali
2026-06-12 11:34   ` sashiko-bot
2026-06-12 13:11   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 57/60] scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject Nilesh Javali
2026-06-12 11:39   ` sashiko-bot
2026-06-12 13:11   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 58/60] scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak Nilesh Javali
2026-06-12 11:40   ` sashiko-bot
2026-06-12 13:12   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 59/60] scsi: qla2xxx: Fix BSG job leak on validate flash image error path Nilesh Javali
2026-06-12 11:38   ` sashiko-bot
2026-06-12 13:12   ` Hannes Reinecke
2026-06-12  9:53 ` [PATCH v2 60/60] scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions() Nilesh Javali
2026-06-12 11:45   ` sashiko-bot
2026-06-12 13:13   ` Hannes Reinecke

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.