scsi: qla2xxx: Add QLA29xx series adapter support
Subsystems (3)
Nilesh Javali
maintainerv6 cover scsi: qla2xxx: Add QLA29xx series adapter support
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, removal of a redundant VPD flash read in the sysfs read path, and BSG passthrough (flash block I/O, MPI firmware load/dump).
Patches 09-11: 128-byte IOCB infrastructure
New qla_fw29.h header with extended structure definitions, status continuation and marker IOCBs, and IO-path updates that select the correct IOCB size via the entry-size helpers.
Patches 12-24: 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 25-39: Response-path IOCB handling and final wiring
Status continuation, status entry, CT pass-through, PUREX, ELS, logio, task management, abort, ABTS, VP control/config/report-ID, LS4 pass-through, and BSG feature gating adjustments.
Patches 40-55: bug fixes uncovered during review of the earlier postings
-- queue teardown NULL dma_free and bitmap locking, endianness/bitfield cleanups, 64-bit FPM word counters, 64G/128G port speed setting and reporting, an edif NULL deref, Name Server logout detection on FWI2 adapters, VP index bounds, NVMe abort and LS-reject locking, a dport diagnostics info leak, a BSG job leak, and an unbounded FRU image count.
Patch 56: bump the driver version to 12.00.00.2607b1.
The series applies on top of Linux 7.2-rc1.
Changes in v6:
- No functional change to the 29xx enablement. Dropped the image_length-based flash-region bounds check that had been folded into the flash block read/write BSG support commit (patch 07). image_length is the size of the image currently stored in a region, not the region's writable capacity, so the check falsely rejected legitimate flash updates that write a new, larger image (e.g. a region 0xd3 write of 0x99404 bytes). Firmware already enforces region isolation via the region-relative address, so the check added no correct protection. Removed the qla29xx_validate_flash_region() helper and its two callers, dropped the qla29xx_get_flash_region() export from qla_gbl.h, and restored the function to static in qla_sup.c.
Changes in v5:
- No functional change from v4. Folded the static-analysis and kernel test robot cleanups into the feature commits they touch, so every commit stays self-contained and bisectable:
- removed set-but-unused variables (chunk_count in the flash read/write interface, vha/ha in the 128-byte IO path);
- fixed kernel-doc parameter lists (added @ha and @data_sz, dropped the excess @bundling description);
- corrected the control_flags endianness annotation to cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE);
- relocated a misplaced out_29xx label flagged by sparse; and
- fixed two checkpatch indentation warnings on ql_dbg() calls.
- Added Reported-by: kernel test robot <[email protected]> and the matching Closes: links to the four affected commits.
Changes in v4:
- Folded the follow-up robustness and bug-fix commits that were posted as separate patches in v3 into the feature commits they correct, resolving their Fixes: tags by squashing, so every commit in the series is self-contained and bisectable with no "fix the previous patch" commits. The posting is now 56 patches (down from 88).
- Dropped fixes to pre-existing driver code that are independent of the 29xx series (e.g. the firmware-dump data-capture change) from this posting; they will be submitted separately.
- Rebased the series onto Linux 7.2-rc1.
Changes in v3:
- Folded several standalone helper and refactor commits into the feature commits they support, so every 29xx enablement commit is self-contained and bisectable: the entry-size helper conversion, the marker IOCB refactor, the NVMe IOCB build-path unification, the NVMe ring-advance conversion, and the duplicate flash-memo block removal are no longer separate patches.
- Reworked flash-version handling: dropped the standalone get_flash_version patch in favour of removing the redundant VPD flash read in the sysfs read path.
- Added a large batch of additional robustness and bug fixes uncovered during continued review, covering the completion/response path, NPIV and report-ID acquisition, NVMe unsolicited-context handling, and BSG passthrough hardening.
- Bumped the driver version to 12.00.00.2607b1.
- Added Reviewed-by: Hannes Reinecke <[email protected]> to the reviewed 29xx enablement patches.
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 (3):
scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx
scsi: qla2xxx: Add extended status continuation and marker IOCBs
scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx
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 29xx support in queue initialisation path
scsi: qla2xxx: Add FC operational firmware load for 29xx
scsi: qla2xxx: Remove redundant VPD flash read in sysfs read path
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 (43):
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: 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: 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()
scsi: qla2xxx: Update version to 12.00.00.2607b1
drivers/scsi/qla2xxx/qla_attr.c | 57 +- drivers/scsi/qla2xxx/qla_bsg.c | 537 ++++++++++- drivers/scsi/qla2xxx/qla_bsg.h | 34 + drivers/scsi/qla2xxx/qla_dbg.c | 31 +- drivers/scsi/qla2xxx/qla_def.h | 143 ++- drivers/scsi/qla2xxx/qla_dfs.c | 4 +- drivers/scsi/qla2xxx/qla_edif.c | 101 +- 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 | 176 +++- drivers/scsi/qla2xxx/qla_init.c | 735 +++++++++++++- drivers/scsi/qla2xxx/qla_inline.h | 282 +++++- drivers/scsi/qla2xxx/qla_iocb.c | 1419 ++++++++++++++++++++++------ drivers/scsi/qla2xxx/qla_isr.c | 676 ++++++++----- drivers/scsi/qla2xxx/qla_mbx.c | 476 ++++++++-- 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 | 781 ++++++++++++++- drivers/scsi/qla2xxx/qla_target.c | 34 +- drivers/scsi/qla2xxx/qla_version.h | 10 +- 24 files changed, 6099 insertions(+), 1048 deletions(-) create mode 100644 drivers/scsi/qla2xxx/qla_fw29.h
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 1/56 scsi: qla2xxx: Add 29xx series PCI device ID support
From: Manish Rangankar <[email protected]>
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.
--- 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(-)
drivers/scsi/qla2xxx/qla_def.h +24 -9
@@ -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 0x92struct 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 0x2291uint32_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) || \
drivers/scsi/qla2xxx/qla_init.c +1 -1
@@ -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 (®->mailbox12) &BIT_0 ) ha->flags.secure_adapter =1 ; ql_log(ql_log_info, vha, 0xffff, "Secure Adapter: %s\n",
drivers/scsi/qla2xxx/qla_isr.c +3 -2
@@ -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 );
drivers/scsi/qla2xxx/qla_os.c +60 -14
153 lines not on this page · raw message
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 01/56] scsi: qla2xxx: Add 29xx series PCI device ID support
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
New issues:
- [High] Critical architectural capability macros omit the QLA29xx family, silently breaking Target Mode and other hardware offloads.
- [High] Hardware queue doorbell registers are incorrectly evaluated when MSI-X is disabled, causing immediate I/O hangs on QLA29XX adapters.
- [High] Optrom sysfs handlers perform invalid flash address calculations for QLA29XX due to uninitialized (~0) offsets.
- [Medium] All four 29xx device-specific ISP type bits are OR'd together unconditionally, breaking individual device identification.
- [Medium] SysFS attributes and Block SCSI Generic (BSG) endpoints unconditionally reject requests for QLA29XX adapters.
Pre-existing issues:
- [High] Unchecked NULL pointer passed to dma_pool_free() in memory allocation error handling path.
- [High] MSI-X vector count truncation leads to ZERO_SIZE_PTR allocation and subsequent kernel panic. --
--- Patch [1]: [PATCH v6 01/56] scsi: qla2xxx: Add 29xx series PCI device ID support --- commit c27da2e671417436f3a15a5fd351d1bc9cab793a
Author: Manish Rangankar <[email protected]>
Subject: scsi: qla2xxx: Add 29xx series PCI device ID support
This commit introduces support for the QLA29xx series FC HBA by registering new PCI device IDs and adding capability checks in the probe and ISP-flag paths. It also extends speed-capability logic to initialize 29xx adapters.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_def.h +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_def.h struct qla_hw_data { · line 4431
Quoted 13 lines
drivers/scsi/qla2xxx/qla_def.h +3
-3@@ -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))
[Severity: High]
Are we missing QLA29XX additions in several other critical macros?
For instance, IS_ATIO_MSIX_CAPABLE() in qla_def.h omits IS_QLA29XX(ha). Without this, qla24xx_enable_msix() will skip allocating the ATIO queue MSI-X vector, which might cause Target Mode I/O hangs.
Similarly, ISP_QUE_REG() lacks IS_QLA29XX(ha). If mqenable is 0, this macro evaluates to ha->iobase instead of the expected mqiobase for newer adapters. Could this zero out unrelated registers in Region 0 during queue configuration?
[Severity: Medium]
Will administrative sysfs and BSG endpoints reject 29xx adapters?
Several management endpoints in qla_attr.c (like qla2x00_port_speed_store) and qla_bsg.c (like qla2x00_update_optrom) have explicit checks for !IS_QLA27XX(ha) && !IS_QLA28XX(ha). Without adding IS_QLA29XX to these checks, could user-space utilities attempting to read link data or execute firmware updates fail with -EPERM?
Quoted 3 lines
drivers/scsi/qla2xxx/qla_def.h +0
-0#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) || \
[ ... ]
Quoted 4 lines
drivers/scsi/qla2xxx/qla_os.c +0
-0
[ ... ]
Quoted 12 lines
drivers/scsi/qla2xxx/qla_os.c +4
-3@@ -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 ) {
drivers/scsi/qla2xxx/qla_os.c qla83xx_iospace_config(struct qla_hw_data *ha) · line 2219
Quoted 10 lines
drivers/scsi/qla2xxx/qla_os.c +7
-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)
[Severity: High]
This is a pre-existing issue, but could this vector count calculation lead to a kernel panic?
In qla83xx_iospace_config(), pci_msix_vec_count() returns the board's supported MSI-X vectors, and the driver bounds it:
ha->max_req_queues = ha->msix_count - 1;
Since max_req_queues is an 8-bit unsigned integer (uint8_t), if a device supports 257 or more vectors, max_req_queues will overflow to 0.
When passed to kzalloc_objs() in qla2x00_alloc_queues():
ha->req_q_map = kzalloc_objs(struct req_que *, ha->max_req_queues);
This 0-sized request returns ZERO_SIZE_PTR (0x10), which is later dereferenced during queue initialization. Should we cap the msix_count to ensure it fits within the 8-bit limit?
[ ... ]
drivers/scsi/qla2xxx/qla_os.c qla2x00_set_isp_flags(struct qla_hw_data *ha) · line 2813
Quoted 12 lines
drivers/scsi/qla2xxx/qla_os.c +8
-0@@ -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 ;
[Severity: Medium]
Does this unconditionally combine all four 29xx device-specific bits?
When any QLA29XX adapter is probed, all four bits are OR'd into ha->isp_type. Will this cause specific device capability macros like IS_QLA2299(ha) to incorrectly evaluate to true for all 29xx models (e.g., ISP2091), breaking individual device identification?
Quoted 7 lines
drivers/scsi/qla2xxx/qla_os.c +6
-0+ 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 ; }
[ ... ]
Quoted 8 lines
drivers/scsi/qla2xxx/qla_os.c +4
-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 ;
drivers/scsi/qla2xxx/qla_os.c qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) · line 3237
Quoted 10 lines
drivers/scsi/qla2xxx/qla_os.c +10
-0+ 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 ;
[Severity: High]
Will this generate an invalid physical address during firmware mailbox commands?
For the QLA29XX, the driver assigns ha->isp_ops = &qla27xx_isp_ops; but sets ha->flash_data_off = ~0.
When the inherited 27xx read_optrom sysfs handler calls flash_data_addr(), it calculates ha->flash_data_off + faddr. Since the offset is ~0, this will wrap around to faddr - 1.
Could using this invalid physical address in commands like qla2x00_dump_ram lead to uncontrolled firmware memory corruption or an adapter hang?
Quoted 3 lines
drivers/scsi/qla2xxx/qla_os.c +2
-0+ ha->nvram_conf_off = ~0 ; + ha->nvram_data_off = ~0 ; }
[ ... ]
drivers/scsi/qla2xxx/qla_os.c qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, · line 4434
Quoted 8 lines
drivers/scsi/qla2xxx/qla_os.c +1
-1@@ -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);
[Severity: High]
This isn't a bug introduced by this patch, but could this error recovery path cause a kernel panic?
If a memory allocation fails during qla2x00_mem_alloc(), the error recovery paths unconditionally call dma_pool_free():
fail_async_pd:
dma_pool_free(ha->s_dma_pool, ha->sf_init_cb, ha->sf_init_cb_dma);
fail_sf_init_cb:
dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma);If these pointers were never allocated, they remain NULL. Passing a NULL pointer to dma_pool_free() causes an invalid memory dereference when virt_to_head_page() evaluates it. Should we add NULL checks before freeing these pool objects?
Quoted 1 line
drivers/scsi/qla2xxx/qla_os.c +0
-0if (!ha->ex_init_cb)
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Nilesh Javali
maintainerPATCH v6 2/56 scsi: qla2xxx: Add flash read/write interface for 29xx
In reply to Nilesh JavaliFrom: Manish Rangankar <[email protected]>
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.
--- 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 | 660 ++++++++++++++++++++++++++++++++- 6 files changed, 898 insertions(+), 13 deletions(-)
drivers/scsi/qla2xxx/qla_def.h +20 -0
@@ -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 4096void *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
drivers/scsi/qla2xxx/qla_fw.h +54 -0
66 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_gbl.h +14 -1
@@ -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. */
drivers/scsi/qla2xxx/qla_mbx.c +144 -0
147 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_os.c +17 -1
@@ -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 ;
drivers/scsi/qla2xxx/qla_sup.c +649 -11
718 lines not on this page · raw message
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 02/56] scsi: qla2xxx: Add flash read/write interface for 29xx
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] The new 29xx-specific flash read/write handlers (`qla29xx_read_optrom_data` and…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The new 29xx-specific flash read/write handlers (qla29xx_read_optrom_data and qla29xx_write_optrom_data) are not wired into the isp_ops table, breaking generic sysfs/bsg flash infrastructure for 29xx hardware. --
--- Patch [2]: [PATCH v6 02/56] scsi: qla2xxx: Add flash read/write interface for 29xx --- commit dc1689f4151bef091f39c3e7154f59adc5ea0501
Author: Manish Rangankar <[email protected]>
scsi: qla2xxx: Add flash read/write interface for 29xx
This patch adds mailbox wrappers and helper functions to support flash read and write operations for the 29xx series adapters. It also intends to wire these operations into the existing flash infrastructure.
Quoted 5 lines
The 29xx series uses a different flash access mechanism than earlier adapters. Add the mailbox wrappers and
qla_suphelpers needed for flash read and write operations, including the necessary hooks inisp_opsso that the existing flash infrastructure can drive the new hardware.
Is this commit message accurate? The patch introduces the new 29xx-specific flash handlers, but it does not appear to register them in the isp_ops table.
drivers/scsi/qla2xxx/qla_os.c qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) · line 3241
Quoted 10 lines
drivers/scsi/qla2xxx/qla_os.c +1
-0@@ -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 ; }
[Severity: High]
Will this cause the generic sysfs/bsg flash infrastructure to crash when used on 29xx hardware?
Because the new 29xx-specific handlers are missing from the isp_ops table, interactions with standard sysfs/BSG optrom interfaces will route to the legacy flash routines instead.
When legacy routines like qla25xx_read_optrom_data run, they calculate the flash address by adding ha->flash_data_off. Since flash_data_off is initialized to ~0 here, the resulting address wraps around to 0xFFFFFFFF.
Could this lead to severe PCIe errors (Target Abort), SError faults on ARM, or firmware lockups when the hardware is instructed to read or write to 0xFFFFFFFF?
Quoted 4 lines
drivers/scsi/qla2xxx/qla_sup.c +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_sup.c line 435
Quoted 4 lines
drivers/scsi/qla2xxx/qla_sup.c +4
-0+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)
[Severity: High]
How will this be hooked up to isp_ops->read_optrom?
The standard isp_ops->read_optrom hook expects a 4-argument signature, but this newly defined function has 6 arguments. Was a wrapper function intended to bridge this gap so it could actually be assigned to the isp_ops table?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Nilesh Javali
maintainerPATCH v6 3/56 scsi: qla2xxx: Add NVRAM config support for 29xx adapters
In reply to Nilesh JavaliFrom: Manish Rangankar <[email protected]>
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.
--- 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(-)
drivers/scsi/qla2xxx/qla_def.h +1 -0
@@ -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;
drivers/scsi/qla2xxx/qla_fw.h +41 -1
58 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_init.c +97 -26
166 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_os.c +2 -0
@@ -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);
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 03/56] scsi: qla2xxx: Add NVRAM config support for 29xx adapters
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] The pointer ha->fiv is not set to NULL when qla29xx_read_optrom_data() fails, leaving it pointing…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The pointer ha->fiv is not set to NULL when qla29xx_read_optrom_data() fails, leaving it pointing to a zeroed buffer instead of correctly indicating absence. --
--- Patch [3]: [PATCH v6 03/56] scsi: qla2xxx: Add NVRAM config support for 29xx adapters --- commit d8579bb80f870f714d329c213d6291f565f67160
Author: Manish Rangankar <[email protected]>
scsi: qla2xxx: Add NVRAM config support for 29xx adapters
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.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_init.c +0
-0
[ ... ]
Quoted 1 line
drivers/scsi/qla2xxx/qla_init.c +0
-0@@ -9306,35 +9306,98 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
[ ... ]
Quoted 11 lines
drivers/scsi/qla2xxx/qla_init.c +0
-0if (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 );
drivers/scsi/qla2xxx/qla_init.c
Quoted 10 lines
drivers/scsi/qla2xxx/qla_init.c +0
-0ha->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" );
[Severity: Low]
Should ha->fiv be set to NULL here when the FMB read fails?
Currently, if qla29xx_read_optrom_data() returns NULL, ha->fiv continues to point at (ha->vpd + ha->vpd_size) rather than correctly indicating absence. In the signature mismatch case below, it is explicitly set to NULL. Does this leave a dangling reference to uninitialized memory that could confuse future code checking if ha->fiv is valid?
Quoted 7 lines
drivers/scsi/qla2xxx/qla_init.c +0
-0}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 {
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Nilesh Javali
maintainerPATCH v6 4/56 scsi: qla2xxx: Add 29xx support in queue initialisation path
In reply to Nilesh JavaliFrom: Manish Rangankar <[email protected]>
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).
--- 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(-)
drivers/scsi/qla2xxx/qla_def.h +30 -0
@@ -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. */
drivers/scsi/qla2xxx/qla_mbx.c +13 -7
@@ -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 ); }
drivers/scsi/qla2xxx/qla_mid.c +21 -4
@@ -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,
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 04/56] scsi: qla2xxx: Add 29xx support in queue initialisation path
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [Critical] Base request and response queues (queue index 0) and fallback frees ignore the new 128-byte…
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] Base request and response queues (queue index 0) and fallback frees ignore the new 128-byte size requirement for 29xx hardware, leading to memory corruption and leaks.
- [High] Ring pointer arithmetic for out_ptr and in_ptr calculates incorrect offsets for QLA29XX adapters, causing memory corruption and breaking bisectability.
- [Medium] The firmware dump logic hardcodes the 64-byte legacy queue sizes, which will result in an undersized dump buffer and truncated queue data for 29xx adapters. --
--- Patch [4]: [PATCH v6 04/56] scsi: qla2xxx: Add 29xx support in queue initialisation path --- commit 892bfd1ade358d1fd826e15942668d47268a93f3
Author: Manish Rangankar <[email protected]>
scsi: qla2xxx: Add 29xx support in queue initialisation path
This commit extends the queue initialization and multi-queue management mailbox commands for 29xx adapters. It introduces 128-byte entry structures and updates DMA allocations to account for the larger entries on 29xx.
Quoted 11 lines
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 structrequest_extand structresponse_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.
Quoted 4 lines
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).
[Severity: Critical]
Does this commit update the base request and response queues (queue index 0) and fallback frees for 29xx hardware?
Looking at qla2x00_mem_alloc() in drivers/scsi/qla2xxx/qla_os.c, it allocates the base request queue with a hardcoded 64-byte size:
(*req)->ring = dma_alloc_coherent(&ha->pdev->dev,
((*req)->length + 1) * sizeof(request_t),
&(*req)->dma, GFP_KERNEL);And similarly in qla2x00_free_req_que(), it uses sizeof(request_t) to free the queue. Will this cause the hardware to operate with 128-byte entries on a queue allocated for 64-byte entries, leading to memory corruption and DMA allocator corruption on 29xx adapters?
[Severity: Medium]
Will the firmware dump logic truncate the 128-byte entries on 29xx adapters?
Looking at qla2x00_alloc_fw_dump() in drivers/scsi/qla2xxx/qla_init.c, it calculates the dump size assuming 64-byte queue entries:
req_q_size = req->length * sizeof(request_t);
rsp_q_size = rsp->length * sizeof(response_t);And qla24xx_dump_ram() in drivers/scsi/qla2xxx/qla_dbg.c copies only 64 bytes per entry:
memcpy(ptr, req->ring, req->length * sizeof(request_t));
Could this result in an undersized dump buffer and truncated queue data for 29xx hardware?
Quoted 4 lines
drivers/scsi/qla2xxx/qla_mid.c +0
-0
[ ... ]
Quoted 10 lines
drivers/scsi/qla2xxx/qla_mid.c +1
-0@@ -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;
drivers/scsi/qla2xxx/qla_mid.c qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, · line 733
Quoted 10 lines
drivers/scsi/qla2xxx/qla_mid.c +4
-1} + 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 );
[Severity: High]
Since pointer arithmetic is handled in later patches in this series, does this break bisectability here?
Looking at qla25xx_create_req_que() in drivers/scsi/qla2xxx/qla_mid.c, the out_ptr sits after the ring buffer:
req->out_ptr = (uint16_t *)(req->ring + req->length);
Because req->ring is a request_t pointer (64-byte stride), adding req->length advances it by length * 64 bytes. For 29xx, the queue stride is 128 bytes, so the shadow pointer will point into the middle of the allocated ring buffer instead of immediately after it. Will this cause memory corruption when the driver or hardware accesses the shadow pointers?
The same issue seems to apply to rsp->in_ptr in qla25xx_create_rsp_que().
Is there a way to make this commit safe for bisection?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
Nilesh Javali
maintainerPATCH v6 5/56 scsi: qla2xxx: Add FC operational firmware load for 29xx
In reply to Nilesh JavaliFrom: Manish Rangankar <[email protected]>
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.
--- drivers/scsi/qla2xxx/qla_fw.h | 36 +++ drivers/scsi/qla2xxx/qla_gbl.h | 3 +- drivers/scsi/qla2xxx/qla_init.c | 546 +++++++++++++++++++++++++++++++- 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, 643 insertions(+), 14 deletions(-)
drivers/scsi/qla2xxx/qla_fw.h +36 -0
@@ -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
drivers/scsi/qla2xxx/qla_gbl.h +2 -1
@@ -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 );
drivers/scsi/qla2xxx/qla_init.c +541 -5
582 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_mbx.c +15 -4
@@ -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);
drivers/scsi/qla2xxx/qla_nx.c +1 -1
@@ -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 "
drivers/scsi/qla2xxx/qla_os.c +46 -1
86 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_sup.c +2 -2
@@ -1913,7 +1913,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 ;
@@ -3513,7 +3513,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",
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 05/56] scsi: qla2xxx: Add FC operational firmware load for 29xx
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
New issues:
- [High] The .start_scsi function pointer is missing from the qla29xx_isp_ops structure.
- [High] The .read_optrom and .write_optrom callbacks in qla29xx_isp_ops incorrectly use legacy handlers that trigger invalid flash accesses.
- [High] qla29xx_load_fw_template() misinterprets the firmware dump template size as bytes instead of dwords, leading to severe memory under-allocation.
- [High] qla29xx_load_fw_template() fails to skip the flash region header when extracting the firmware dump template, breaking validation.
- [High] Firmware dump template validation failures in 29xx load paths incorrectly abort the entire adapter initialization.
Pre-existing issues:
- [High] Use-After-Free in ha->mpi_fw_dump pointer when firmware dump buffer is reallocated. --
--- Patch [5]: [PATCH v6 05/56] scsi: qla2xxx: Add FC operational firmware load for 29xx --- commit ed0a0bf5b60c5fe925e18499926faba91b6ac03a
Author: Manish Rangankar <[email protected]>
scsi: qla2xxx: Add FC operational firmware load for 29xx
This commit adds support to load the 29xx FC operational firmware from the filesystem and to set up the corresponding firmware dump template. It follows the same request_firmware and segment load pattern used by earlier adapters.
drivers/scsi/qla2xxx/qla_init.c qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) · line 3944
Quoted 13 lines
drivers/scsi/qla2xxx/qla_init.c +2
-1@@ -3937,7 +3937,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)"Allocated (%d KB) for firmware dump.\n" , dump_size / 1024); -if (IS_QLA27XX (ha) ||IS_QLA28XX (ha)) { +if (IS_QLA27XX (ha) ||IS_QLA28XX (ha) || +IS_QLA29XX (ha)) { ha->mpi_fw_dump = (char *)fw_dump + ha->fwdt[1 ].dump_size;mutex_unlock (&ha->optrom_mutex);
[Severity: High]
This is a pre-existing issue, but does adding 29xx to this path expose a use-after-free when the firmware dump buffer is reallocated?
Earlier in qla2x00_alloc_fw_dump(), when ha->fw_dumped is true, the old buffer is freed via vfree(ha->fw_dump) and reallocated. However, the ha->mpi_fw_dump pointer is not updated to point into the new buffer. It seems it will remain pointing to the freed memory, and a subsequent MPI firmware dump would corrupt memory.
[ ... ]
Quoted 3 lines
drivers/scsi/qla2xxx/qla_init.c +3
-0+static int +qla29xx_load_risc_blob (scsi_qla_host_t *vha,uint32_t *srisc_addr) +{
[ ... ]
drivers/scsi/qla2xxx/qla_init.c qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) · line 9529
Quoted 8 lines
drivers/scsi/qla2xxx/qla_init.c +8
-0+failed: +vfree (fwdt->template); + fwdt->template =NULL ; + fwdt->length =0 ; +img_corrupt: +vfree (header); +return QLA_FUNCTION_FAILED ; +}
[Severity: High]
Should template validation failures in the 29xx load paths abort the entire adapter initialization?
In previous hardware generations, firmware dump template failures are treated as non-fatal and return QLA_SUCCESS, allowing the driver to operate without firmware dump capabilities. Returning QLA_FUNCTION_FAILED here propagates up and makes the adapter completely unusable if the optional template validation fails.
[ ... ]
Quoted 3 lines
drivers/scsi/qla2xxx/qla_init.c +3
-0+static int +qla29xx_load_fw_template (scsi_qla_host_t *vha) +{
[ ... ]
Quoted 4 lines
drivers/scsi/qla2xxx/qla_init.c +4
-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",
drivers/scsi/qla2xxx/qla_init.c qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) · line 9592
Quoted 10 lines
drivers/scsi/qla2xxx/qla_init.c +10
-0+ j, fw_dump_tmplt, template_size); + +if (!template_size || !~template_size || + template_size > ha->fw_dump_tmplt_len) { +ql_dbg (ql_dbg_init, vha,0x0162 , +"-> fwdt%u failed to read array\n" , j); + goto failed; + } + + fwdt->template =vmalloc (template_size);
[Severity: High]
Does this misinterpret the firmware dump template size as bytes instead of dwords?
The template_size is read from the flash header which typically stores the size in dwords. Passing this directly to vmalloc() and memcpy() would allocate and copy only 25 percent of the needed memory, and guarantee that the subsequent size verification (len > template_size) fails.
drivers/scsi/qla2xxx/qla_init.c qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) · line 9602
Quoted 10 lines
drivers/scsi/qla2xxx/qla_init.c +10
-0+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)) {
[Severity: High]
Does this copy fail to skip the 7-dword flash region header?
Other firmware load functions skip the header before extracting the template. Copying directly from offset 0 means the dcode buffer points to the flash header instead of the template header, which would cause qla27xx_fwdt_template_valid() to unconditionally fail.
[ ... ]
drivers/scsi/qla2xxx/qla_init.c qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) · line 9632
Quoted 4 lines
drivers/scsi/qla2xxx/qla_init.c +4
-0+free_fw_dump: +kfree (fw_dump_tmplt); +return QLA_FUNCTION_FAILED ; +}
[Severity: High]
As mentioned above, should this optional firmware dump template failure abort the entire adapter initialization? Returning QLA_FUNCTION_FAILED here will fail the probe.
[ ... ]
drivers/scsi/qla2xxx/qla_os.c static struct isp_operations qla27xx_isp_ops = { · line 2644
Quoted 9 lines
drivers/scsi/qla2xxx/qla_os.c +2
-0@@ -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,
[Severity: High]
The start_scsi function pointer appears to be missing from the qla29xx_isp_ops structure.
In qla2xxx_queuecommand(), if ha->mqenable evaluates to 0 (which happens if MSI-X allocation fails or is disabled by user), the driver falls back to single-queue mode and explicitly calls ha->isp_ops->start_scsi(). Does this missing callback cause a fatal NULL pointer dereference on the first submitted SCSI I/O?
[ ... ]
drivers/scsi/qla2xxx/qla_os.c static struct isp_operations qla27xx_isp_ops = { · line 2674
Quoted 5 lines
drivers/scsi/qla2xxx/qla_os.c +5
-0+ .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,
[Severity: High]
Are these legacy flash I/O functions compatible with the 29xx adapter?
These functions compute flash addresses using flash_data_addr(), which adds ha->flash_data_off to the offset. For 29xx, ha->flash_data_off is initialized to ~0 (0xFFFFFFFF). This appears to cause invalid flash reads and writes.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
Re: [PATCH v6 05/56] scsi: qla2xxx: Add FC operational firmware load for 29xx
In reply to Nilesh Javalidrivers/scsi/qla2xxx/qla_init.c qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) · line 9182
Quoted 9 lines · Nilesh Javali
drivers/scsi/qla2xxx/qla_init.c +9
-0+ +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 ; + }
Not that this is generating a warning for i386 builds on the mkp-scsi 7.3 staging branch:
drivers/scsi/qla2xxx/qla_init.c: In function ‘qla29xx_process_rd_image’:drivers/scsi/qla2xxx/qla_init.c:9272:53: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 6 has type ‘size_t’ {aka ‘unsigned int’} [-Werror=format=]
9272 | "TIM section too large (0x%x bytes, ring 0x%lx bytes).\n",
| ~~^
| |
| long
unsigned int
| %x
9273 | section_size,
9274 | req->length * qla_req_entry_size(ha));
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| size_t {aka unsigned int}cc1: all warnings being treated as errors
[REGRESSION] Re: [PATCH v6 05/56] scsi: qla2xxx: Add FC operational firmware load for 29xx
Quoted 29 lines · John Garry
drivers/scsi/qla2xxx/qla_init.c qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) · line 9182
Quoted 9 lines · Nilesh Javali
drivers/scsi/qla2xxx/qla_init.c +9
-0+ +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 ; + }Not that this is generating a warning for i386 builds on the mkp-scsi 7.3 staging branch:
drivers/scsi/qla2xxx/qla_init.c: In function ‘qla29xx_process_rd_image’:drivers/scsi/qla2xxx/qla_init.c:9272:53: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 6 has type ‘size_t’ {aka ‘unsigned int’} [-Werror=format=]9272 | "TIM section too large (0x%x bytes, ring 0x%lx bytes).\n", | ~~^ | | | long unsigned int | %x 9273 | section_size, 9274 | req->length * qla_req_entry_size(ha)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | size_t {aka unsigned int}
Quoted 1 line
cc1: all warnings being treated as errors
This patch became commit c3930ec119cb ("scsi: qla2xxx: Add FC operational firmware load for 29xx") now and is included in next-20260810 and later.
#regzbot introduced: c3930ec119cb916be879c017ea1e389e05dbe1aa ^
Best regards
Uwe
Nilesh Javali
maintainerPATCH v6 6/56 scsi: qla2xxx: Remove redundant VPD flash read in sysfs read path
In reply to Nilesh JavaliFrom: Manish Rangankar <[email protected]>
qla2x00_sysfs_read_vpd() called ha->isp_ops->read_optrom() a second time after releasing optrom_mutex. The repeated read is redundant and, unlike the first, runs without optrom_mutex held, exposing flash access to concurrent optrom operations. Drop the duplicate call.
--- drivers/scsi/qla2xxx/qla_attr.c | 1 - 1 file changed, 1 deletion(-)
drivers/scsi/qla2xxx/qla_attr.c +0 -1
@@ -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); }
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 06/56] scsi: qla2xxx: Remove redundant VPD flash read in sysfs read path
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Unprotected flash hardware register access in qla2x00_sysfs_read_vpd(). --
--- Patch [6]: [PATCH v6 06/56] scsi: qla2xxx: Remove redundant VPD flash read in sysfs read path --- commit e9338dabc7b53d75f2d4ddaf069664fa8b72258d
Author: Manish Rangankar <[email protected]>
Subject: scsi: qla2xxx: Remove redundant VPD flash read in sysfs read path
This patch removes a redundant and unprotected call to read_optrom() in qla2x00_sysfs_read_vpd(). By dropping the second call, it prevents exposing flash accesses to concurrent optrom operations while optrom_mutex is not held.
drivers/scsi/qla2xxx/qla_attr.c qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
Quoted 5 lines
drivers/scsi/qla2xxx/qla_attr.c +0
-0@@ -580,7 +580,6 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
[Severity: High]
This is a pre-existing issue, but does calling qla28xx_get_aux_images() earlier in qla2x00_sysfs_read_vpd() without holding optrom_mutex risk corrupting the flash hardware state?
While this patch successfully addresses the unprotected read_optrom() call below, qla28xx_get_aux_images() is still called before the lock is acquired:
qla2x00_sysfs_read_vpd() {
...
if (IS_QLA28XX(ha)) {
qla28xx_get_aux_images(vha, &active_regions);
...
}
mutex_lock(&ha->optrom_mutex);
...
}Because qla28xx_get_aux_images() eventually performs raw MMIO accesses to the flash hardware registers, could concurrent sysfs reads to the vpd attribute interleave these writes and reads (e.g., to reg->flash_addr and reg->flash_data) and corrupt the ISP flash hardware state machine?
Quoted 7 lines
drivers/scsi/qla2xxx/qla_attr.c +0
-1ha->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); }
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
Nilesh Javali
maintainerPATCH v6 7/56 scsi: qla2xxx: Add flash block read/write BSG support for 29xx
In reply to Nilesh JavaliFrom: Manish Rangankar <[email protected]>
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.
--- drivers/scsi/qla2xxx/qla_bsg.c | 298 ++++++++++++++++++++++++++++----- drivers/scsi/qla2xxx/qla_bsg.h | 16 ++ drivers/scsi/qla2xxx/qla_def.h | 7 + drivers/scsi/qla2xxx/qla_os.c | 24 ++- 4 files changed, 304 insertions(+), 41 deletions(-)
drivers/scsi/qla2xxx/qla_bsg.c +259 -39
@@ -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,182 @@ 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); + +if (brcmd->region >U16_MAX ) { +ql_log (ql_log_warn, vha,0x7066 , +"%s: invalid region 0x%x\n" , __func__, brcmd->region); +return -EINVAL ; + } + +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 0 ; +} + +/** +* 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); + +if (bwcmd->region >U16_MAX ) { +ql_log (ql_log_warn, vha,0x7067 , +"%s: invalid region 0x%x\n" , __func__, bwcmd->region); +return -EINVAL ; + } + +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 +3221,12 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_jcase 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 ; }
drivers/scsi/qla2xxx/qla_bsg.h +16 -0
@@ -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
drivers/scsi/qla2xxx/qla_def.h +7 -0
@@ -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 *);
drivers/scsi/qla2xxx/qla_os.c +22 -2
@@ -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,
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 07/56] scsi: qla2xxx: Add flash block read/write BSG support for 29xx
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [Medium] The BSG request length check double-counts the union size, incorrectly forcing an 8-byte extraneous padding and rejecting perfectly sized userspace requests with -EINVAL.
Pre-existing issues:
- [High] Unconditional read of vendor_cmd[0] without request_len validation leads to a heap out-of-bounds read if the userspace request is undersized. --
--- Patch [7]: [PATCH v6 07/56] scsi: qla2xxx: Add flash block read/write BSG support for 29xx --- commit 57ce5ec988753c7bc4221ec14672382fc6af4d41
Author: Manish Rangankar <[email protected]>
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.
Quoted 3 lines
drivers/scsi/qla2xxx/qla_bsg.c +0
-0
[ ... ]
Quoted 15 lines
drivers/scsi/qla2xxx/qla_bsg.c +11
-0@@ -1554,6 +1592,182 @@ 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);
drivers/scsi/qla2xxx/qla_bsg.c qla2x00_update_optrom(struct bsg_job *bsg_job) · line 1615
Quoted 10 lines
drivers/scsi/qla2xxx/qla_bsg.c +10
-0+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 ;
[Severity: Medium]
Does this length check double-count the first two 32-bit words of the vendor command?
Since sizeof(struct fc_bsg_request) already includes the 16-byte union space for rqst_data, the first 8 bytes of vendor_cmd are effectively counted twice.
By adding 2 * sizeof(uint32_t), does this incorrectly force an 8-byte padding, causing valid 84-byte requests from userspace tools to be rejected with -EINVAL unless they are padded to 92 bytes?
[ ... ]
Quoted 4 lines
drivers/scsi/qla2xxx/qla_bsg.c +4
-0+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;
drivers/scsi/qla2xxx/qla_bsg.c qla2x00_update_optrom(struct bsg_job *bsg_job) · line 1705
Quoted 10 lines
drivers/scsi/qla2xxx/qla_bsg.c +10
-0+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 ;
[Severity: Medium]
Similarly, does this length check also mistakenly double-count the first two 32-bit words, incorrectly rejecting valid unpadded write requests?
[ ... ]
drivers/scsi/qla2xxx/qla_bsg.c qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_j · line 3228
Quoted 9 lines
drivers/scsi/qla2xxx/qla_bsg.c +5
-0@@ -3007,6 +3221,12 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_jcase 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);
[Severity: High]
This is a pre-existing issue, but since we are adding new vendor commands here, is it possible to trigger an out-of-bounds read if the userspace request is undersized?
Looking at qla2x00_process_vendor_specific() and qla24xx_bsg_request(), the code unconditionally accesses bsg_request->rqst_data.h_vendor.vendor_cmd[0] without verifying that bsg_job->request_len is at least 16 bytes.
If a process with CAP_SYS_RAWIO submits a FC_BSG_HST_VENDOR request with request_len set to 12, the block layer allocates exactly 12 bytes. Reading vendor_cmd[0] at offset 12 could lead to a heap out-of-bounds read.
Would it make sense to add a request_len bounds check before inspecting vendor_cmd[0] to prevent this?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
Nilesh Javali
maintainerPATCH v6 8/56 scsi: qla2xxx: Add BSG MPI firmware load/dump for 29xx
In reply to Nilesh JavaliFrom: Manish Rangankar <[email protected]>
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.
--- drivers/scsi/qla2xxx/qla_bsg.c | 203 +++++++++++++++++++++++++++++++++ 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, 393 insertions(+)
drivers/scsi/qla2xxx/qla_bsg.c +203 -0
@@ -1768,6 +1768,203 @@ static int qla29xx_bsg_flash_block_write(struct bsg_job *bsg_job)return 0 ; } +static int +qla29xx_mpi_optrom_setup (struct bsg_job *bsg_job,scsi_qla_host_t *vha, +uint32_t start,uint8_t is_update) +{ +struct qla_hw_data *ha = vha->hw; + +if (unlikely (pci_channel_offline (ha->pdev))) +return -EINVAL ; + +if (ha->optrom_state !=QLA_SWAITING ) { +ql_log (ql_log_info, vha,0x7068 , +"optrom_state %d.\n" , ha->optrom_state); +return -EBUSY ; + } + + ha->optrom_region_start = start; +if (is_update) { + ha->optrom_region_size = bsg_job->request_payload.payload_len; + ha->optrom_state =QLA_SWRITING ; + }else { + ha->optrom_region_size = 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,0x7069 , +"%s: Unable to allocate memory for optrom retrieval (%x)\n" , + __func__, ha->optrom_region_size); + ha->optrom_state =QLA_SWAITING ; +return -ENOMEM ; + } + +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 ; + +if (!IS_QLA29XX (ha)) { +ql_log (ql_log_warn, vha,0x706c , +"%s: MPI dump not supported on this adapter.\n" , + __func__); +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 =qla29xx_mpi_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 ; + +if (!IS_QLA29XX (ha)) { +ql_log (ql_log_warn, vha,0x706d , +"%s: MPI load not supported on this adapter.\n" , + __func__); +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 =qla29xx_mpi_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) {
@@ -3227,6 +3424,12 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_jcase 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 ; }
drivers/scsi/qla2xxx/qla_bsg.h +18 -0
@@ -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
drivers/scsi/qla2xxx/qla_def.h +5 -0
@@ -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
drivers/scsi/qla2xxx/qla_gbl.h +5 -0
@@ -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. */
drivers/scsi/qla2xxx/qla_mbx.c +45 -0
48 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_sup.c +117 -0
123 lines not on this page · raw message
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 08/56] scsi: qla2xxx: Add BSG MPI firmware load/dump for 29xx
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] Double completion of a BSG job resulting in use-after-free in the block layer. - [High] Swapped…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Double completion of a BSG job resulting in use-after-free in the block layer.
- [High] Swapped semantics between LOAD and DUMP operations for MPI firmware. --
--- Patch [8]: [PATCH v6 08/56] scsi: qla2xxx: Add BSG MPI firmware load/dump for 29xx --- commit cd4037683fe65a034825a9797719d6d2dd2a6eb6
Author: Manish Rangankar <[email protected]>
scsi: qla2xxx: Add BSG MPI firmware load/dump for 29xx
This commit adds BSG vendor commands for loading and dumping MPI firmware on 29xx adapters. It extends the existing BSG infrastructure by providing necessary mailbox wrappers and flash helpers for MPI operations.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_bsg.c +0
-0
[ ... ]
Quoted 1 line
drivers/scsi/qla2xxx/qla_bsg.c +0
-0@@ -1768,6 +1768,203 @@ static int qla29xx_bsg_flash_block_write(struct bsg_job *bsg_job)
[ ... ]
Quoted 2 lines
drivers/scsi/qla2xxx/qla_bsg.c +2
-0+static int qla2900_bsg_dump_mpi (struct bsg_job *bsg_job) +{
[ ... ]
drivers/scsi/qla2xxx/qla_bsg.c static int qla29xx_bsg_flash_block_write(struct bsg_job *bsg_job) · line 1837
Quoted 2 lines
drivers/scsi/qla2xxx/qla_bsg.c +2
-0+mutex_lock (&ha->optrom_mutex); + rval =qla29xx_mpi_optrom_setup (bsg_job, vha, dmcmd->mpi_address,1 );
[Severity: High]
Are the semantics for DUMP and LOAD swapped in these functions?
It looks like the dump function sets is_update to 1 here, which reads from the request payload and writes to the adapter.
Quoted 8 lines
drivers/scsi/qla2xxx/qla_bsg.c +8
-0+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);
[ ... ]
Quoted 4 lines
drivers/scsi/qla2xxx/qla_bsg.c +4
-0+ rval =qla29xx_mpi_optrom_data (vha, opts, ha->optrom_buffer, + ha->optrom_region_start, + ha->optrom_region_size, +QLA29XX_MPI_OP_DUMP );
[ ... ]
Quoted 2 lines
drivers/scsi/qla2xxx/qla_bsg.c +2
-0+static int qla2900_bsg_load_mpi (struct bsg_job *bsg_job) +{
[ ... ]
drivers/scsi/qla2xxx/qla_bsg.c static int qla29xx_bsg_flash_block_write(struct bsg_job *bsg_job) · line 1915
Quoted 2 lines
drivers/scsi/qla2xxx/qla_bsg.c +2
-0+mutex_lock (&ha->optrom_mutex); + rval =qla29xx_mpi_optrom_setup (bsg_job, vha, lmcmd->mpi_address,0 );
[Severity: High]
Conversely, the load function sets is_update to 0 here, reading from the adapter into the reply payload.
Could this accidentally overwrite the adapter firmware when a user merely attempts to dump it?
Quoted 4 lines
drivers/scsi/qla2xxx/qla_bsg.c +4
-0+if (rval) { +mutex_unlock (&ha->optrom_mutex); +return rval; + }
[ ... ]
drivers/scsi/qla2xxx/qla_bsg.c static int qla29xx_bsg_flash_block_write(struct bsg_job *bsg_job) · line 1965
Quoted 10 lines
drivers/scsi/qla2xxx/qla_bsg.c +10
-0+ 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;
[Severity: High]
Does returning a non-zero rval here cause a double completion?
If qla29xx_mpi_optrom_data() fails, rval is returned as an error code. Since bsg_job_done() was already called above, the BSG caller (fc_bsg_host_dispatch) might see the non-zero return value, treat it as a dispatch failure, and call bsg_job_done() a second time on the same job.
Could this lead to a use-after-free in the block layer?
Quoted 1 line
+}
[ ... ]
Quoted 4 lines
drivers/scsi/qla2xxx/qla_sup.c +0
-0
[ ... ]
Quoted 1 line
drivers/scsi/qla2xxx/qla_sup.c +0
-0@@ -541,6 +541,123 @@ qla29xx_read_optrom_data(struct scsi_qla_host *vha, uint16_t reg_code,
[ ... ]
Quoted 4 lines
drivers/scsi/qla2xxx/qla_sup.c +4
-0+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) +{
[ ... ]
drivers/scsi/qla2xxx/qla_sup.c qla29xx_read_optrom_data(struct scsi_qla_host *vha, uint16_t reg_code, · line 622
Quoted 13 lines
drivers/scsi/qla2xxx/qla_sup.c +13
-0+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);
[Severity: High]
And similarly in qla29xx_mpi_optrom_data(), OP_DUMP maps to a device write by setting BIT_0 and copying the host buffer to the DMA buffer before calling qla29xx_load_dump_mpi().
Should this be OP_LOAD instead?
Quoted 5 lines
drivers/scsi/qla2xxx/qla_sup.c +5
-0+if (rval) { +ql_log (ql_log_fatal, vha,0x0098 , +"Failed dump mpi firmware.\n" ); + goto free_buf; + }
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
Nilesh Javali
maintainerPATCH v6 9/56 scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx
In reply to Nilesh JavaliFrom: Anil Gurumurthy <[email protected]>
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.
--- drivers/scsi/qla2xxx/qla_fw29.h | 686 ++++++++++++++++++++++++++++++++ 1 file changed, 686 insertions(+) create mode 100644 drivers/scsi/qla2xxx/qla_fw29.h
drivers/scsi/qla2xxx/qla_fw29.h new file +686 -0
@@ -0,0 +1,686 @@ +/* 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; +}; +#endif
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 09/56] scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [High] Endianness portability violation using bitfields on __le16 DMA structures. - [Medium] Missing…
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Endianness portability violation using bitfields on __le16 DMA structures.
- [Medium] Missing padding array leaves struct vp_rpt_id_entry_24xx_ext at 64 bytes instead of the required 128 bytes.
- [Medium] Possible truncation of 9-bit VP indices in vp_config_entry_24xx_ext and vp_ctrl_entry_24xx_ext.
- [Low] Stale comment in struct sts_entry_24xx_ext provides incorrect array offsets for DIF error handling. --
--- Patch [9]: [PATCH v6 09/56] scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx --- commit f045d9bbc4916b8badfe0c3d725fe53a57f4cac2
Author: Anil Gurumurthy <[email protected]>
scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx
This commit introduces a new header file containing extended 128-byte IOCB structure definitions for the QLogic 29xx series adapters. It maps the new firmware interface to C structures for hardware DMA interactions.
Quoted 6 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +0
-0@@ -0,0 +1,686 @@
[ ... ]
Quoted 3 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +3
-0+struct sts_entry_24xx_ext { +uint8_t entry_type;/* Entry type. */ +uint8_t entry_count;/* Entry count. */
[ ... ]
Quoted 4 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +4
-0+uint8_t reserved_2[8 ]; +uint8_t act_dif[8 ]; +uint8_t exp_dif[8 ]; +union {
[ ... ]
drivers/scsi/qla2xxx/qla_fw29.h line 229
Quoted 13 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +13
-0+/* +* 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 +*/ +};
[Severity: Low]
Is this comment still accurate for the new 128-byte structure?
It appears this was copied from the legacy 64-byte struct. In this new layout, the data array starts at offset 68, but the DIF error fields are explicitly defined as act_dif[8] and exp_dif[8] at offsets 32 and 40.
Could this documentation mislead developers trying to access DIF error data?
[ ... ]
Quoted 2 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +2
-0+struct els_entry_24xx_ext { +uint8_t entry_type;/* Entry type. */
[ ... ]
drivers/scsi/qla2xxx/qla_fw29.h line 352
Quoted 7 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +7
-0+__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. */
[Severity: High]
Can this cause endianness issues on big-endian architectures?
Since these structures map directly to hardware DMA buffers, compiler-dependent C bitfield packing on __le16 variables could scramble the vp_index and sof_type bits on big-endian hosts.
Would it be safer to use a plain __le16 field and define bitmask macros like CMD_EXT_VP_INDEX_MASK, similar to what was done for cmd_type_crc_2_ext?
[ ... ]
Quoted 2 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +2
-0+struct els_sts_entry_24xx_ext { +uint8_t entry_type;/* Entry type. */
[ ... ]
drivers/scsi/qla2xxx/qla_fw29.h line 403
Quoted 7 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +7
-0+__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. */
[Severity: High]
Are these __le16 bitfields also susceptible to endianness packing issues across different architectures?
[ ... ]
Quoted 3 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +3
-0+struct abts_entry_24xx_ext { +uint8_t entry_type; +uint8_t entry_count;
[ ... ]
drivers/scsi/qla2xxx/qla_fw29.h line 522
Quoted 6 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +6
-0+__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;
[Severity: High]
Do these bitfields have the same endianness concerns as the others?
[ ... ]
Quoted 2 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +2
-0+struct vp_ctrl_entry_24xx_ext { +uint8_t entry_type;/* Entry type. */
[ ... ]
drivers/scsi/qla2xxx/qla_fw29.h line 589
Quoted 7 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +7
-0+__le16 command; + +__le16 vp_count; + +uint8_t vp_idx_map[16 ]; +__le16 flags; +__le16 id;
[Severity: Medium]
Are these 8-bit map entries sufficient for a 9-bit virtual port index?
The rest of the 29xx extended structures expand the virtual port index to 9 bits to support up to 512 virtual ports. Will mapping these indices to uint8_t fields silently truncate values above 255?
[ ... ]
Quoted 2 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +2
-0+struct vp_config_entry_24xx_ext { +uint8_t entry_type;/* Entry type. */
[ ... ]
drivers/scsi/qla2xxx/qla_fw29.h line 617
Quoted 8 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +8
-0+uint8_t command; + +uint8_t vp_count; + +uint8_t vp_index1; +uint8_t vp_index2; + +uint8_t options_idx1;
[Severity: Medium]
Could this truncate the 9-bit virtual port indices?
If the 29xx hardware supports indices up to 511, storing them in these uint8_t variables will drop the upper bit.
[ ... ]
drivers/scsi/qla2xxx/qla_fw29.h line 643
Quoted 10 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +10
-0+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 */
[Severity: High]
Do these bitfields have the same endianness concerns as the ones in els_entry_24xx_ext?
[ ... ]
drivers/scsi/qla2xxx/qla_fw29.h line 686
Quoted 9 lines
drivers/scsi/qla2xxx/qla_fw29.h new file +9
-0+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; +}; +#endif
[Severity: Medium]
Does this structure meet the 128-byte size requirement?
Unlike the other extended structures which include a reserved padding array at the end to ensure the struct size is exactly 128 bytes, this one appears to omit the padding and end at 64 bytes.
If any queue logic relies on the size of this struct, could it miscalculate strides or corrupt memory queues?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=9
Nilesh Javali
maintainerPATCH v6 10/56 scsi: qla2xxx: Add extended status continuation and marker IOCBs
In reply to Nilesh JavaliFrom: Anil Gurumurthy <[email protected]>
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.
--- drivers/scsi/qla2xxx/qla_def.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/scsi/qla2xxx/qla_def.h +10 -0
@@ -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. */
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 10/56] scsi: qla2xxx: Add extended status continuation and marker IOCBs
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] The commit message claims to add `sts_cont_entry_ext_t` and `mrk_entry_ext_t`, but the patch…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The commit message claims to add sts_cont_entry_ext_t and mrk_entry_ext_t, but the patch only adds struct sts_cont_entry_ext and entirely omits the marker structure. --
--- Patch [10]: [PATCH v6 10/56] scsi: qla2xxx: Add extended status continuation and marker IOCBs --- commit e3f382fa4d5aa55c429c51349c5574fdb65d9249
Author: Anil Gurumurthy <[email protected]>
scsi: qla2xxx: Add extended status continuation and marker IOCBs
This commit adds the 128-byte extended status continuation structure and includes the new qla_fw29.h header for 29xx firmware support.
Quoted 4 lines
scsi: qla2xxx: Add extended status continuation and marker IOCBs
Add the 128-byte
sts_cont_entry_ext_tandmrk_entry_ext_tstructures required by 29xx firmware.
[ ... ]
Quoted 3 lines
drivers/scsi/qla2xxx/qla_def.h +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_def.h typedef struct { · line 2371
Quoted 12 lines
drivers/scsi/qla2xxx/qla_def.h +8
-0@@ -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 */ +};
[Severity: Medium]
The commit message states that both sts_cont_entry_ext_t and mrk_entry_ext_t are being added, but only struct sts_cont_entry_ext is present in the code.
Is the mrk_entry_ext_t structure accidentally missing from this patch, or does the commit message need to be updated?
Additionally, should sts_cont_entry_ext use a typedef to match the sts_cont_entry_ext_t description in the commit message?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=10
Nilesh Javali
maintainerPATCH v6 11/56 scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx
In reply to Nilesh JavaliFrom: Anil Gurumurthy <[email protected]>
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.
--- drivers/scsi/qla2xxx/qla_dbg.c | 31 +- drivers/scsi/qla2xxx/qla_def.h | 29 +- 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 | 53 +- drivers/scsi/qla2xxx/qla_inline.h | 174 ++++- drivers/scsi/qla2xxx/qla_iocb.c | 1116 ++++++++++++++++++++++++----- drivers/scsi/qla2xxx/qla_isr.c | 55 +- drivers/scsi/qla2xxx/qla_mid.c | 65 +- drivers/scsi/qla2xxx/qla_nvme.c | 156 ++-- drivers/scsi/qla2xxx/qla_os.c | 39 +- drivers/scsi/qla2xxx/qla_target.c | 34 +- 13 files changed, 1497 insertions(+), 354 deletions(-)
drivers/scsi/qla2xxx/qla_dbg.c +17 -14
@@ -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;
drivers/scsi/qla2xxx/qla_def.h +27 -2
@@ -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 {
@@ -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;
@@ -4488,7 +4512,8 @@ struct qla_hw_data {#define IS_ATIO_MSIX_CAPABLE (ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \ IS_QLA28XX(ha))#define IS_TGT_MODE_CAPABLE (ha) (ha->tgt.atio_q_length) -#define IS_SHADOW_REG_CAPABLE (ha) (IS_QLA27XX(ha) || IS_QLA28XX(ha)) +#define IS_SHADOW_REG_CAPABLE (ha) (IS_QLA27XX(ha) || IS_QLA28XX(ha) || \ + IS_QLA29XX(ha))#define IS_DPORT_CAPABLE (ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \ IS_QLA28XX(ha))#define IS_FAWWN_CAPABLE (ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
drivers/scsi/qla2xxx/qla_edif.c +17 -1
@@ -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 ; }
drivers/scsi/qla2xxx/qla_fw29.h +77 -0
87 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_gbl.h +3 -1
@@ -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 );
drivers/scsi/qla2xxx/qla_init.c +42 -11
100 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_inline.h +169 -5
192 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_iocb.c +935 -181
1,394 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_isr.c +13 -42
117 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_mid.c +41 -24
143 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_nvme.c +111 -45
218 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_os.c +29 -10
@@ -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,8 +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 ) *sizeof (request_t), - req->ring, req->dma); + (req->length +1 ) * req_entry_size, + req->ring, req->dma);if (req)kfree (req->outstanding_cmds);
@@ -520,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,
@@ -527,8 +531,8 @@ 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 ) * rsp_entry_size, + 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,
@@ -4249,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,
@@ -4444,13 +4451,17 @@ 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 ) * req_entry_size, &(*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,17 @@ 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 ) * rsp_entry_size, &(*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,
@@ -4617,16 +4632,18 @@ 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 ) * -sizeof (response_t), (*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 ; fail_rsp_ring:kfree (*rsp); *rsp =NULL ; fail_rsp: -dma_free_coherent (&ha->pdev->dev, ((*req)->length +1 ) * -sizeof (request_t), (*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 ; fail_req_ring:
@@ -8324,6 +8341,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 );
@@ -8351,6 +8369,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 );
drivers/scsi/qla2xxx/qla_target.c +16 -18
@@ -1738,8 +1738,8 @@ static int qlt_build_abts_resp_iocb(struct qla_tgt_mgmt_cmd *mcmd)return -EAGAIN ; } - resp = (struct abts_resp_to_24xx *)qpair->req->ring_ptr; -memset (resp,0 ,sizeof (*resp)); + resp = (struct abts_resp_to_24xx *)qla_req_ring_slot (ha, qpair->req); +memset (resp,0 ,qla_req_entry_size (ha)); h =qlt_make_handle (qpair);if (unlikely (h ==QLA_TGT_NULL_HANDLE )) {
@@ -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 */
@@ -2549,9 +2545,9 @@ static int qlt_24xx_build_ctio_pkt(struct qla_qpair *qpair,uint16_t temp;struct qla_tgt_cmd *cmd = prm->cmd; - pkt = (struct ctio7_to_24xx *)qpair->req->ring_ptr; + pkt = (struct ctio7_to_24xx *)qla_req_ring_slot (qpair->hw, qpair->req); prm->pkt = pkt; -memset (pkt,0 ,sizeof (*pkt)); +memset (pkt,0 ,qla_req_entry_size (qpair->hw)); pkt->entry_type =CTIO_TYPE7 ; pkt->entry_count = (uint8_t )prm->req_cnt;
@@ -2600,11 +2596,12 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm) {int cnt;struct dsd64 *cur_dsd; +struct qla_hw_data *ha = prm->cmd->qpair->hw;/* Build continuation packets */ while (prm->seg_cnt >0 ) {cont_a64_entry_t *cont_pkt64 = - (cont_a64_entry_t *)qlt_get_req_pkt ( + (cont_a64_entry_t *)qlt_get_req_pkt (ha, prm->cmd->qpair->req);/*
@@ -2614,7 +2611,7 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm)* that. */ -memset (cont_pkt64,0 ,sizeof (*cont_pkt64)); +memset (cont_pkt64,0 ,qla_req_entry_size (ha)); cont_pkt64->entry_count =1 ; cont_pkt64->sys_define =0 ;
@@ -3012,9 +3009,9 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) ha = vha->hw; - pkt = (struct ctio_crc2_to_fw *)qpair->req->ring_ptr; + pkt = (struct ctio_crc2_to_fw *)qla_req_ring_slot (ha, qpair->req); prm->pkt = pkt; -memset (pkt,0 ,sizeof (*pkt)); +memset (pkt,0 ,qla_req_entry_size (ha)); ql_dbg_qp(ql_dbg_tgt, cmd->qpair, 0xe071, "qla_target(%d):%s: se_cmd[%p] CRC2 prot_op[0x%x] cmd prot sg:cnt[%p:%x] lba[%llu]\n",
@@ -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",
@@ -3316,6 +3313,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,* T10Dif: ctio_crc2_to_fw overlay ontop of * ctio7_to_24xx */ +memset (ctio,0 ,qla_req_entry_size (vha->hw));memcpy (ctio, pkt,sizeof (*ctio));/* reset back to CTIO7 */ ctio->entry_count =1 ;
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 11/56] scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
New issues:
- [Critical] qla27xx_copy_multiple_pkt uses rsp_q->ring_ptr++ instead of qla_rsp_ring_advance(), immediately corrupting the 128-byte response ring on 29xx.
- [High] Target mode scatter-gather transfers > 6 segments will fail on 29xx due to hardcoded continuation DSD limits, and target mode unconditionally uses 64-byte ctio7_to_24xx offsets for 128-byte IOCBs.
- [High] Payload extraction paths for PUREX, FPIN, and STATUS_CONT_TYPE response IOCBs fail to use the extended 128-byte struct layouts on 29xx adapters, silently truncating data.
- [High] The completion path (ISR) unconditionally parses 128-byte 29xx status IOCBs using the legacy 64-byte sts_entry_24xx layout, reading critical fields from the wrong offsets.
- [High] qla24xx_tm_iocb builds Task Management IOCBs using the 24xx layout, corrupting the vp_index on 29xx.
Pre-existing issues:
- [High] The 24xx path in qla24xx_dif_start_scsi and qla2xxx_dif_start_scsi_mq fails to initialize the vp_index field of the cmd_type_crc_2 IOCB, leaving it at 0. This breaks NPIV for DIF/PI commands on 24xx adapters. --
--- Patch [11]: [PATCH v6 11/56] scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx --- commit 6d84675eb563d48a8c7790164426bd51a8bdfb65
Author: Anil Gurumurthy <[email protected]>
scsi: qla2xxx: Update IO path to use 128-byte IOCBs for 29xx
This patch updates the IO submission, completion, and queue-management paths to support 128-byte extended IOCBs on 29xx adapters. It introduces helpers for dynamic ring entry size and pointer advancement to support both legacy and extended layouts.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_iocb.c +0
-0
[ ... ]
Quoted 12 lines
drivers/scsi/qla2xxx/qla_iocb.c +2
-2@@ -1829,17 +1901,24 @@ 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 ; -memset (clr_ptr,0 ,REQUEST_ENTRY_SIZE -8 ); +memset (clr_ptr,0 ,qla_req_entry_size (ha) -8 );
drivers/scsi/qla2xxx/qla_iocb.c qla24xx_dif_start_scsi(srb_t *sp) · line 1916
Quoted 10 lines
drivers/scsi/qla2xxx/qla_iocb.c +5
-3/* 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; + }
[Severity: High]
This is a pre-existing issue, but does the 24xx branch fail to initialize the vp_index field here?
Because vp_index is not assigned, it remains at the zeroed default. This breaks NPIV for DIF/PI commands on 24xx adapters, as the switch will receive frames from the base port's WWPN instead of the virtual port's WWPN.
This same pre-existing issue appears in qla2xxx_dif_start_scsi_mq() as well.
Quoted 5 lines
drivers/scsi/qla2xxx/qla_iocb.c +5
-0+/* +* 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. +*/
[ ... ]
drivers/scsi/qla2xxx/qla_iocb.c qla_start_scsi_type6(srb_t *sp)
Quoted 1 line
drivers/scsi/qla2xxx/qla_iocb.c +0
-0@@ -4289,8 +4529,15 @@ qla_start_scsi_type6(srb_t *sp)
[Severity: High]
Are Task Management IOCBs built correctly for 29xx hardware?
When issuing an abort or reset, qla24xx_tm_iocb() fills the 128-byte slot assuming the 64-byte tsk_mgmt_entry layout. It writes port_id to offset 48 and vp_index to offset 51, but on 29xx (tsk_mgmt_entry_ext), vp_index is a 16-bit field at offset 28.
Could this cause TMF commands to be routed to the wrong virtual port and overwrite reserved fields?
Quoted 4 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0
[ ... ]
Quoted 4 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0@@ -287,13 +281,7 @@ int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,break ; }
drivers/scsi/qla2xxx/qla_isr.c int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha, · line 286
Quoted 10 lines
drivers/scsi/qla2xxx/qla_isr.c +1
-7- 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;
[Severity: High]
Does this code truncate the payload extraction on 29xx adapters?
sizeof(new_pkt->data) evaluates to 60 bytes (for sts_cont_entry_t), but a 29xx continuation slot holds 124 bytes of data. It appears the remaining 64 bytes will be skipped and lost here.
The same truncation issue exists in qla27xx_copy_fpin_pkt() and qla2x00_status_cont_entry() where SCSI sense data extraction is also limited to sizeof(pkt->data).
Quoted 1 line
drivers/scsi/qla2xxx/qla_isr.c +0
-0if ((buffer_copy_offset + no_bytes) <= total_bytes) {
[ ... ]
drivers/scsi/qla2xxx/qla_isr.c void qla24xx_process_response_queue(struct scsi_qla_host *vha, · line 3983
Quoted 12 lines
drivers/scsi/qla2xxx/qla_isr.c +1
-7@@ -4003,13 +3980,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);
[Severity: High]
Will the completion path correctly parse 128-byte 29xx status IOCBs?
The main loop processes completions using the legacy 64-byte sts_entry_24xx layout. For example, qla2x00_status_entry() reads scsi_status from offset 22, but on 29xx (sts_entry_24xx_ext), scsi_status is located at offset 54. Could this result in misinterpreting completion status and residual counts?
[Severity: Critical]
Did we miss converting a manual pointer increment in qla27xx_copy_multiple_pkt()?
If rsp_q->ring_ptr++ is used there instead of qla_rsp_ring_advance(), the pointer will advance by 64 bytes instead of 128 bytes on 29xx hardware, permanently desynchronizing the driver's view of the ring from the firmware.
Quoted 7 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0if (pkt->entry_status !=0 ) {if (qla2x00_error_entry (vha, rsp, (sts_entry_t *) pkt))drivers/scsi/qla2xxx/qla_target.c +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_target.c static int qlt_24xx_build_ctio_pkt(struct qla_qpair *qpair, · line 2553
Quoted 12 lines
drivers/scsi/qla2xxx/qla_target.c +2
-2@@ -2549,9 +2545,9 @@ static int qlt_24xx_build_ctio_pkt(struct qla_qpair *qpair,uint16_t temp;struct qla_tgt_cmd *cmd = prm->cmd; - pkt = (struct ctio7_to_24xx *)qpair->req->ring_ptr; + pkt = (struct ctio7_to_24xx *)qla_req_ring_slot (qpair->hw, qpair->req); prm->pkt = pkt; -memset (pkt,0 ,sizeof (*pkt)); +memset (pkt,0 ,qla_req_entry_size (qpair->hw)); pkt->entry_type =CTIO_TYPE7 ; pkt->entry_count = (uint8_t )prm->req_cnt;
[Severity: High]
Are we sure it is safe to cast the 128-byte slot to the legacy 64-byte ctio7_to_24xx struct here?
On 29xx hardware, qla_req_ring_slot() will return a 128-byte slot, but writing to it with the 64-byte struct offsets will misalign critical fields like vp_index.
drivers/scsi/qla2xxx/qla_target.c static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm) · line 2605
Quoted 12 lines
drivers/scsi/qla2xxx/qla_target.c +2
-1@@ -2600,11 +2596,12 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm) {int cnt;struct dsd64 *cur_dsd; +struct qla_hw_data *ha = prm->cmd->qpair->hw;/* Build continuation packets */ while (prm->seg_cnt >0 ) {cont_a64_entry_t *cont_pkt64 = - (cont_a64_entry_t *)qlt_get_req_pkt ( + (cont_a64_entry_t *)qlt_get_req_pkt (ha, prm->cmd->qpair->req);
[Severity: High]
Does this continuation logic correctly handle the 29xx hardware requirements?
Looking at the loop below, only 5 DSDs are populated into the 128-byte extended continuation IOCB here, but 29xx hardware expects 10 DSDs. Will the firmware terminate the transfer early when it encounters the zeroed 6th DSD?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=11
Nilesh Javali
maintainerPATCH v6 12/56 scsi: qla2xxx: Skip image-set-valid attribute for 29xx
In reply to Nilesh JavaliThe 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.
--- drivers/scsi/qla2xxx/qla_bsg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/scsi/qla2xxx/qla_bsg.c +4 -1
@@ -2966,11 +2966,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,
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 13/56 scsi: qla2xxx: Skip unsupported sysfs attributes for 29xx
In reply to Nilesh JavaliNot 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.
--- drivers/scsi/qla2xxx/qla_attr.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
drivers/scsi/qla2xxx/qla_attr.c +21 -0
@@ -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" );
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 14/56 scsi: qla2xxx: Enable get_fw_version mailbox for 29xx
In reply to Nilesh JavaliThe 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.
--- drivers/scsi/qla2xxx/qla_attr.c | 4 ++-- drivers/scsi/qla2xxx/qla_mbx.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-)
drivers/scsi/qla2xxx/qla_attr.c +2 -2
@@ -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",
@@ -2386,7 +2386,7 @@ qla2x00_fw_attr_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, "%llx\n",
drivers/scsi/qla2xxx/qla_mbx.c +4 -4
@@ -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 ;
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 14/56] scsi: qla2xxx: Enable get_fw_version mailbox for 29xx
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] The patch attempts to enable EDIF support for QLA29XX adapters, but the implementation is…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The patch attempts to enable EDIF support for QLA29XX adapters, but the implementation is structurally unreachable dead code, and the underlying EDIF I/O path explicitly rejects QLA29XX.
- [Medium] The sysfs attributes for mpi_version and pep_version are not exported for QLA29XX adapters due to missing IS_QLA29XX(ha) checks in their respective show functions. --
--- Patch [14]: [PATCH v6 14/56] scsi: qla2xxx: Enable get_fw_version mailbox for 29xx --- commit 93f36311743cc5868596ac6cab18df55689b0cd9
Author: Nilesh Javali <[email protected]>
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.
drivers/scsi/qla2xxx/qla_attr.c qla2x00_serdes_version_show(struct device *dev, struct device_attribute *attr, · line 1530
Quoted 11 lines
drivers/scsi/qla2xxx/qla_attr.c +1
-1@@ -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]
Should the sysfs attributes for mpi_version and pep_version also be updated to support 29xx?
The get_fw_version mailbox command now successfully retrieves ha->mpi_version and ha->pep_version for 29xx adapters, but qla2x00_mpi_version_show() and qla2x00_pep_version_show() in qla_attr.c still restrict visibility:
drivers/scsi/qla2xxx/qla_attr.c:qla2x00_mpi_version_show() {
...
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha) &&
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return scnprintf(buf, PAGE_SIZE, "\n");
...
}Will this cause userspace tools to incorrectly receive a blank line when reading these attributes on 29xx hardware?
[ ... ]
drivers/scsi/qla2xxx/qla_mbx.c qla2x00_get_fw_version(scsi_qla_host_t *vha) · line 1218
Quoted 13 lines
drivers/scsi/qla2xxx/qla_mbx.c +1
-1@@ -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,
[Severity: High]
Is this EDIF enablement reachable for 29xx adapters, and if so, is it safe?
This condition requires ha->flags.edif_hw to be set, but looking at qla2x00_execute_fw(), edif_hw is only initialized for QLA28XX:
drivers/scsi/qla2xxx/qla_mbx.c:qla2x00_execute_fw() {
...
if (IS_QLA28XX(ha) && (mcp->mb[5] & EDIF_HW_SUPPORT)) {
ha->flags.edif_hw = 1;
...
}Additionally, if EDIF were to be enabled here, would it cause I/O failures? The underlying EDIF I/O path appears to explicitly reject 29xx hardware:
drivers/scsi/qla2xxx/qla_edif.c:qla28xx_start_scsi_edif() {
...
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;
}
...
}Does the 29xx platform intentionally lack EDIF support, making this conditional update unnecessary?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=14
Nilesh Javali
maintainerPATCH v6 15/56 scsi: qla2xxx: Extend execute_fw mailbox to include 29xx
In reply to Nilesh JavaliAdd 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.
--- drivers/scsi/qla2xxx/qla_attr.c | 12 ++++++++++-- drivers/scsi/qla2xxx/qla_def.h | 5 +++-- drivers/scsi/qla2xxx/qla_gs.c | 16 +++++++++++++--- drivers/scsi/qla2xxx/qla_isr.c | 2 +- drivers/scsi/qla2xxx/qla_mbx.c | 23 +++++++++++++---------- 5 files changed, 40 insertions(+), 18 deletions(-)
drivers/scsi/qla2xxx/qla_attr.c +10 -2
@@ -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 )
drivers/scsi/qla2xxx/qla_def.h +3 -2
@@ -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 0x13uint16_t link_data_rate;/* F/W operating speed */ uint16_t set_data_rate;/* Set by user */
@@ -5582,9 +5583,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))
drivers/scsi/qla2xxx/qla_gs.c +13 -3
@@ -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 ; }
@@ -2620,6 +2628,8 @@ qla2x00_port_speed_capability(uint16_t speed)return PORT_SPEED_32GB ;case BIT_7 :return PORT_SPEED_64GB ; +case BIT_6 : +return PORT_SPEED_128GB ;default :return PORT_SPEED_UNKNOWN ; }
drivers/scsi/qla2xxx/qla_isr.c +1 -1
@@ -652,7 +652,7 @@ const char * qla2x00_get_link_speed_str(struct qla_hw_data *ha, uint16_t speed) {static const char *const link_speeds[] = { -"1" ,"2" ,"?" ,"4" ,"8" ,"16" ,"32" ,"64" ,"10" +"1" ,"2" ,"?" ,"4" ,"8" ,"16" ,"32" ,"64" ,"128" ,"10" };#define QLA_LAST_SPEED (ARRAY_SIZE(link_speeds) - 1)
drivers/scsi/qla2xxx/qla_mbx.c +13 -10
@@ -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__);
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 15/56] scsi: qla2xxx: Extend execute_fw mailbox to include 29xx
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] The `port_speed` sysfs setter fails unconditionally for QLA29XX adapters and lacks support for…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The port_speed sysfs setter fails unconditionally for QLA29XX adapters and lacks support for configuring 64Gps and 128Gps speeds. --
--- Patch [15]: [PATCH v6 15/56] scsi: qla2xxx: Extend execute_fw mailbox to include 29xx --- commit f710a272666aaab612a05e252367e3da5901939a
Author: Nilesh Javali <[email protected]>
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.
Quoted 3 lines
drivers/scsi/qla2xxx/qla_attr.c +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_attr.c qla2x00_max_supported_speed_show(struct device *dev, · line 1808
Quoted 7 lines
drivers/scsi/qla2xxx/qla_attr.c +1
-1@@ -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" );
[Severity: Medium]
Since IS_QLA29XX was added here, does qla2x00_port_speed_store() also need to be updated?
drivers/scsi/qla2xxx/qla_attr.c:qla2x00_port_speed_store() {
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) {
ql_log(ql_log_warn, vha, 0x70d8,
"Speed setting not supported \n");
return -EINVAL;
}
...
}Otherwise, the setter will unconditionally return -EINVAL for QLA29XX adapters.
[ ... ]
drivers/scsi/qla2xxx/qla_attr.c static const struct { · line 1894
Quoted 7 lines
drivers/scsi/qla2xxx/qla_attr.c +1
-0@@ -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" }, };
[Severity: Medium]
Does qla2x00_port_speed_store() need to support 64 and 128 Gbps speeds? Currently, its switch statement lacks cases for 64Gps and 128Gps, causing them to fall back to Autoneg:
drivers/scsi/qla2xxx/qla_attr.c:qla2x00_port_speed_store() {
...
default:
ql_log(ql_log_warn, vha, 0x1199,
"Unrecognized speed setting:%lx. Setting Autoneg\n",
speed);
ha->set_data_rate = PORT_SPEED_AUTO;
...
}It appears a similar switch in qla2x00_set_data_rate() in qla_mbx.c is also missing these cases.
Quoted 3 lines
drivers/scsi/qla2xxx/qla_mbx.c +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_mbx.c qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) · line 732
Quoted 7 lines
drivers/scsi/qla2xxx/qla_mbx.c +1
-1@@ -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 ;
[Severity: Medium]
Should IS_QLA29XX(ha) be added to the mailbox command setup in qla2x00_set_data_rate() as well?
drivers/scsi/qla2xxx/qla_mbx.c:qla2x00_set_data_rate() {
...
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
mcp->in_mb |= MBX_4|MBX_3;
...
}Without it, the function might fail to correctly populate the in_mb mask for the new adapters.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=15
Nilesh Javali
maintainerPATCH v6 16/56 scsi: qla2xxx: Enable get_adapter_id mailbox for 29xx
In reply to Nilesh JavaliAdd 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.
--- drivers/scsi/qla2xxx/qla_mbx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_mbx.c +2 -2
@@ -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,
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 16/56] scsi: qla2xxx: Enable get_adapter_id mailbox for 29xx
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] Userspace access to Buffer-to-Buffer Credit (BBCR) data on QLA29XX adapters is blocked by a…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Userspace access to Buffer-to-Buffer Credit (BBCR) data on QLA29XX adapters is blocked by a missing whitelist check in qla27xx_get_bbcr_data(). --
--- Patch [16]: [PATCH v6 16/56] scsi: qla2xxx: Enable get_adapter_id mailbox for 29xx --- commit 9877d8e47534a68c96e077863320b75953d374f1
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Enable get_adapter_id mailbox for 29xx
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.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_mbx.c +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_mbx.c qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa, · line 1831
Quoted 7 lines
drivers/scsi/qla2xxx/qla_mbx.c +1
-1@@ -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 ];
[Severity: Medium]
Will userspace be able to access the BBCR data read here for 29xx adapters?
Looking at qla27xx_get_bbcr_data() in drivers/scsi/qla2xxx/qla_bsg.c, the BSG ioctl handler explicitly rejects adapters that are not 27xx or 28xx:
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return -EPERM;
Should IS_QLA29XX(ha) be added to this check as well, so that the newly read BBCR data isn't blocked from being retrieved by userspace querying QL_VND_GET_BBCR_DATA?
Quoted 2 lines
drivers/scsi/qla2xxx/qla_mbx.c +0
-0if (mcp->mb[7 ] &SCM_EDC_ACC_RECEIVED ) { ql_log(ql_log_info, vha, 0x11a4,
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=16
Nilesh Javali
maintainerPATCH v6 17/56 scsi: qla2xxx: Enable init_firmware mailbox for 29xx
In reply to Nilesh JavaliThe 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.
--- drivers/scsi/qla2xxx/qla_mbx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_mbx.c +2 -2
@@ -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" );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 17/56] scsi: qla2xxx: Enable init_firmware mailbox for 29xx
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] Missing IS_QLA29XX() generation checks in firmware state and data rate mailbox commands, leading…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Missing IS_QLA29XX() generation checks in firmware state and data rate mailbox commands, leading to incomplete hardware support. --
--- Patch [17]: [PATCH v6 17/56] scsi: qla2xxx: Enable init_firmware mailbox for 29xx --- commit 7e60ed82a282887839ef4256a5c2633b284fa01f
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Enable init_firmware mailbox for 29xx
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.
Quoted 13 lines
drivers/scsi/qla2xxx/qla_mbx.c +1
-1@@ -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;
[ ... ]
drivers/scsi/qla2xxx/qla_mbx.c qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size) · line 1995
Quoted 6 lines
drivers/scsi/qla2xxx/qla_mbx.c +1
-1@@ -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)) {
[Severity: Medium]
Since IS_QLA29XX(ha) is added here for SFP validation and mailbox commands, should it also be added to other mailbox commands like qla2x00_get_firmware_state()?
For example, without it, MPI state reporting fails to request mcp->mb[12] on 29xx adapters:
drivers/scsi/qla2xxx/qla_mbx.c:qla2x00_get_firmware_state() {
...
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
mcp->mb[12] = 0;
mcp->out_mb |= MBX_12;
mcp->in_mb |= MBX_12;
}
...
}This also causes sysfs MPI state reads to fail for 29xx adapters:
drivers/scsi/qla2xxx/qla_attr.c:qla2x00_mpi_fw_state_show() {
...
if (!(IS_QLA27XX(ha) || IS_QLA28XX(ha)))
return scnprintf(buf, PAGE_SIZE,
"MPI state reporting is not supported for this HBA.\n");
...
}Does IS_QLA29XX(ha) also need to be included in data rate commands to report FEC link status?
drivers/scsi/qla2xxx/qla_mbx.c:qla2x00_set_data_rate() {
...
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
mcp->in_mb |= MBX_4|MBX_3;
...
}drivers/scsi/qla2xxx/qla_mbx.c:qla2x00_get_data_rate() {
...
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
mcp->in_mb |= MBX_4|MBX_3;
...
}Quoted 3 lines
drivers/scsi/qla2xxx/qla_mbx.c +0
-0if (mcp->mb[2 ] ==6 || mcp->mb[3 ] ==2 )ql_dbg (ql_dbg_mbx, vha,0x119d ,"Invalid SFP/Validation Failed\n" );
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=17
Nilesh Javali
maintainerPATCH v6 18/56 scsi: qla2xxx: Enable get_firmware_state for 29xx
In reply to Nilesh JavaliEnable 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.
--- drivers/scsi/qla2xxx/qla_attr.c | 2 +- drivers/scsi/qla2xxx/qla_mbx.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-)
drivers/scsi/qla2xxx/qla_attr.c +1 -1
@@ -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" );
drivers/scsi/qla2xxx/qla_mbx.c +3 -3
@@ -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" );
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 19/56 scsi: qla2xxx: Enable serdes, resource count and FCE trace for 29xx
In reply to Nilesh JavaliThe 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().
--- 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(-)
drivers/scsi/qla2xxx/qla_dfs.c +2 -2
@@ -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)
drivers/scsi/qla2xxx/qla_init.c +1 -1
@@ -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) {
drivers/scsi/qla2xxx/qla_mbx.c +7 -4
@@ -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)))
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 19/56] scsi: qla2xxx: Enable serdes, resource count and FCE trace for 29xx
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] The debugfs write handler qla2x00_dfs_fce_write() passes a NULL pointer to kstrtoul(), guaranteeing a kernel crash upon successful parsing, and erroneously evaluates its error code as the parsed value.
- [High] Dynamically enabling FCE trace via debugfs causes a 64KB out-of-bounds write during a firmware dump because the fw_dump buffer is not properly resized.
- [High] Concurrent execution of a firmware dump and disabling the FCE trace via debugfs leads to a Use-After-Free of the FCE DMA buffer.
--
--- Patch [19]: [PATCH v6 19/56] scsi: qla2xxx: Enable serdes, resource count and FCE trace for 29xx --- commit ce99a18d7438f0c23e7c18bd3dad0bfb7220456a
Author: Nilesh Javali <[email protected]>
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.
drivers/scsi/qla2xxx/qla_dfs.c qla2x00_dfs_fce_write(struct file *file, const char __user *buffer, · line 503
Quoted 13 lines
drivers/scsi/qla2xxx/qla_dfs.c +1
-1@@ -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 ;
[Severity: High]
This is a pre-existing issue, but since this patch exposes the FCE debugfs node to 29xx adapters, does writing to this node cause a guaranteed kernel panic?
Looking at qla2x00_dfs_fce_write() just below this check:
enable = kstrtoul(buf, 0, 0);
Does passing 0 (NULL) as the third argument to kstrtoul() cause a NULL pointer dereference when the function attempts to write the successfully parsed value?
Additionally, since it assigns the return value (an error code) to enable rather than the parsed number, does writing an invalid string return a non-zero negative error code that evaluates to true, incorrectly enabling the trace without crashing?
[Severity: High]
This is another pre-existing issue exposed by enabling FCE trace via debugfs, but does dynamically enabling this feature cause an out-of-bounds write during a firmware dump?
When FCE is enabled dynamically, qla2x00_dfs_fce_write() calls qla2x00_alloc_fw_dump() to resize the dump buffer. However, qla2x00_alloc_fw_dump() returns early if the buffer is already allocated:
drivers/scsi/qla2xxx/qla_init.c:qla2x00_alloc_fw_dump() {
if (ha->fw_dump) {
ql_dbg(ql_dbg_init, vha, 0x00bd,
"Firmware dump already allocated.\n");
return;
}
...
}During a firmware dump, qla25xx_copy_fce() appends the 64KB FCE buffer to the fw_dump buffer:
drivers/scsi/qla2xxx/qla_dbg.c:qla25xx_copy_fce() {
...
memcpy(iter_reg, ha->fce, ntohl(fcec->size));
...
}Does this blindly write 64KB past the end of the unresized firmware dump buffer?
[Severity: High]
This is also a pre-existing issue, but does disabling the FCE trace via this debugfs node race with firmware dumps, leading to a Use-After-Free?
When disabling FCE, qla2x00_dfs_fce_write() calls qla2x00_free_fce_trace() which frees ha->fce using dma_free_coherent() while holding fce_mutex.
Concurrently, if a firmware dump triggers (e.g., via a system error), the dump path accesses this same memory:
drivers/scsi/qla2xxx/qla_dbg.c:qla25xx_copy_fce() {
...
memcpy(iter_reg, ha->fce, ntohl(fcec->size));
...
}Since the dump path executes under hardware_lock but without holding fce_mutex, and the free path does not acquire hardware_lock, can the dump path observe a non-NULL pointer and access the memory after it has been freed?
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=19
Nilesh Javali
maintainerPATCH v6 20/56 scsi: qla2xxx: Enable set_els_cmds and echo_test for 29xx
In reply to Nilesh JavaliAdd 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.
--- drivers/scsi/qla2xxx/qla_mbx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/scsi/qla2xxx/qla_mbx.c +4 -3
@@ -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 ;
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 21/56 scsi: qla2xxx: Add support for QLA29XX in data rate functions
In reply to Nilesh JavaliEnhance 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.
--- drivers/scsi/qla2xxx/qla_attr.c | 2 +- drivers/scsi/qla2xxx/qla_mbx.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-)
drivers/scsi/qla2xxx/qla_attr.c +1 -1
@@ -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 ;
drivers/scsi/qla2xxx/qla_mbx.c +3 -3
@@ -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" );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 21/56] scsi: qla2xxx: Add support for QLA29XX in data rate functions
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The check mcp->mb[1] != 0x7 prevents updating ha->link_data_rate for 64GBps links. --
--- Patch [21]: [PATCH v6 21/56] scsi: qla2xxx: Add support for QLA29XX in data rate functions --- commit a940865e619482397b688263aefb07728776bca0
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Add support for QLA29XX in data rate functions
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.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_mbx.c +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_mbx.c qla2x00_get_data_rate(scsi_qla_host_t *vha) · line 5734
Quoted 3 lines
drivers/scsi/qla2xxx/qla_mbx.c +0
-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 ];
[Severity: High]
This is a pre-existing issue, but does this check prevent updating the link speed for 64GBps links?
Since PORT_SPEED_64GB is defined as 0x07, querying a 64GBps link will return 0x07 in mcp->mb[1]. Filtering this out appears to leave ha->link_data_rate stale (e.g., PORT_SPEED_UNKNOWN).
Could this break sysfs speed reporting and prevent proper hardware configuration, such as setting the correct iIDMA speed in qla2x00_iidma_fcport()?
There appears to be another instance of this check further down in qla2x00_get_data_rate(), as well as a similar check in qla2x00_set_data_rate() that prevents logging the successful configuration of a 64GBps speed.
Quoted 5 lines
drivers/scsi/qla2xxx/qla_mbx.c +1
-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" );
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=21
Nilesh Javali
maintainerPATCH v6 22/56 scsi: qla2xxx: Enable qla2x00_shutdown for 29xx
In reply to Nilesh JavaliEnable qla2x00_shutdown for 29xx adapter by adding IS_QLA29XX check to the shutdown path that performs firmware abort cleanup.
--- drivers/scsi/qla2xxx/qla_os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/qla2xxx/qla_os.c +1 -1
@@ -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 {
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 22/56] scsi: qla2xxx: Enable qla2x00_shutdown for 29xx
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Unsafe lock drop inside list_for_each_entry_safe over ha->vp_list causes Use-After-Free during list traversal.
- [High] Unprotected list traversal over vp_fcports without holding sess_lock allows concurrent modifications to corrupt the traversal. --
--- Patch [22]: [PATCH v6 22/56] scsi: qla2xxx: Enable qla2x00_shutdown for 29xx --- commit 432bc00837ab9eb63a8687ca9bc265acf0d5bb67
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Enable qla2x00_shutdown for 29xx
Enable qla2x00_shutdown for 29xx adapter by adding IS_QLA29XX check to the shutdown path that performs firmware abort cleanup.
drivers/scsi/qla2xxx/qla_os.c qla2x00_shutdown(struct pci_dev *pdev) · line 3845
Quoted 12 lines
drivers/scsi/qla2xxx/qla_os.c +1
-1@@ -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);
[Severity: High]
This isn't a bug introduced by this patch, but since you are enabling qla2x00_abort_isp_cleanup() for 29xx adapters, could this lead to a use-after-free during list traversal?
Looking at qla2x00_abort_isp_cleanup() in drivers/scsi/qla2xxx/qla_init.c:
spin_lock_irqsave(&ha->vport_slock, flags);
list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
atomic_inc(&vp->vref_count);
spin_unlock_irqrestore(&ha->vport_slock, flags);Is it safe to drop vport_slock inside the loop?
Since list_for_each_entry_safe() caches the next entry (tvp) prior to dropping the lock, a concurrent thread (like qla24xx_vport_delete() via sysfs) could remove and free tvp while the lock is dropped. When the lock is reacquired, the loop would attempt to advance using the freed tvp.
[Severity: High]
This is a pre-existing issue, but does this function also lack necessary locking when traversing vp_fcports?
Further down in qla2x00_abort_isp_cleanup():
list_for_each_entry(fcport, &vha->vp_fcports, list) {
fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
fcport->scan_state = 0;
}And similarly for vp->vp_fcports:
list_for_each_entry(fcport, &vp->vp_fcports, list) fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
Can these iterations be corrupted by concurrent modifications?
This traversal doesn't appear to hold vha->hw->tgt.sess_lock. If concurrent tasks (such as workqueues or softirqs executing qlt_create_sess() or qla24xx_create_new_sess()) add to vp_fcports via list_add_tail(), or sysfs tasks executing qla2x00_free_fcport() remove from it via list_del(), could it corrupt the traversal state and cause a use-after-free?
Quoted 3 lines
drivers/scsi/qla2xxx/qla_os.c +0
-0}else {drivers/scsi/qla2xxx/qla_os.c +0
-0/* Stop currently executing firmware. */ qla2x00_try_to_stop_firmware (vha);
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=22
Nilesh Javali
maintainerPATCH v6 23/56 scsi: qla2xxx: Use ring-slot helpers in __qla2x00_alloc_iocbs
In reply to Nilesh Javali__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.
--- drivers/scsi/qla2xxx/qla_iocb.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-)
drivers/scsi/qla2xxx/qla_iocb.c +3 -9
@@ -2466,10 +2466,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 ;
@@ -2530,13 +2529,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);
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 24/56 scsi: qla2xxx: Add support for QLA29XX in memory allocation
In reply to Nilesh JavaliEnhance 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.
--- drivers/scsi/qla2xxx/qla_os.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/scsi/qla2xxx/qla_os.c +6 -4
@@ -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 ; }
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 24/56] scsi: qla2xxx: Add support for QLA29XX in memory allocation
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Missing IS_QLA29XX support in the EDIF_CAP macro causes vp_map allocation failure for QLA29XX when EDIF is enabled, leading to a BUG_ON kernel panic.
Pre-existing issues:
- [High] The IO error paths for qla82xx_start_scsi and qla_start_scsi_type6 erroneously free a DMA pool allocation into a slab-backed mempool, causing SLUB corruption and kernel panics. --
--- Patch [24]: [PATCH v6 24/56] scsi: qla2xxx: Add support for QLA29XX in memory allocation --- commit 1fa851dd2c23362f8090c4cdabea1624fe07304b
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Add support for QLA29XX in memory allocation
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.
Quoted 5 lines
drivers/scsi/qla2xxx/qla_os.c +0
-0
drivers/scsi/qla2xxx/qla_os.c qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, · line 4292
Quoted 9 lines
drivers/scsi/qla2xxx/qla_os.c +2
-1@@ -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",
[Severity: High]
This is a pre-existing issue, but do the IO error paths for qla82xx_start_scsi and qla_start_scsi_type6 incorrectly free a DMA pool allocation into a slab-backed mempool?
The crc_ctx object is allocated from dl_dma_pool via dma_pool_zalloc(), e.g. in qla24xx_build_scsi_crc_2_iocbs(), but the error paths in qla82xx_start_scsi() and qla_start_scsi_type6() do this:
drivers/scsi/qla2xxx/qla_iocb.c:qla82xx_start_scsi() {
...
if (sp->u.scmd.crc_ctx) {
mempool_free(sp->u.scmd.crc_ctx, ha->ctx_mempool);
sp->u.scmd.crc_ctx = NULL;
}
}Since ctx_mempool is created here as a slab pool, freeing DMA-coherent memory back into it causes SLUB corruption or kernel panics when queueing fails under load.
drivers/scsi/qla2xxx/qla_os.c qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, · line 4324
Quoted 7 lines
drivers/scsi/qla2xxx/qla_os.c +2
-1@@ -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)) {
[Severity: High]
By adding QLA29XX to the ql2xsecenable condition here, we enable EDIF allocations for the new adapters. However, does this miss updating the EDIF_CAP macro?
The EDIF_CAP macro in drivers/scsi/qla2xxx/qla_edif.h remains hardcoded to IS_QLA28XX:
drivers/scsi/qla2xxx/qla_edif.h:
#define EDIF_CAP(_ha) (ql2xsecenable && IS_QLA28XX(_ha))
Earlier in qla2x00_mem_alloc(), vp_map is conditionally allocated using this macro:
drivers/scsi/qla2xxx/qla_os.c:qla2x00_mem_alloc() {
if (QLA_TGT_MODE_ENABLED() || EDIF_CAP(ha)) {
ha->vp_map = kzalloc_objs(struct qla_vp_map, MAX_MULTI_ID_FABRIC);
}
}If QLA29XX adapters operate in initiator mode with EDIF enabled, vp_map will be NULL. When EDIF receives ELS/Auth packets, it routes through target-mode infrastructure and calls qla_find_host_by_vp_idx(), which will trigger a BUG_ON(ha->vp_map == NULL) panic.
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=24
Nilesh Javali
maintainerPATCH v6 25/56 scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters
In reply to Nilesh Javali29xx 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).
--- drivers/scsi/qla2xxx/qla_inline.h | 16 ++++ drivers/scsi/qla2xxx/qla_isr.c | 118 ++++++++++++++++++------------ drivers/scsi/qla2xxx/qla_os.c | 1 + 3 files changed, 87 insertions(+), 48 deletions(-)
drivers/scsi/qla2xxx/qla_inline.h +16 -0
@@ -103,6 +103,22 @@ qla_rsp_entry_size(struct qla_hw_data *ha)return IS_QLA29XX (ha) ?sizeof (struct response_ext ) :sizeof (response_t); } +/** +* qla_sts_cont_data_size() - status-continuation IOCB data payload size. +* @ha: HBA pointer +* +* sts_cont_entry_t and struct sts_cont_entry_ext share the same header and +* data offset; only the trailing data[] size differs (60 vs 124 bytes). +* Returns that size so callers need not branch on the adapter type. +*/ +static inline u32 +qla_sts_cont_data_size (struct qla_hw_data *ha) +{ +return IS_QLA29XX (ha) ? + sizeof_field(struct sts_cont_entry_ext, data) : +sizeof_field (sts_cont_entry_t, data); +} +static inline void qla2x00_poll (struct rsp_que *rsp) {
drivers/scsi/qla2xxx/qla_isr.c +70 -48
270 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_os.c +1 -0
@@ -8411,6 +8411,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 );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 25/56] scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] FORTIFY_SOURCE Buffer Over-Read Panic - [High] DMA Synchronization Hazard --
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] FORTIFY_SOURCE Buffer Over-Read Panic
- [High] DMA Synchronization Hazard
--
--- Patch [25]: [PATCH v6 25/56] scsi: qla2xxx: Handle sts_cont_entry_ext_t for 29xx adapters --- commit 90b126fb190842b2de74935641902992115ca941
Author: Nilesh Javali <[email protected]>
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.
drivers/scsi/qla2xxx/qla_isr.c int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha, · line 280
Quoted 11 lines
drivers/scsi/qla2xxx/qla_isr.c +2
-2@@ -271,10 +276,12 @@ 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; + *pkt = rsp_q->ring_ptr; + data = ((sts_cont_entry_t *)*pkt)->data;
[Severity: High]
Will this unconditional cast trigger a buffer over-read panic on QLA29XX adapters?
When CONFIG_FORTIFY_SOURCE is enabled, the compiler tracks object bounds to prevent buffer overflows. Here, the packet is cast to sts_cont_entry_t, which limits the compiler's view of the data array to 60 bytes.
Since qla_sts_cont_data_size() returns 124 bytes for 29xx adapters, a subsequent memcpy() using this data pointer could exceed the 60-byte known bound and trigger a fortify_panic().
Could this dynamically select the correct pointer type, such as casting to struct sts_cont_entry_ext, based on the adapter type?
Quoted 1 line
drivers/scsi/qla2xxx/qla_isr.c +1
-0+ data_sz =qla_sts_cont_data_size (ha);
[ ... ]
drivers/scsi/qla2xxx/qla_isr.c qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt, · line 915
Quoted 2 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0@@ -906,28 +915,24 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,continue ;
[Severity: High]
Can this loop condition result in silent data corruption by copying stale memory?
Looking at qla27xx_copy_multiple_pkt(), the driver polls the signature field to wait for continuation IOCBs from the hardware:
if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) {
...
cpu_relax();
continue;
}The signature field is located at offset 60, which falls within the first 64-byte cacheline. Since 29xx adapters use 128-byte extended IOCBs, the data payload extends into the second cacheline (bytes 64-127).
PCIe root complexes and CPU memory controllers do not guarantee ordering between multiple cacheline writes within a single DMA transaction. If the CPU observes the updated signature in the first cacheline, could it proceed to copy the entire 124-byte payload while the second cacheline still contains stale data?
drivers/scsi/qla2xxx/qla_isr.c qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt, · line 919
Quoted 6 lines
drivers/scsi/qla2xxx/qla_isr.c +2
-2} - new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr; - *pkt = new_pkt; + *pkt = rsp_q->ring_ptr; + data = ((sts_cont_entry_t *)*pkt)->data;
[Severity: High]
Similarly, does this cast also restrict the object bounds for FORTIFY_SOURCE and risk a panic when copying up to 124 bytes during qla27xx_copy_multiple_pkt()?
Quoted 1 line
drivers/scsi/qla2xxx/qla_isr.c +1
-0+ data_sz =qla_sts_cont_data_size (ha);
[ ... ]
drivers/scsi/qla2xxx/qla_isr.c qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt, · line 1206
Quoted 2 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0@@ -1190,10 +1206,12 @@ qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,continue ;
[Severity: High]
Does this exhibit the same DMA synchronization hazard when polling the signature field in qla27xx_copy_fpin_pkt() while waiting for 128-byte entries?
drivers/scsi/qla2xxx/qla_isr.c qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt, · line 919
Quoted 6 lines
drivers/scsi/qla2xxx/qla_isr.c +2
-2} - new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr; - *pkt = new_pkt; + *pkt = rsp_q->ring_ptr; + data = ((sts_cont_entry_t *)*pkt)->data;
[Severity: High]
Does this cast also restrict the object bounds for FORTIFY_SOURCE and risk a panic when copying up to 124 bytes during qla27xx_copy_fpin_pkt()?
Quoted 1 line
drivers/scsi/qla2xxx/qla_isr.c +1
-0+ data_sz =qla_sts_cont_data_size (ha);
[ ... ]
Quoted 15 lines
drivers/scsi/qla2xxx/qla_isr.c +2
-2@@ -3691,6 +3711,7 @@ 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 = ((sts_cont_entry_t *)pkt)->data;if (!sp || !GET_CMD_SENSE_LEN (sp))return ;@@ -3707,15 +3728,15 @@ 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 (sense_len > data_sz)
drivers/scsi/qla2xxx/qla_isr.c qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt) · line 3739
Quoted 10 lines
drivers/scsi/qla2xxx/qla_isr.c +3
-2+ 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);
[Severity: High]
Will this trigger a fortify_panic() when handling 128-byte payloads?
The function qla2x00_status_cont_entry() now accepts a void pointer but hardcodes the data pointer cast to sts_cont_entry_t. This destroys the compiler's view of the 124-byte payload.
Since sense_sz can evaluate to 124 bytes for 29xx adapters, calling memcpy() with a data pointer bounded to 60 bytes by the compiler will result in a buffer over-read panic.
Could the data pointer be derived using the appropriate extended structure when handling 29xx adapters?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=25
Nilesh Javali
maintainerPATCH v6 26/56 scsi: qla2xxx: Update handling of status entries for 29xx series
In reply to Nilesh JavaliModify 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.
--- 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(-)
drivers/scsi/qla2xxx/qla_edif.c +11 -4
@@ -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,
drivers/scsi/qla2xxx/qla_gbl.h +1 -1
@@ -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);
drivers/scsi/qla2xxx/qla_inline.h +45 -0
48 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_isr.c +69 -42
253 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_mbx.c +16 -12
@@ -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 ; + } } }
drivers/scsi/qla2xxx/qla_os.c +1 -0
@@ -8400,6 +8400,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 );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 26/56] scsi: qla2xxx: Update handling of status entries for 29xx series
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Integer underflow in par_sense_len calculation causes an out-of-bounds read from the DMA response ring buffer. --
--- Patch [26]: [PATCH v6 26/56] scsi: qla2xxx: Update handling of status entries for 29xx series --- commit 41d187f5b4a36f6b90c11b4e9bb88831b9152960
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Update handling of status entries for 29xx series
This commit modifies the qla2xxx driver to handle extended status entries for the 29xx series. It updates function signatures to accept generic pointers and adjusts the parsing logic for FWI2 status IOCBs.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0
[ ... ]
Quoted 12 lines
drivers/scsi/qla2xxx/qla_isr.c +3
-2@@ -3429,20 +3454,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 ))
drivers/scsi/qla2xxx/qla_isr.c qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) · line 3468
Quoted 10 lines
drivers/scsi/qla2xxx/qla_isr.c +4
-4- 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;
[Severity: High]
This is a pre-existing issue, but can this code cause an integer underflow when calculating the remaining sense length?
If the HBA firmware returns a status IOCB with SS_RESPONSE_INFO_LEN_VALID set and provides an rsp_data_len that is larger than the inline data buffer size in sf.data_sz, the subtraction further down in qla2x00_status_entry() will wrap around:
if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
if (IS_FWI2_CAPABLE(ha)) {
sense_data += rsp_info_len;
par_sense_len -= rsp_info_len;
}Since par_sense_len is an unsigned integer, it becomes a large positive value. Later, in qla2x00_handle_sense(), this bypasses the bounds check and leads to an out-of-bounds read from the DMA response ring buffer:
qla2x00_handle_sense() {
...
if (sense_len > par_sense_len)
sense_len = par_sense_len;
memcpy(cp->sense_buffer, sense_data, sense_len);
...
}Should rsp_info_len be validated against par_sense_len before subtracting it, to prevent potential leaks of kernel DMA memory?
Quoted 6 lines
drivers/scsi/qla2xxx/qla_isr.c +1
-2+ 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 )
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=26
Nilesh Javali
maintainerPATCH v6 27/56 scsi: qla2xxx: Enhance ct_entry_24xx_ext iocb handling for 29xx series
In reply to Nilesh JavaliRefine 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.
--- 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(-)
drivers/scsi/qla2xxx/qla_gs.c +117 -39
@@ -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; }
drivers/scsi/qla2xxx/qla_iocb.c +50 -28
111 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_os.c +1 -0
@@ -8349,6 +8349,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 );
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 28/56 scsi: qla2xxx: Enhance purex_entry handling for 29xx series
In reply to Nilesh JavaliUpdate 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).
--- drivers/scsi/qla2xxx/qla_def.h | 3 +- drivers/scsi/qla2xxx/qla_edif.c | 65 +++++++++++++++++------- drivers/scsi/qla2xxx/qla_isr.c | 88 ++++++++++++++++++++++++++------- drivers/scsi/qla2xxx/qla_os.c | 24 +++++++-- 4 files changed, 139 insertions(+), 41 deletions(-)
drivers/scsi/qla2xxx/qla_def.h +2 -1
@@ -5001,6 +5001,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
@@ -5015,7 +5016,7 @@ struct purex_item {atomic_t in_use;uint16_t size;struct { -uint8_t iocb[64 ]; +u8 iocb[QLA_MAX_IOCB_SIZE ]; } iocb; };
drivers/scsi/qla2xxx/qla_edif.c +47 -18
92 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_isr.c +71 -17
195 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_os.c +19 -5
@@ -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 ;
@@ -8378,6 +8391,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 );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 28/56] scsi: qla2xxx: Enhance purex_entry handling for 29xx series
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
New issues:
- [High] The 9-bit virtual port index (vp_idx) from 29xx hardware is silently truncated to 8 bits.
- [High] Incorrect response IOCB bitfield corruption for 29xx hardware due to writing via a legacy 24xx struct view.
- [High] Buffer over-read in continuation IOCB parsing on 29xx hardware triggers a FORTIFY_SOURCE panic.
Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but a crafted ELS payload containing 0xDEADDEAD at offset 16 will permanently hang the response queue.
- [High] This problem wasn't introduced by this patch, but __qla_consume_iocb consumes an extra, unrelated IOCB and fails to clear the original packet's signature.
- [High] This problem wasn't introduced by this patch, but there is a data race between atomic_inc_return and non-atomic memset on the default PUREX item.
- [High] This problem wasn't introduced by this patch, but there is an infinite polling loop inside interrupt context causing potential hard lockup. --
--- Patch [28]: [PATCH v6 28/56] scsi: qla2xxx: Enhance purex_entry handling for 29xx series --- commit 44ae6bdcc8dd39ac0f056b9473fb3475613ffb9b
Author: Nilesh Javali <[email protected]>
Subject: scsi: qla2xxx: Enhance purex_entry handling for 29xx series
This patch updates purex_entry handling to support the 29xx series by differentiating between standard 64-byte and 128-byte extended structures. It reuses overlapping byte views to avoid duplicating read paths.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_edif.c +0
-0@@ -2544,26 +2544,55 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
[ ... ]
Quoted 2 lines
drivers/scsi/qla2xxx/qla_edif.c +2
-0+uint8_t vp_idx; +struct purex_entry_24xx *p = *pkt;
[ ... ]
drivers/scsi/qla2xxx/qla_edif.c void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp) · line 2575
Quoted 3 lines
drivers/scsi/qla2xxx/qla_edif.c +3
-0+if (IS_QLA29XX (ha)) + vp_idx =le16_to_cpu (((struct purex_entry_24xx_ext *) + *pkt)->vp_idx);
[Severity: High]
Does assigning the 16-bit packed vp_idx value to a uint8_t local variable truncate the 9-bit virtual port index for 29xx hardware? This looks like it might cause responses for NPIV virtual ports with IDs 256 and above to be misrouted or dropped.
[ ... ]
Quoted 4 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0@@ -202,6 +202,11 @@ void __qla_consume_iocb(struct scsi_qla_host *vha,
[ ... ]
drivers/scsi/qla2xxx/qla_isr.c
Quoted 4 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0entry_count_remaining = purex->entry_count;while (entry_count_remaining >0 ) { new_pkt = rsp_q->ring_ptr; *pkt = new_pkt;
[Severity: High]
This is a pre-existing issue, but does __qla_consume_iocb skip the first packet and over-consume the ring buffer?
The loop executes entry_count times starting from the next packet:
while (entry_count_remaining > 0) {
new_pkt = rsp_q->ring_ptr;
*pkt = new_pkt;Could this consume and silently drop the next valid IOCB while leaving the original IOCB signature uncleared?
[ ... ]
Quoted 1 line
drivers/scsi/qla2xxx/qla_isr.c +0
-0@@ -262,14 +275,24 @@ int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
[ ... ]
drivers/scsi/qla2xxx/qla_isr.c int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha, · line 286
Quoted 8 lines
drivers/scsi/qla2xxx/qla_isr.c +6
-1+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); + }
[Severity: High]
Is there a risk of a FORTIFY_SOURCE buffer over-read panic during continuation IOCB parsing on 29xx hardware?
In __qla_copy_purex_to_buffer and similar functions, the data pointer is extracted using the sts_cont_entry_t structure:
data = ((sts_cont_entry_t *)*pkt)->data;
data_sz = qla_sts_cont_data_size(ha);Since sts_cont_entry_t->data is statically defined as a 60-byte array, FORTIFY_SOURCE sets __builtin_object_size to 60. On 29xx hardware, data_sz returns 124 bytes. Could the subsequent memcpy trigger a panic by attempting to copy up to 124 bytes from a 60-byte object?
[ ... ]
Quoted 1 line
drivers/scsi/qla2xxx/qla_isr.c +0
-0@@ -867,6 +891,13 @@ qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
[ ... ]
drivers/scsi/qla2xxx/qla_isr.c qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt, · line 897
Quoted 4 lines
drivers/scsi/qla2xxx/qla_isr.c +4
-0+ }else if (IS_QLA29XX (ha)) { + purex_ext = *pkt; + total_bytes = (le16_to_cpu (purex_ext->frame_size) &0x0FFF ) - +PURX_ELS_HEADER_SIZE ;
[Severity: High]
This is a pre-existing issue, but can the spin loop in qla27xx_copy_multiple_pkt cause a hard lockup?
If the hardware fails to provide the next packet, the code executes an unbounded spin loop in interrupt context:
if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) {
ql_dbg(...);
cpu_relax();
continue;
}Could a hardware fault or maliciously crafted entry_count trap the CPU forever?
[ ... ]
Quoted 1 line
drivers/scsi/qla2xxx/qla_isr.c +0
-0@@ -1075,9 +1110,9 @@ qla24xx_alloc_purex_item(scsi_qla_host_t *vha, uint16_t size)
[ ... ]
drivers/scsi/qla2xxx/qla_isr.c qla24xx_alloc_purex_item(scsi_qla_host_t *vha, uint16_t size) · line 1118
Quoted 3 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0}else {if (atomic_inc_return (&vha->default_item.in_use) ==1 ) { item = &vha->default_item;
[Severity: High]
This is a pre-existing issue, but is there a data race when acquiring the default PUREX item?
In qla24xx_alloc_purex_item, the code uses atomic_inc_return to acquire the item:
if (atomic_inc_return(&vha->default_item.in_use) == 1) {However, in qla24xx_free_purex_item, the memory is cleared with a non-atomic memset:
memset(&item->vha->default_item, 0, sizeof(struct purex_item));
Could two threads simultaneously acquire the default_item if the memset clears the in_use field while another thread is checking it out?
[ ... ]
Quoted 1 line
drivers/scsi/qla2xxx/qla_isr.c +0
-0@@ -4151,6 +4201,8 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
[ ... ]
drivers/scsi/qla2xxx/qla_isr.c void qla24xx_process_response_queue(struct scsi_qla_host *vha, · line 4159
Quoted 5 lines
drivers/scsi/qla2xxx/qla_isr.c +2
-2case PUREX_IOCB_TYPE : - purex_entry = (void *)pkt; -switch (purex_entry->els_frame_payload[3 ]) { +if (IS_QLA29XX (ha)) { + purex_entry_ext = (void *)pkt;
[Severity: High]
This is a pre-existing issue, but can the response queue permanently hang if a crafted ELS payload contains 0xDEADDEAD at offset 16?
In qla24xx_process_response_queue, the signature field is evaluated to determine if the hardware has written a new IOCB:
while (rsp->ring_index != rsp_in &&
rsp->ring_ptr->signature != RESPONSE_PROCESSED) {Because the signature field overlaps with bytes 16-19 of the els_frame_payload, could a malicious payload prematurely terminate the polling loop and prevent further packets from being processed?
[ ... ]
Quoted 4 lines
drivers/scsi/qla2xxx/qla_os.c +0
-0@@ -6209,15 +6211,26 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
[ ... ]
drivers/scsi/qla2xxx/qla_os.c void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, · line 6224
Quoted 4 lines
drivers/scsi/qla2xxx/qla_os.c +4
-0+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 );
[Severity: High]
Similarly, does extracting the 16-bit vp_idx and storing it in a uint8_t local variable truncate the value before assigning it to the response IOCB?
[ ... ]
drivers/scsi/qla2xxx/qla_os.c void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, · line 6275
Quoted 8 lines
drivers/scsi/qla2xxx/qla_os.c +1
-1@@ -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;
[Severity: High]
Will writing to rsp_els->vp_index and rsp_els->sof_type byte-by-byte corrupt the packed bitfield on 29xx hardware?
In the 24xx struct view, these are separate bytes, but on 29xx they overlap with the __le16 vp_idx_sof packed bitfield. Writing EST_SOFI3 to the 8-bit sof_type could clear the 9th bit of vp_index and set the wrong frame properties.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=28
Nilesh Javali
maintainerPATCH v6 29/56 scsi: qla2xxx: Update handling of ELS IOCBs for 29xx series
In reply to Nilesh JavaliUpdate 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.
--- 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(-)
drivers/scsi/qla2xxx/qla_gbl.h +1 -1
@@ -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,
drivers/scsi/qla2xxx/qla_inline.h +28 -0
@@ -863,3 +863,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 ; + } +}
drivers/scsi/qla2xxx/qla_iocb.c +18 -10
@@ -2975,8 +2975,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;
@@ -2987,11 +2988,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;
@@ -3322,9 +3323,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 ;
@@ -3333,11 +3335,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;
@@ -3358,8 +3360,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;
@@ -3370,8 +3373,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 =
@@ -4203,6 +4206,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 :
drivers/scsi/qla2xxx/qla_isr.c +18 -8
@@ -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); }/**
@@ -2385,7 +2394,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;
@@ -2395,7 +2405,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,
drivers/scsi/qla2xxx/qla_os.c +20 -11
@@ -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
@@ -8376,6 +8384,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 );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 29/56] scsi: qla2xxx: Update handling of ELS IOCBs for 29xx series
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [Critical] The `els_entry_24xx_ext` structure uses C bitfields for `vp_index` and `sof_type` over an…
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] The els_entry_24xx_ext structure uses C bitfields for vp_index and sof_type over an __le16 type, which violates kernel hardware interface standards and causes endianness corruption.
- [High] In qla24xx_process_abts(), the driver formats the ABTS response for 29xx adapters using the legacy 64-byte abts_entry_24xx layout, which truncates the 9-bit vp_idx to 8 bits.
- [High] The intermediate struct qla_els_pt_arg defines vp_idx as a u8, which truncates the new 9-bit virtual port indices on 29xx adapters.
--
--- Patch [29]: [PATCH v6 29/56] scsi: qla2xxx: Update handling of ELS IOCBs for 29xx series --- commit d16d36ca3053582bede2c0cc15922ffd29809f7f
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Update handling of ELS IOCBs for 29xx series
Update ELS IOCB handling to support the extended 128-byte els_entry_24xx_ext structure used by 29xx series adapters.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_inline.h +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_inline.h qla_sts_fwi2_extract(struct qla_hw_data *ha, void *pkt, · line 870
Quoted 9 lines
drivers/scsi/qla2xxx/qla_inline.h +8
-0@@ -863,3 +863,31 @@ qla_sts_fwi2_extract(struct qla_hw_data *ha, void *pkt, +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 ;
[Severity: Critical]
Will this cause endianness corruption on big-endian architectures?
Hardware descriptors sent to the device should generally avoid C bitfields like vp_index and sof_type over an __le16 type, as memory layout is compiler- and endian-dependent. A native assignment here might generate host-endian accesses instead of proper little-endian hardware writes, which could cause the adapter to read garbled virtual port indices and SOF types.
Quoted 12 lines
drivers/scsi/qla2xxx/qla_inline.h +7
-0+ }else { +struct els_entry_24xx *e = pkt; + + e->vp_index = vp_idx; + e->sof_type =EST_SOFI3 ; + } +}drivers/scsi/qla2xxx/qla_iocb.c +0
-0
[ ... ]
Quoted 10 lines
drivers/scsi/qla2xxx/qla_iocb.c +3
-2@@ -3322,9 +3323,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; +
[ ... ]
drivers/scsi/qla2xxx/qla_iocb.c void qla_els_pt_iocb(struct scsi_qla_host *vha, · line 3341
Quoted 6 lines
drivers/scsi/qla2xxx/qla_iocb.c +1
-2- 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);
[Severity: High]
Could this pass a truncated virtual port index for 29xx adapters?
In qla_def.h, struct qla_els_pt_arg defines vp_idx as a u8. Since 29xx adapters use a 9-bit virtual port index, will assigning a->vp_idx truncate values >= 256 before they are passed to qla_els_set_vp_sof()?
This might cause ELS passthrough commands to execute on the wrong virtual port.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_isr.c qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt) · line 146
Quoted 9 lines
drivers/scsi/qla2xxx/qla_isr.c +1
-1@@ -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 ;
[Severity: High]
Does this code still format the ABTS response for 29xx adapters using the legacy 64-byte abts_entry_24xx layout?
If abts_rsp casts rsp_pkt to struct abts_entry_24xx, reading and writing the 8-bit abts->vp_idx later in this function might discard the 9th bit. Would this cause virtual port indices > 255 to be modulo-256 truncated, routing ABTS responses to the wrong tenant's virtual port?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=29
Nilesh Javali
maintainerPATCH v6 30/56 scsi: qla2xxx: Add size check for ELS status entry layout on 29xx
In reply to Nilesh JavaliAdd 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.
--- drivers/scsi/qla2xxx/qla_isr.c | 31 +++++++++++++++++++++++-------- drivers/scsi/qla2xxx/qla_os.c | 1 + 2 files changed, 24 insertions(+), 8 deletions(-)
drivers/scsi/qla2xxx/qla_isr.c +23 -8
@@ -2359,6 +2359,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" ;
@@ -2400,7 +2416,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);
@@ -2461,14 +2477,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 ; }
@@ -2496,8 +2513,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 ]); }
@@ -2514,8 +2530,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 ]); }
drivers/scsi/qla2xxx/qla_os.c +1 -0
@@ -8386,6 +8386,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 );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 30/56] scsi: qla2xxx: Add size check for ELS status entry layout on 29xx
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Hardware-defined structures els_sts_entry_24xx_ext, els_entry_24xx_ext, abts_entry_24xx_ext, and vp_rpt_id_entry_24xx_ext use C bitfields, which breaks memory layout on big-endian architectures.
Pre-existing issues:
- [High] Missing dma_rmb() after checking the response queue entry signature, causing a data race against the hardware DMA. --
--- Patch [30]: [PATCH v6 30/56] scsi: qla2xxx: Add size check for ELS status entry layout on 29xx --- commit 1f1ccbc0c325b75366f8fa3f7fd4fcf61ec13421
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Add size check for ELS status entry layout on 29xx
This commit adds a BUILD_BUG_ON check to validate that struct els_sts_entry_24xx_ext is 128 bytes, matching the 29xx firmware IOCB size. It also adds a docblock in qla24xx_els_ct_entry() detailing the memory layout overlay and improves log messages.
Quoted 5 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0
drivers/scsi/qla2xxx/qla_isr.c static void · line 2368
Quoted 10 lines
drivers/scsi/qla2xxx/qla_isr.c +7
-0@@ -2359,6 +2359,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
[Severity: High]
Does defining C bitfields in the hardware structure els_sts_entry_24xx_ext break the memory layout on big-endian architectures?
In drivers/scsi/qla2xxx/qla_fw29.h:els_sts_entry_24xx_ext:
__le16 vp_index : 9; /* VP Index 9bits */ __le16 reserved_1_sof : 3; __le16 sof_type : 4;
Using __le16 with bitfields doesn't fix the endianness of the bitfields themselves. Because they are placed in an implementation-defined order (LSB-to-MSB on little-endian vs MSB-to-LSB on big-endian), hardware receives scrambled values on big-endian architectures.
A similar issue appears in els_entry_24xx_ext. Can this lead to device failure when communicating with the 29xx firmware on big-endian systems like s390x or PowerPC?
[ ... ]
[Severity: High]
This is a pre-existing issue, but is there a missing dma_rmb() after checking the response queue entry signature in qla24xx_process_response_queue()?
In drivers/scsi/qla2xxx/qla_isr.c:qla24xx_process_response_queue():
while (rsp->ring_index != rsp_in &&
rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
pkt = (void *)rsp->ring_ptr;
cur_ring_index = rsp->ring_index;
qla_rsp_ring_advance(rsp);
if (((response_t *)pkt)->entry_status != 0) {The loop condition reads the descriptor signature to check for completion, but accessing the payload (like entry_status) without executing dma_rmb() first can cause a data race against the hardware DMA.
On weakly ordered architectures (e.g., ARM64, PowerPC), does this allow speculative out-of-order reads, leading to parsing stale descriptor data?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=30
Nilesh Javali
maintainerPATCH v6 31/56 scsi: qla2xxx: Add 29xx extended logio IOCB support
In reply to Nilesh JavaliThe 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.
--- drivers/scsi/qla2xxx/qla_inline.h | 19 ++++++++++++++ drivers/scsi/qla2xxx/qla_iocb.c | 28 +++++++++++++-------- drivers/scsi/qla2xxx/qla_isr.c | 41 ++++++++++++++++++------------- drivers/scsi/qla2xxx/qla_mbx.c | 27 +++++++++++--------- drivers/scsi/qla2xxx/qla_os.c | 1 + 5 files changed, 78 insertions(+), 38 deletions(-)
drivers/scsi/qla2xxx/qla_inline.h +19 -0
@@ -119,6 +119,25 @@ qla_sts_cont_data_size(struct qla_hw_data *ha)sizeof_field (sts_cont_entry_t, data); } +/** +* qla_logio_set_vp_index() - write vp_index into a login/logout IOCB. +* @ha: HBA pointer +* @pkt: logio IOCB (logio_entry_24xx or logio_entry_24xx_ext) +* @vp_idx: virtual port index +* +* vp_index widens from u8 (logio_entry_24xx) to __le16 +* (logio_entry_24xx_ext) on 29xx; write the field at the right width. +*/ +static inline void +qla_logio_set_vp_index (struct qla_hw_data *ha,void *pkt,u16 vp_idx) +{ +if (IS_QLA29XX (ha)) + ((struct logio_entry_24xx_ext *)pkt)->vp_index = +cpu_to_le16 (vp_idx); +else + ((struct logio_entry_24xx *)pkt)->vp_index = vp_idx; +} +static inline void qla2x00_poll (struct rsp_que *rsp) {
drivers/scsi/qla2xxx/qla_iocb.c +18 -10
@@ -2564,8 +2564,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 ;
@@ -2592,12 +2593,13 @@ 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; +qla_logio_set_vp_index (sp->vha->hw, pkt, 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 ;
@@ -2622,7 +2624,7 @@ 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; +qla_logio_set_vp_index (sp->vha->hw, pkt, sp->vha->vp_idx); } static void
@@ -2650,9 +2652,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) {
@@ -2669,7 +2673,7 @@ 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; +qla_logio_set_vp_index (sp->vha->hw, pkt, sp->vha->vp_idx); } static void
@@ -2691,12 +2695,14 @@ 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; +qla_logio_set_vp_index (sp->vha->hw, pkt, sp->vha->vp_idx); } static void
@@ -4057,8 +4063,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 );
@@ -4067,7 +4075,7 @@ 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; +qla_logio_set_vp_index (sp->vha->hw, pkt, sp->fcport->vha->vp_idx); }static int qla_get_iocbs_resource (struct srb *sp)
drivers/scsi/qla2xxx/qla_isr.c +24 -17
98 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_mbx.c +16 -11
@@ -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,9 @@ 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 , +qla_logio_set_vp_index (ha, lg, 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 +2680,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 +2851,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 +2860,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 +2879,9 @@ 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 , +qla_logio_set_vp_index (ha, lg, 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 +2903,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; }
drivers/scsi/qla2xxx/qla_os.c +1 -0
@@ -8392,6 +8392,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 );
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 32/56 scsi: qla2xxx: Enhance task management IOCB handling for 29xx series
In reply to Nilesh JavaliUpdate 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.
--- 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(-)
drivers/scsi/qla2xxx/qla_iocb.c +22 -9
@@ -2727,7 +2727,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;
@@ -2736,26 +2736,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)); } }
drivers/scsi/qla2xxx/qla_mbx.c +14 -4
@@ -3411,6 +3411,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;
@@ -3450,16 +3451,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,
drivers/scsi/qla2xxx/qla_os.c +1 -0
@@ -8428,6 +8428,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 );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 32/56] scsi: qla2xxx: Enhance task management IOCB handling for 29xx series
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] qla24xx_abort_iocb() and qla24xx_abort_command() fail to use the extended 29xx layout…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] qla24xx_abort_iocb() and qla24xx_abort_command() fail to use the extended 29xx layout (abort_entry_24xx_ext) for ABORT_IOCB_TYPE commands.
- [High] qla_nvme_abort_set_option() writes to incorrect struct offsets for 29xx adapters.
--
--- Patch [32]: [PATCH v6 32/56] scsi: qla2xxx: Enhance task management IOCB handling for 29xx series --- commit f1cddf95aa4847713d2ce2a2f2a175d85c061018
Author: Nilesh Javali <[email protected]>
Subject: scsi: qla2xxx: Enhance task management IOCB handling for 29xx series
This commit updates qla24xx_tm_iocb() and __qla24xx_issue_tmf() to support the extended task management structure for 29xx adapters. It introduces a common view for the IOCB header and branches on IS_QLA29XX() for diverging port_id and vp_index assignments.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_iocb.c +0
-0
[ ... ]
Quoted 26 lines
drivers/scsi/qla2xxx/qla_iocb.c +9
-3@@ -2736,26 +2736,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;
drivers/scsi/qla2xxx/qla_iocb.c qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) · line 2766
Quoted 10 lines
drivers/scsi/qla2xxx/qla_iocb.c +9
-1- 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; + }
[Severity: High]
Does this same IS_QLA29XX check need to be applied to abort IOCB handling as well?
In qla24xx_abort_iocb() and qla24xx_abort_command(), for ABORT_IOCB_TYPE commands, vp_index is written at offset 51. Without an IS_QLA29XX check, it misses the required offset 18 for the extended 29xx layout (abort_entry_24xx_ext).
When an asynchronous abort is issued on a 29xx adapter, this could result in 29xx firmware reading a zeroed vp_index and an invalid port ID, potentially leading to abort failures and host resets.
[Severity: High]
Similarly, does qla_nvme_abort_set_option() need to be updated to write to the correct struct offsets for 29xx adapters?
It currently writes the retry count to offset 56 (drv.abts_rty_cnt) instead of the 29xx-expected offset 24. If NVMe command timeouts trigger this path, the aborts could miss their driver-specified retry counts and response timeouts on 29xx adapters, corrupting other fields in the 128-byte IOCB.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=32
Nilesh Javali
maintainerPATCH v6 33/56 scsi: qla2xxx: Add abort command handling for 29xx series
In reply to Nilesh JavaliExtend 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.
--- 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(-)
drivers/scsi/qla2xxx/qla_gbl.h +2 -4
@@ -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);
drivers/scsi/qla2xxx/qla_iocb.c +35 -17
67 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_isr.c +10 -4
@@ -3961,7 +3961,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;
@@ -3973,7 +3973,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)
@@ -4175,8 +4182,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,
drivers/scsi/qla2xxx/qla_mbx.c +30 -15
88 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_nvme.c +42 -12
89 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_os.c +1 -0
@@ -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 );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 33/56] scsi: qla2xxx: Add abort command handling for 29xx series
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Potential use-after-free of the original SRB (orig_sp) during asynchronous abort completion if the original command completes concurrently. --
--- Patch [33]: [PATCH v6 33/56] scsi: qla2xxx: Add abort command handling for 29xx series --- commit 7e8bef4c0a160dfafa23b4b48905c50cc258d592
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Add abort command handling for 29xx series
Extend the abort-IOCB code path to support the 29xx extended abort_entry_24xx_ext structure alongside the existing abort_entry_24xx.
Quoted 9 lines
drivers/scsi/qla2xxx/qla_isr.c +1
-1@@ -3973,7 +3973,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; +/*
drivers/scsi/qla2xxx/qla_isr.c qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, · line 3986
Quoted 10 lines
drivers/scsi/qla2xxx/qla_isr.c +7
-0+* 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)
[Severity: High]
This isn't a bug introduced by this patch, but can orig_sp be accessed after it has been freed here?
If an asynchronous command (e.g., SRB_LOGIN_CMD) times out, the timeout handler qla2x00_async_iocb_timeout() creates an abort SRB holding a pointer to the original SRB (abt_sp->cmd_sp = sp) without incrementing its kref. It then drops its timer reference on the original SRB.
If the firmware completes the original command concurrently, the ISR will process the completion and drop the initial reference. This can drop the refcount to 0, freeing the original SRB.
Later, when the abort IOCB completes, qla24xx_abort_iocb_entry() reads orig_sp = sp->cmd_sp (which now points to freed memory) and passes it to qla_nvme_abort_process_comp_status(), where dereferencing orig_sp->fcport or orig_sp->type would cause a use-after-free.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=33
Nilesh Javali
maintainerPATCH v6 34/56 scsi: qla2xxx: Enhance ABTS processing for 29xx series
In reply to Nilesh JavaliUse 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.
--- drivers/scsi/qla2xxx/qla_isr.c | 167 ++++++++++++++++++++------------- drivers/scsi/qla2xxx/qla_os.c | 1 + 2 files changed, 104 insertions(+), 64 deletions(-)
drivers/scsi/qla2xxx/qla_isr.c +103 -64
@@ -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
drivers/scsi/qla2xxx/qla_os.c +1 -0
@@ -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 );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 34/56] scsi: qla2xxx: Enhance ABTS processing for 29xx series
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Usage of C bitfields for hardware-defined struct fields causes endianness corruption on big-endian architectures.
Pre-existing issues:
- [High] DMA Use-After-Free and data race if qla2x00_issue_iocb() times out. --
--- Patch [34]: [PATCH v6 34/56] scsi: qla2xxx: Enhance ABTS processing for 29xx series --- commit 80e303232b31e50198f4e69882bfefaff470d483
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Enhance ABTS processing for 29xx series
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.
Quoted 13 lines
drivers/scsi/qla2xxx/qla_isr.c +5
-0@@ -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. +*/
[ ... ]
drivers/scsi/qla2xxx/qla_isr.c static inline void display_Laser_info(scsi_qla_host_t *vha, · line 99
Quoted 7 lines
drivers/scsi/qla2xxx/qla_isr.c +7
-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); \
[Severity: High]
Will these bitfield assignments cause endianness corruption on big-endian architectures?
Since vp_idx and sof_type in struct abts_entry_24xx_ext are defined as C bitfields:
__le16 vp_idx : 9; /* VP index 9 bits */
__le16 reserved_1_sof : 3;
__le16 sof_type : 4;Assigning directly to them allows the C compiler to pack them based on host endianness. On big-endian systems, this places the bitfields in the most significant bits, but the little-endian firmware expects them at the least significant bits.
Could this result in the firmware receiving an incorrect VP index and SOF type, breaking FC operations?
Quoted 3 lines
drivers/scsi/qla2xxx/qla_isr.c +3
-0+ (rsp)->rx_xch_addr = (src)->rx_xch_addr; \ + (rsp)->d_id[0 ] = (src)->s_id[0 ]; \ + (rsp)->d_id[1 ] = (src)->s_id[1 ]; \
[ ... ]
Quoted 9 lines
drivers/scsi/qla2xxx/qla_isr.c +5
-0@@ -140,60 +212,27 @@ qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt) }/* send ABTS response */ +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);
drivers/scsi/qla2xxx/qla_isr.c qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt) · line 229
Quoted 10 lines
drivers/scsi/qla2xxx/qla_isr.c +6
-0+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_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 does this function have a DMA use-after-free risk if qla2x00_issue_iocb times out?
Earlier in qla24xx_process_abts, qla2x00_issue_iocb is called to send an ELS response using rsp_pkt. If that command times out, the firmware may still be actively processing it.
Since the function merely logs a warning and proceeds, it ends up overwriting the actively-used DMA memory here in QLA_BUILD_ABTS_BA_ACC and re-issuing it. Finally, the function calls dma_free_coherent while the firmware might still be writing its completion status to the buffer, leading to a DMA use-after-free.
Quoted 1 line
drivers/scsi/qla2xxx/qla_isr.c +0
-0}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=34
Nilesh Javali
maintainerPATCH v6 35/56 scsi: qla2xxx: Update VP control IOCB handling for 29xx series
In reply to Nilesh JavaliUpdate 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.
--- 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(-)
drivers/scsi/qla2xxx/qla_iocb.c +16 -7
@@ -4074,22 +4074,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; }
drivers/scsi/qla2xxx/qla_isr.c +9 -4
@@ -3000,13 +3000,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 ;
@@ -4228,8 +4234,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)) {
drivers/scsi/qla2xxx/qla_os.c +1 -0
@@ -8437,6 +8437,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 );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 35/56] scsi: qla2xxx: Update VP control IOCB handling for 29xx series
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing bounds check on vp_index allows an out-of-bounds array write within the IOCB struct in qla25xx_ctrlvp_iocb().
- [High] Missing dma_rmb() after reading the ownership signature from the DMA response queue descriptor.
--
--- Patch [35]: [PATCH v6 35/56] scsi: qla2xxx: Update VP control IOCB handling for 29xx series --- commit 3663b31ed4aaf500c1d3217a87f3276026fd224c
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Update VP control IOCB handling for 29xx series
This patch updates the VP control IOCB command and response handling to support the 29xx series adapters. It modifies qla25xx_ctrlvp_iocb() and qla_ctrlvp_completed() to accept generic void pointers, allowing them to handle both 64-byte and 128-byte entry layouts seamlessly.
Quoted 21 lines
drivers/scsi/qla2xxx/qla_iocb.c +10
-1@@ -4074,22 +4074,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;
[ ... ]
drivers/scsi/qla2xxx/qla_iocb.c qla_nvme_ls(srb_t *sp, struct pt_ls4_request *cmd_pkt) · line 4102
Quoted 13 lines
drivers/scsi/qla2xxx/qla_iocb.c +6
-0/* * 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;
[Severity: High]
This isn't a bug introduced by this patch, but does this write corrupt adjacent fields in the DMA-mapped IOCB structure?
Since max_npiv_vports can be configured up to 255, vp_index can reach 254. When vp_index is greater than 128, the map index becomes >= 16.
Because vp_idx_map is only a 16-byte array, writing to vce->vp_idx_map[map] in this case writes past the end of the array, potentially corrupting fields like flags, id, hopct, and reserved_5 before the descriptor is sent to the firmware.
Quoted 1 line
}
[ ... ]
Quoted 4 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_isr.c void qla24xx_process_response_queue(struct scsi_qla_host *vha, · line 4237
Quoted 7 lines
drivers/scsi/qla2xxx/qla_isr.c +1
-2@@ -4228,8 +4234,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);
[Severity: High]
This is a pre-existing issue, but is it possible for the CPU to read stale descriptor fields when processing this DMA response queue?
In qla24xx_process_response_queue(), the CPU reads the descriptor ownership signature:
while (rsp->ring_index != rsp_in &&
rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
...
if (((response_t *)pkt)->entry_status != 0) {If the CPU observes a changed signature, it assumes device ownership transfer is complete and proceeds to read payload fields (like entry_status and the type fields handled in this switch statement).
Without a dma_rmb() immediately after reading the signature, weakly-ordered CPUs may reorder the memory reads and fetch the payload fields before the DMA write for them is visible in CPU cache. Would adding a dma_rmb() prevent the driver from processing uninitialized or stale status payload data?
Quoted 3 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0break ;case PUREX_IOCB_TYPE :if (IS_QLA29XX (ha)) {
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=35
Nilesh Javali
maintainerPATCH v6 36/56 scsi: qla2xxx: Add build-time size check for VP config IOCB layout
In reply to Nilesh JavaliAdd 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.
--- drivers/scsi/qla2xxx/qla_mbx.c | 8 +++++++- drivers/scsi/qla2xxx/qla_os.c | 1 + 2 files changed, 8 insertions(+), 1 deletion(-)
drivers/scsi/qla2xxx/qla_mbx.c +7 -1
@@ -4364,6 +4364,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 ;
@@ -4392,7 +4399,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 );
drivers/scsi/qla2xxx/qla_os.c +1 -0
@@ -8436,6 +8436,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 );
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 37/56 scsi: qla2xxx: Add size check for extended VP report ID entry
In reply to Nilesh JavaliAdd 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.
--- 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(-)
drivers/scsi/qla2xxx/qla_fw29.h +1 -0
@@ -693,6 +693,7 @@ struct vp_rpt_id_entry_24xx_ext {uint8_t remote_nport_id[4 ]; } f2; } u; +uint8_t reserved_end[64 ]; };/*
drivers/scsi/qla2xxx/qla_gbl.h +1 -2
@@ -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 *);
drivers/scsi/qla2xxx/qla_isr.c +1 -2
@@ -4175,8 +4175,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, qla_sts_cont_data_size(rsp->hw));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);
drivers/scsi/qla2xxx/qla_mbx.c +21 -11
@@ -4086,15 +4086,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__);
@@ -4102,6 +4105,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 ];
@@ -4124,9 +4135,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,
@@ -4223,8 +4233,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 &&
@@ -4241,18 +4251,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 ; }
drivers/scsi/qla2xxx/qla_os.c +1 -0
@@ -8440,6 +8440,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 );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 37/56] scsi: qla2xxx: Add size check for extended VP report ID entry
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] Extracting vp_idx and vp_status using C bitfields over a little-endian __le16 type causes undefined behavior and data corruption on Big-Endian architectures.
Pre-existing issues:
- [High] The vport pointer (vp) is accessed after ha->vport_slock is released without holding a reference, leading to a potential Use-After-Free.
- [High] The fcport list is traversed locklessly for Format 2 RIDA IOCBs, and the found fcport is accessed after dropping tgt.sess_lock without holding a reference, leading to data races and Use-After-Free.
- [High] Missing dma_rmb() read barrier after polling the hardware DMA response queue signature.
--
--- Patch [37]: [PATCH v6 37/56] scsi: qla2xxx: Add size check for extended VP report ID entry --- commit b119ba076c242111b3050f1eff45472d3fdf947f
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Add size check for extended VP report ID entry
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.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_fw29.h +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_isr.c void qla24xx_process_response_queue(struct scsi_qla_host *vha,
Quoted 5 lines
drivers/scsi/qla2xxx/qla_isr.c +0
-0@@ -4175,8 +4175,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
[Severity: High]
This isn't a bug introduced by this patch, but looking at qla24xx_process_response_queue(), is a dma_rmb() read barrier needed after polling the hardware DMA response queue signature?
The driver checks if the signature is valid:
while (rsp->ring_index != rsp_in &&
rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
pkt = (void *)rsp->ring_ptr;
cur_ring_index = rsp->ring_index;
qla_rsp_ring_advance(rsp);
if (((response_t *)pkt)->entry_status != 0) {Without a dma_rmb() barrier after observing the valid signature, can the CPU speculatively reorder reads and fetch the queue entry payload before the hardware's DMA write is fully visible?
Quoted 9 lines
drivers/scsi/qla2xxx/qla_isr.c +1
-2qla_sts_cont_data_size(rsp->hw));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);
[ ... ]
Quoted 26 lines
drivers/scsi/qla2xxx/qla_mbx.c +5
-2@@ -4086,15 +4086,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__);
drivers/scsi/qla2xxx/qla_mbx.c qla24xx_report_id_acquisition(scsi_qla_host_t *vha, · line 4110
Quoted 6 lines
drivers/scsi/qla2xxx/qla_mbx.c +3
-0@@ -4102,6 +4105,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;
[Severity: High]
Does this extract the wrong bits on big-endian architectures?
struct vp_rpt_id_entry_24xx_ext defines vp_idx and vp_status as bitfields over an __le16 type:
__le16 vp_idx : 9; /* VP Index 9bits */ __le16 vp_status : 7; /* VP Status 7bits */
Since C bitfield layout is implementation- and endian-dependent, the compiler on big-endian CPUs typically allocates the first bitfield to the most significant bits.
Since the hardware writes the DMA data in little-endian format, should this be defined as a single __le16 field and parsed via le16_to_cpu() combined with bitwise masks to ensure it is endian-safe?
Quoted 7 lines
drivers/scsi/qla2xxx/qla_mbx.c +5
-0+ }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 ];
[ ... ]
Quoted 23 lines
drivers/scsi/qla2xxx/qla_mbx.c +4
-4@@ -4241,18 +4251,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 ; }
Quoted 1 line
}
[Severity: High]
This is a pre-existing issue, but can this lead to a use-after-free of the vp pointer?
In qla24xx_report_id_acquisition(), the code iterates over ha->vp_list while holding ha->vport_slock to find a matching vp. Once found, the lock is released without taking a reference count (e.g., atomic_inc(&vp->vref_count)).
Can vp be concurrently removed from the list and freed by qla24xx_vport_delete(), resulting in a use-after-free when the unreferenced vp is subsequently passed to qla_update_host_map(vp, id)?
[ ... ]
[Severity: High]
This is also a pre-existing issue, but I see fcport accessed outside of its protective lock in qla24xx_report_id_acquisition().
In the Format 1 path, sess_lock is held during lookup but dropped immediately:
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;Could a concurrent session deletion free this memory, causing a use-after-free when fcport is modified?
Also, in the Format 2 path, the list is traversed 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);Can this cause list corruption or a crash on stale pointers if other contexts modify this list under sess_lock?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=37
Nilesh Javali
maintainerPATCH v6 38/56 scsi: qla2xxx: Add LS4 pass-through IOCB handling for 29xx series
In reply to Nilesh JavaliFrom: Manish Rangankar <[email protected]>
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.
--- 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(-)
drivers/scsi/qla2xxx/qla_fw29.h +37 -0
@@ -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 */
drivers/scsi/qla2xxx/qla_iocb.c +50 -23
88 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_isr.c +5 -4
@@ -4035,7 +4035,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" ;
@@ -4045,7 +4045,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); }
@@ -4211,8 +4213,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 )
drivers/scsi/qla2xxx/qla_nvme.c +42 -22
79 lines not on this page · raw message
drivers/scsi/qla2xxx/qla_nvme.h +2 -2
@@ -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
drivers/scsi/qla2xxx/qla_os.c +1 -0
@@ -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 );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 38/56] scsi: qla2xxx: Add LS4 pass-through IOCB handling for 29xx series
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] The 29xx extended NVMe LS reject path truncates 9-bit virtual port indices (vp_idx >= 256) to 8 bits, potentially causing the reject IOCB to be sent on the wrong vport.
Pre-existing issues:
- [High] The function qla_nvme_ls_reject_iocb() modifies the hardware request queue and a shared DMA buffer without holding the required queue locks, causing queue corruption. --
--- Patch [38]: [PATCH v6 38/56] scsi: qla2xxx: Add LS4 pass-through IOCB handling for 29xx series --- commit f75839a47ccdbe873640f70512142d6ebee38618
Author: Manish Rangankar <[email protected]> Date: Thu Jul 23 05:03:55 2026 +0000
scsi: qla2xxx: Add LS4 pass-through IOCB handling for 29xx series
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.
Quoted 5 lines
drivers/scsi/qla2xxx/qla_nvme.c +0
-0@@ -1197,37 +1197,57 @@ static void qla_nvme_fc_format_rjt(void *buf, u8 ls_cmd, u8 reason,
[ ... ]
drivers/scsi/qla2xxx/qla_nvme.c static void qla_nvme_fc_format_rjt(void *buf, u8 ls_cmd, u8 reason, · line 1228
Quoted 4 lines
drivers/scsi/qla2xxx/qla_nvme.c +4
-0+if (IS_QLA29XX (ha)) { +struct pt_ls4_request_ext *ext = lsrjt_iocb; + + ext->vp_index =cpu_to_le16 (a->vp_idx);
[Severity: High]
Does this truncate 9-bit virtual port indices (vp_idx >= 256)?
The struct pt_ls4_request_ext widens vp_index to a 16-bit integer, but the intermediate struct qla_nvme_lsrjt_pt_arg still defines vp_idx as a u8.
Assigning a->vp_idx to ext->vp_index will drop the highest bit for any index over 255. Will this cause the reject IOCB to be sent on the wrong vport if an initiator sends an invalid request to a high-numbered vport?
Quoted 2 lines
drivers/scsi/qla2xxx/qla_nvme.c +2
-0+ ext->tx_byte_count =cpu_to_le32 (a->tx_byte_count); + ext->rx_byte_count =0 ;
[ ... ]
drivers/scsi/qla2xxx/qla_nvme.c static void qla_nvme_fc_format_rjt(void *buf, u8 ls_cmd, u8 reason, · line 1252
Quoted 8 lines
static int
qla_nvme_ls_reject_iocb(structscsi_qla_host*vha, structqla_qpair*qp,drivers/scsi/qla2xxx/qla_nvme.c +1
-1struct 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 );
[Severity: High]
This is a pre-existing issue, but does calling __qla2x00_alloc_iocbs() here modify the hardware request queue safely?
__qla2x00_alloc_iocbs() typically requires the hardware queue lock (qp_lock_ptr) to be held to safely manipulate ring buffer pointers. However, qla_nvme_ls_reject_iocb() is called from qla2xxx_process_purls_pkt() in a workqueue context without holding the hardware_lock or qp_lock.
Additionally, it can be called from qla24xx_process_nvme_ls4_unsol() in interrupt context holding hardware_lock, but not qp_lock. Can this concurrent lockless access cause queue corruption or garbled NVMe reject payloads?
Quoted 3 lines
drivers/scsi/qla2xxx/qla_nvme.c +0
-0if (!lsrjt_iocb) {ql_log (ql_log_warn, vha,0x210e ,"qla2x00_alloc_iocbs failed.\n" );
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=38
Nilesh Javali
maintainerPATCH v6 39/56 scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support
In reply to Nilesh JavaliFrom: Manish Rangankar <[email protected]>
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.
--- 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_mbx.c | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-)
drivers/scsi/qla2xxx/qla_attr.c +2 -2
@@ -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",
drivers/scsi/qla2xxx/qla_bsg.c +12 -7
@@ -1962,7 +1962,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
@@ -2606,7 +2606,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));
@@ -2639,7 +2639,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));
@@ -2687,7 +2687,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));
@@ -2803,7 +2803,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);
@@ -2929,8 +2929,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 ;
drivers/scsi/qla2xxx/qla_def.h +1 -1
@@ -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))
drivers/scsi/qla2xxx/qla_mbx.c +1 -1
@@ -6566,7 +6566,7 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha,dma_addr_t dd_dma;if (!IS_QLA83XX (vha->hw) && !IS_QLA27XX (vha->hw) && - !IS_QLA28XX (vha->hw)) + !IS_QLA28XX (vha->hw) && !IS_QLA29XX (vha->hw))return QLA_FUNCTION_FAILED ; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x119f,
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 39/56] scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Pre-existing issues:
- [High] Multiple vendor-specific BSG handlers copy user data into an uninitialized stack buffer without validating the request payload length, leading to uninitialized stack variable usage and information leaks.
- [High] The qla28xx_validate_flash_image function fails to call bsg_job_done() on error paths but still returns QLA_SUCCESS (0), bypassing completion mechanisms and hanging the job.
- [High] Information leak via uninitialized kernel heap memory in qla2x00_do_dport_diagnostics.
- [High] Unaligned DMA mapping of an interior struct member in qla26xx_dport_diagnostics.
--
--- Patch [39]: [PATCH v6 39/56] scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support --- commit c26fb874cafb5af2254e6979b56c1d91494f6044
Author: Manish Rangankar <[email protected]>
scsi: qla2xxx: Adjust feature gating in BSG paths for 29xx support
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 and restrict unsupported operations on QLA29xx.
drivers/scsi/qla2xxx/qla_bsg.c static int qla2900_bsg_load_mpi(struct bsg_job *bsg_job) · line 1966
Quoted 11 lines
drivers/scsi/qla2xxx/qla_bsg.c +1
-1@@ -1962,7 +1962,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 ; }
[Severity: High]
This isn't a bug introduced by this patch, but does qla2x00_update_fru_versions in drivers/scsi/qla2xxx/qla_bsg.c read uninitialized stack values?
Multiple vendor-specific BSG handlers copy user data into an uninitialized stack buffer without validating the request payload length. For example, if the payload is short, the count variable can remain uninitialized:
qla2x00_update_fru_versions() {
...
uint8_t bsg[DMA_POOL_SIZE];
struct qla_image_version_list *list = (void *)bsg;
...
sg_copy_to_buffer(bsg_job->request_payload.sg_list,
bsg_job->request_payload.sg_cnt, list, sizeof(bsg));
image = list->version;
count = list->count;
...
while (count--) {
...
}This could lead to out-of-bounds DMA and hardware writes driven by uninitialized stack data.
Similarly, in qla2x00_read_fru_status, uninitialized stack memory might be used as device parameters:
qla2x00_read_fru_status() {
...
rval = qla2x00_read_sfp(vha, sfp_dma, sfp,
sr->field_address.device, sr->field_address.offset,
sizeof(sr->status_reg), sr->field_address.option);
...
}Can we validate the request payload length to prevent this regression?
[ ... ]
drivers/scsi/qla2xxx/qla_bsg.c qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job) · line 2809
Quoted 9 lines
drivers/scsi/qla2xxx/qla_bsg.c +1
-1@@ -2803,7 +2803,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);
[Severity: High]
This is a pre-existing issue, but does this allocation leak uninitialized kernel heap memory to user-space causing a regression?
If a user issues the dport diagnostics BSG command with a truncated request payload, kmalloc_obj allocates memory without zeroing it. The unwritten struct fields and padding could then be copied to the user reply payload:
qla2x00_do_dport_diagnostics() {
...
if (rval == QLA_SUCCESS) {
sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
bsg_job->reply_payload.sg_cnt, dd, sizeof(*dd));
}
...
}Could this regression expose sensitive kernel heap contents?
[Severity: High]
This is also a pre-existing issue, but does this unaligned DMA mapping risk memory corruption?
When the dport diagnostic BSG command is initiated, qla26xx_dport_diagnostics is called with the dd->buf member:
qla2x00_do_dport_diagnostics() {
...
rval = qla26xx_dport_diagnostics(
vha, dd->buf, sizeof(dd->buf), dd->options);
...
}Inside qla26xx_dport_diagnostics in drivers/scsi/qla2xxx/qla_mbx.c, this buffer is mapped for DMA:
qla26xx_dport_diagnostics() {
...
dd_dma = dma_map_single(&vha->hw->pdev->dev,
dd_buf, size, DMA_FROM_DEVICE);
...
}Since struct qla_dport_diag is packed, the buf member sits at a 2-byte offset. Mapping an unaligned struct member could violate DMA constraints, leading to silent memory corruption during cache flushes on architectures that are not cache-coherent, or hardware overwrite of adjacent fields. Can this regression be adjusted?
[ ... ]
drivers/scsi/qla2xxx/qla_bsg.c qla2x00_get_flash_image_status(struct bsg_job *bsg_job) · line 2938
Quoted 13 lines
drivers/scsi/qla2xxx/qla_bsg.c +7
-2@@ -2929,8 +2929,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; + }
[Severity: High]
This is a pre-existing issue, but does qla28xx_validate_flash_image in drivers/scsi/qla2xxx/qla_bsg.c skip completing the BSG job on error paths?
If the internal validation fails and rval is non-zero, it bypasses the bsg_job_done call:
qla28xx_validate_flash_image() {
...
if (!rval)
bsg_job_done(bsg_job, bsg_reply->result,
bsg_reply->reply_payload_rcv_len);
return QLA_SUCCESS;
}Returning QLA_SUCCESS without completing the job causes the BSG block layer to wait indefinitely. Could this hang the user-space process and cause a denial of service regression?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=39
Nilesh Javali
maintainerPATCH v6 40/56 scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking
In reply to Nilesh Javaliqla25xx_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.
--- drivers/scsi/qla2xxx/qla_mid.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-)
drivers/scsi/qla2xxx/qla_mid.c +12 -16
@@ -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 ;
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 40/56] scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Severe resource and memory leak on queue teardown due to reliance on a global flag and early returns on error. --
--- Patch [40]: [PATCH v6 40/56] scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking --- commit 4a4916d52b2174b3c6221fdaca0059abdec4d678
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Fix queue teardown NULL dma_free and bitmap locking
This commit addresses two bugs in the error paths of queue creation. It adds a NULL check before calling dma_free_coherent and ensures the same lock is held when clearing queue map entries during teardown.
Quoted 17 lines
drivers/scsi/qla2xxx/qla_mid.c +4
-3@@ -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 ;
drivers/scsi/qla2xxx/qla_mid.c qla25xx_free_req_que(struct scsi_qla_host *vha, struct req_que *req) · line 592
Quoted 10 lines
drivers/scsi/qla2xxx/qla_mid.c +2
-2if (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);
[Severity: High]
This is a pre-existing issue, but I noticed a potential leak related to queue teardown.
In drivers/scsi/qla2xxx/qla_mid.c:qla25xx_delete_req_que(), the driver relies on a global flag and returns early on error:
if (req && vha->flags.qpairs_req_created) {
req->options |= BIT_0;
ret = qla25xx_init_req_que(vha, req);
if (ret != QLA_SUCCESS)
return QLA_FUNCTION_FAILED;
qla25xx_free_req_que(vha, req);
}If the queue was never initialized in hardware (for example, if qla2xxx_create_qpair() passes startqp=false in target-only mode), qpairs_req_created is 0. This bypasses the call to qla25xx_free_req_que() entirely, silently leaking the memory and DMA rings.
Additionally, if hardware teardown fails and returns QLA_FUNCTION_FAILED, this propagates up to drivers/scsi/qla2xxx/qla_init.c:qla2xxx_delete_qpair():
ret = qla25xx_delete_req_que(vha, qpair->req);
if (ret != QLA_SUCCESS)
goto fail;
This aborts the remaining cleanup for the qpair, which abandons the response queue and MSI-X handlers.
Could this sequence leave the DMA mappings and IRQ vectors permanently orphaned on module unload?
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=40
Nilesh Javali
maintainerPATCH v6 41/56 scsi: qla2xxx: Replace __le16 bitfields with scalar and accessors
In reply to Nilesh JavaliC 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.
--- 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(-)
drivers/scsi/qla2xxx/qla_fw29.h +30 -9
@@ -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;
drivers/scsi/qla2xxx/qla_inline.h +4 -4
@@ -890,8 +890,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. */
@@ -901,8 +901,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;
drivers/scsi/qla2xxx/qla_isr.c +8 -7
@@ -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); }
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 41/56] scsi: qla2xxx: Replace __le16 bitfields with scalar and accessors
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Incomplete fix for endianness bug in 29xx extended IOCBs
Pre-existing issues:
- [High] Target mode ABTS failures on big-endian due to bitfield packing --
--- Patch [41]: [PATCH v6 41/56] scsi: qla2xxx: Replace __le16 bitfields with scalar and accessors --- commit aa60e92d6d4c10c7735dd3bda849923fc8a00254
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Replace __le16 bitfields with scalar and accessors
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.
Quoted 4 lines
Replace the three sets of
__le16bitfields (inels_entry_24xx_ext,els_sts_entry_24xx_ext, andabts_entry_24xx_ext) with a single__le16scalar field and provide inline accessor functions that use proper le16_to_cpu()/cpu_to_le16() with shift-and-mask operations.
[Severity: High]
Does this fix also need to be applied to vp_rpt_id_entry_24xx_ext in drivers/scsi/qla2xxx/qla_fw29.h?
It appears vp_rpt_id_entry_24xx_ext still uses __le16 bitfields for vp_idx and vp_status:
__le16 vp_idx : 9; /* VP Index 9bits */ __le16 vp_status : 7; /* VP Status 7bits */
When these fields are extracted in qla24xx_report_id_acquisition(), they will be read incorrectly on big-endian architectures, causing VP ID reporting and initialization to fail for 29xx series adapters.
Could this have been missed from the earlier patch "scsi: qla2xxx: Add size check for extended VP report ID entry" in this series?
Quoted 8 lines
Fixes 4e0e5b8c80e8 ("scsi: qla2xxx: Add 128-byte IOCB definitions for 29xx")Signed-off-by Nilesh Javali <[email protected]>Reviewed-by Hannes Reinecke <[email protected]>drivers/scsi/qla2xxx/qla_fw29.h +0
-0
[ ... ]
drivers/scsi/qla2xxx/qla_fw29.h struct abts_entry_24xx_ext { · line 589
Quoted 8 lines
drivers/scsi/qla2xxx/qla_fw29.h +1
-3@@ -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 */
[Severity: High]
This isn't a bug introduced by this patch, but does the abts_recv_from_24xx structure in drivers/scsi/qla2xxx/qla_target.h suffer from a similar bitfield packing issue?
Looking at abts_recv_from_24xx:
uint8_t reserved_3:4; uint8_t sof_type:4;
GCC packs the first bitfield in the most-significant bits on big-endian systems, moving sof_type to the least-significant bits. Since the hardware expects sof_type in the upper nibble, could this lead to malformed ABTS responses and target-mode functional failures?
This appears to be a pre-existing issue dating back to commit 2d70c103fd2a06.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=41
Nilesh Javali
maintainerPATCH v6 42/56 scsi: qla2xxx: Fix endianness annotations in vp_rpt_id_entry structures
In reply to Nilesh JavaliThe 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
--- 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(-)
drivers/scsi/qla2xxx/qla_fw.h +4 -4
@@ -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;
drivers/scsi/qla2xxx/qla_fw29.h +14 -6
@@ -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;
drivers/scsi/qla2xxx/qla_mbx.c +6 -3
@@ -4106,8 +4106,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;
@@ -4231,7 +4233,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 ) {
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 43/56 scsi: qla2xxx: Use 64-bit FPM word counters for 29xx host stats
In reply to Nilesh Javali29xx 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.
--- drivers/scsi/qla2xxx/qla_attr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/scsi/qla2xxx/qla_attr.c +2 -1
@@ -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 {
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 44/56 scsi: qla2xxx: Add 64G/128G port speed setting support
In reply to Nilesh JavaliThe 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.
--- drivers/scsi/qla2xxx/qla_attr.c | 8 +++++++- drivers/scsi/qla2xxx/qla_init.c | 9 ++++++++- drivers/scsi/qla2xxx/qla_mbx.c | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_attr.c +7 -1
@@ -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",
drivers/scsi/qla2xxx/qla_init.c +8 -1
@@ -4793,7 +4793,14 @@ qla24xx_config_rings(struct scsi_qla_host *vha)ql_dbg (ql_dbg_init, vha,0x00fd ,"Speed set by user : %s Gbps \n" ,qla2x00_get_link_speed_str (ha, ha->set_data_rate)); - icb->firmware_options_3 =cpu_to_le32 (ha->set_data_rate <<13 ); +/* +* The ICB data-rate field is 3 bits (bits 13-15); rates above +* 64G do not fit and would overflow into bit 16 (75 ohm +* termination select). Such rates are forced via MBC_DATA_RATE. +*/ +if (ha->set_data_rate <=PORT_SPEED_64GB ) + icb->firmware_options_3 = +cpu_to_le32 (ha->set_data_rate <<13 ); }/* PCI posting */
drivers/scsi/qla2xxx/qla_mbx.c +2 -0
@@ -5720,6 +5720,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 :
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 44/56] scsi: qla2xxx: Add 64G/128G port speed setting support
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] User-configured 128G port speed is silently lost upon HBA reset.
Pre-existing issues:
- [High] Applying a user-configured port speed (<= 64G) in the Initialization Control Block inadvertently wipes out other critical firmware flags. --
--- Patch [44]: [PATCH v6 44/56] scsi: qla2xxx: Add 64G/128G port speed setting support --- commit 8d7fef6e4c3ea0599d570b41649eeea6750d4564
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Add 64G/128G port speed setting support
This patch adds support for 64G and 128G port speeds by mapping sysfs inputs to the corresponding PORT_SPEED_* constants. It also updates the ring configuration to only set the data rate in the Initialization Control Block (ICB) for speeds up to 64G to prevent overflow.
Quoted 4 lines
drivers/scsi/qla2xxx/qla_init.c qla24xx_config_rings(struct scsi_qla_host *vha) · line 4801
Quoted 10 lines
drivers/scsi/qla2xxx/qla_init.c +6
-1@@ -4793,7 +4793,14 @@ qla24xx_config_rings(struct scsi_qla_host *vha)ql_dbg (ql_dbg_init, vha,0x00fd ,"Speed set by user : %s Gbps \n" ,qla2x00_get_link_speed_str (ha, ha->set_data_rate)); - icb->firmware_options_3 =cpu_to_le32 (ha->set_data_rate <<13 ); +/* +* The ICB data-rate field is 3 bits (bits 13-15); rates above +* 64G do not fit and would overflow into bit 16 (75 ohm +* termination select). Such rates are forced via MBC_DATA_RATE. +*/ +if (ha->set_data_rate <=PORT_SPEED_64GB )
[Severity: High]
Does this code silently drop the user-configured 128G port speed upon HBA reset?
If a user sets the 128G port speed via sysfs, and later a normal operational reset (such as a LIP reset or driver re-initialization) triggers qla24xx_config_rings(), the 128G speed won't be set here since it's > 64G.
However, the driver doesn't seem to issue the MBC_DATA_RATE mailbox command during or after the reset sequence to restore the 128G setting.
Does the adapter fall back to auto-negotiation or the NVRAM default in this case?
drivers/scsi/qla2xxx/qla_init.c qla24xx_config_rings(struct scsi_qla_host *vha) · line 4803
Quoted 2 lines
drivers/scsi/qla2xxx/qla_init.c +2
-0+ icb->firmware_options_3 = +cpu_to_le32 (ha->set_data_rate <<13 );
[Severity: High]
This is a pre-existing issue, but does this absolute assignment blindly overwrite the entire firmware_options_3 register instead of preserving previously configured bits?
When qla24xx_config_rings() applies a custom port speed (<= 64G), it overwrites flags like BIT_8 (N2N driver-initiated login) and BIT_0 (RIDA Format2) that were initialized earlier in qla24xx_nvram_config().
Can this break N2N topology login and other features when a custom port speed is used?
Quoted 3 lines
drivers/scsi/qla2xxx/qla_init.c +0
-0}/* PCI posting */
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=44
Nilesh Javali
maintainerPATCH v6 45/56 scsi: qla2xxx: Fix 64G link speed reporting in get_data_rate
In reply to Nilesh Javaliqla2x00_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.
--- drivers/scsi/qla2xxx/qla_mbx.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/scsi/qla2xxx/qla_mbx.c +3 -4
@@ -5785,10 +5785,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" );
@@ -5796,8 +5797,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;
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 45/56] scsi: qla2xxx: Fix 64G link speed reporting in get_data_rate
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] Incomplete removal of the `0x7` legacy sentinel filter in `qla2x00_set_data_rate()`, causing the…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Incomplete removal of the 0x7 legacy sentinel filter in qla2x00_set_data_rate(), causing the success debug log to be skipped when setting a 64G port speed. --
--- Patch [45]: [PATCH v6 45/56] scsi: qla2xxx: Fix 64G link speed reporting in get_data_rate --- commit 052c747978461ea82dcccd377a664fbb8431d087
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Fix 64G link speed reporting in get_data_rate
qla2x00_get_data_rate() skips updating ha->link_data_rate when the firmware returns mcp->mb[1] == 0x7. This updates the check to allow 0x07 on 64G-capable adapters while keeping the legacy filter for older ones.
drivers/scsi/qla2xxx/qla_mbx.c qla2x00_get_data_rate(scsi_qla_host_t *vha) · line 5789
Quoted 11 lines
drivers/scsi/qla2xxx/qla_mbx.c +1
-1@@ -5785,10 +5785,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 ];
[Severity: Low]
Since the legacy filter was updated here to allow 0x7 for 64G-capable adapters, should the same check be updated in qla2x00_set_data_rate()?
It looks like qla2x00_set_data_rate() still retains the legacy check:
drivers/scsi/qla2xxx/qla_mbx.c:qla2x00_set_data_rate() {
...
} else {
if (mcp->mb[1] != 0x7)
ql_dbg(ql_dbg_mbx, vha, 0x1179,
"Speed set:0x%x\n", mcp->mb[1]);
...
}Will this skip the success debug log when a 64G speed is successfully applied on a 64G-capable adapter?
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=45
Nilesh Javali
maintainerPATCH v6 46/56 scsi: qla2xxx: edif: Fix NULL pointer deref in RX SA delete check
In reply to Nilesh Javaliqla_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.
--- drivers/scsi/qla2xxx/qla_edif.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/scsi/qla2xxx/qla_edif.c +3 -0
@@ -3540,6 +3540,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 */
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 47/56 scsi: qla2xxx: Fix Name Server logout detection on FWI2 adapters
In reply to Nilesh JavaliIn 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.
--- drivers/scsi/qla2xxx/qla_gs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_gs.c +2 -2
@@ -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) ==
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 48/56 scsi: qla2xxx: Bound VP index against VP_CTRL IOCB bitmap size
In reply to Nilesh JavaliThe 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.
--- drivers/scsi/qla2xxx/qla_iocb.c | 6 ++++++ drivers/scsi/qla2xxx/qla_mid.c | 8 ++++++++ 2 files changed, 14 insertions(+)
drivers/scsi/qla2xxx/qla_iocb.c +6 -0
@@ -4126,6 +4126,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; }
drivers/scsi/qla2xxx/qla_mid.c +8 -0
@@ -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)
Signature · 1 line
2.47.3
Nilesh Javali
maintainerPATCH v6 49/56 scsi: qla2xxx: Check entry_status in qla24xx_modify_vp_config()
In reply to Nilesh JavaliThe 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.
--- drivers/scsi/qla2xxx/qla_mbx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_mbx.c +2 -2
@@ -4401,10 +4401,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,
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 49/56] scsi: qla2xxx: Check entry_status in qla24xx_modify_vp_config()
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing IOCB entry_status checks cause firmware rejections to be incorrectly treated as success. --
--- Patch [49]: [PATCH v6 49/56] scsi: qla2xxx: Check entry_status in qla24xx_modify_vp_config() --- commit 2e991988fb5984a6e00b391f35371b9211fc9e9a
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Check entry_status in qla24xx_modify_vp_config()
This commit fixes a bug in qla24xx_modify_vp_config() where the IOCB completion handler checked comp_status instead of entry_status. This prevented early firmware rejections from being properly detected.
Quoted 5 lines
drivers/scsi/qla2xxx/qla_mbx.c +0
-0@@ -4401,10 +4401,10 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)if (rval !=QLA_SUCCESS ) {
drivers/scsi/qla2xxx/qla_mbx.c qla24xx_modify_vp_config(scsi_qla_host_t *vha) · line 4409
Quoted 10 lines
drivers/scsi/qla2xxx/qla_mbx.c +2
-2ql_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 )) {
[Severity: High]
This isn't a bug introduced by this patch, but since you are fixing the missing entry_status check here, do we have similar vulnerabilities in other IOCB handlers across the driver?
Looking at other parts of the driver, several functions appear to make the same mistake of ignoring entry_status when an IOCB is rejected early.
For example, in qla84xx_verify_chip(), it only checks comp_status:
drivers/scsi/qla2xxx/qla_mbx.c:qla84xx_verify_chip() {
...
status[0] = le16_to_cpu(mn->p.rsp.comp_status);
status[1] = status[0] == CS_VCS_CHIP_FAILURE ?
le16_to_cpu(mn->p.rsp.failure_code) : 0;
...
if (status[0] != CS_COMPLETE) {
...
}Could this treat a rejected verify chip IOCB as a success if entry_status is set but comp_status remains zero?
Similarly, the BSG handlers qla84xx_updatefw() and qla84xx_mgmt_cmd() in drivers/scsi/qla2xxx/qla_bsg.c only check the mailbox command return status (rval) but ignore both entry_status and comp_status entirely.
Do these need to be updated to prevent returning DID_OK to userspace if the firmware update fails, or copying zeroed memory into the user's BSG reply payload?
Finally, in the ELS/ABTS paths, qla24xx_process_abts() in qla_isr.c and qla24xx_process_purex_rdp() in qla_os.c both check rsp_els->comp_status but completely ignore entry_status.
Could a rejected exchange termination be silently treated as successful here, leaving active exchanges in the firmware and potentially causing resource exhaustion?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=49
Nilesh Javali
maintainerPATCH v6 50/56 scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition()
In reply to Nilesh JavaliIn 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.
--- drivers/scsi/qla2xxx/qla_mbx.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/scsi/qla2xxx/qla_mbx.c +3 -0
@@ -4267,6 +4267,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 ; } }
@@ -4284,6 +4285,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);
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 50/56] scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition()
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
New issues:
- [High] Missing memory barrier before atomic_dec(&vp->vref_count) allows compiler/CPU reordering, reopening the use-after-free window.
Pre-existing issues:
- [High] Missing lock serialization on host_map btree in qla_update_host_map().
- [High] Unchecked VPORT_DELETE state in qla24xx_report_id_acquisition() allows a dying vport to be re-inserted into the host map btree.
- [High] Unprotected list traversal and access of vp_fcports in qla24xx_report_id_acquisition (Format 2 path) can lead to Use-After-Free.
- [High] Pre-existing list_for_each_entry_safe iteration across lock drops allows the cached next element to be freed. --
--- Patch [50]: [PATCH v6 50/56] scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition() --- commit 63a71c77c454d2559780ee0faf9f716b8a83c5f1
Author: Nilesh Javali <[email protected]>
Subject: scsi: qla2xxx: Hold vport reference in qla24xx_report_id_acquisition()
This commit fixes a use-after-free window in the format 1 path by taking a vport reference under the vport_slock during id acquisition. The lock is held while searching the list, and the reference ensures the vport remains valid during subsequent lockless setup.
drivers/scsi/qla2xxx/qla_mbx.c qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt) · line 4270
Quoted 9 lines
drivers/scsi/qla2xxx/qla_mbx.c +1
-0@@ -4267,6 +4267,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 whether the vport is actively being deleted?
If a concurrent thread removes the vport from the host map and sets the deletion state, could this loop erroneously take a reference on the dying vport and re-insert it into the host map below, creating a dangling pointer once the reference is dropped?
drivers/scsi/qla2xxx/qla_mbx.c qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt) · line 4290
Quoted 10 lines
drivers/scsi/qla2xxx/qla_mbx.c +0
-0break ; } }@@ -4284,6 +4285,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt)spin_unlock_irqrestore (&ha->vport_slock, flags);if (!found)return ;qla_update_host_map (vp, id);
[Severity: High]
This isn't a bug introduced by this patch, but does dropping the vport_slock leave qla_update_host_map() unprotected?
The btree functions are used locklessly in this operation. If another thread modifies the host map concurrently, can this result in data races and btree corruption?
drivers/scsi/qla2xxx/qla_mbx.c qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt) · line 4289
Quoted 10 lines
drivers/scsi/qla2xxx/qla_mbx.c +2
-0/* * Cannot configure here as we are still sitting on the * response queue. Handle it in dpc context. */ 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]
Can this regression allow the compiler or CPU to reorder the set_bit() operations?
Since void-returning atomic operations like atomic_dec() and set_bit() do not imply memory barriers, could the CPU reorder the memory stores to become visible after the reference count is decremented?
If a concurrent thread polls the reference count, observes it drop to zero, unlinks, and frees the vport, would the delayed set_bit() stores corrupt the freed memory?
drivers/scsi/qla2xxx/qla_mbx.c qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt) · line 4291
Quoted 2 lines
drivers/scsi/qla2xxx/qla_mbx.c +0
-0}set_bit (VP_DPC_NEEDED , &vha->dpc_flags);
[ ... ]
[Severity: High]
This is a pre-existing issue, but is the vp_fcports list traversed safely in the Format 2 path of qla24xx_report_id_acquisition()?
drivers/scsi/qla2xxx/qla_mbx.c:qla24xx_report_id_acquisition() {
...
} else if (rptid_entry->format == 2) {
...
list_for_each_entry(fcport, &vha->vp_fcports, list) {
fcport->scan_state = QLA_FCPORT_SCAN;
fcport->n2n_flag = 0;
}
...
}Unlike the Format 1 path, this traversal appears to happen without holding the session lock. If a concurrent session deletion unlinks and frees the fcport elements during this loop, could this lead to list corruption and a use-after-free?
[Severity: High]
This is also a pre-existing issue, but does list_for_each_entry_safe() across a lock drop open a window for the cached next element to be freed?
drivers/scsi/qla2xxx/qla_mid.c:qla2x00_do_dpc_all_vps() {
...
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);
qla2x00_do_dpc_vp(vp);
spin_lock_irqsave(&ha->vport_slock, flags);
atomic_dec(&vp->vref_count);
}
}
...
}Because the macro caches the next element (tvp) before dropping the lock, could a concurrent removal free tvp while the lock is dropped, causing a use-after-free when the loop advances?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=50
Nilesh Javali
maintainerPATCH v6 51/56 scsi: qla2xxx: Initialize NVMe abort_work once at submission
In reply to Nilesh Javaliqla_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.
--- drivers/scsi/qla2xxx/qla_nvme.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_nvme.c +2 -2
@@ -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 ;
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 51/56] scsi: qla2xxx: Initialize NVMe abort_work once at submission
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
New issues:
- [Critical] The patch moves INIT_WORK to the command submission paths but fails to order it safely against the publication of priv->sp, causing a NULL pointer dereference.
- [High] Calling qla_nvme_fcp_abort or qla_nvme_ls_abort multiple times for the same command leaks its kref and permanently hangs the request.
Pre-existing issues:
- [Critical] The command state (priv->sp) is exposed to concurrent abort handlers before the spinlock (priv->cmd_lock) is initialized, leading to spinlock corruption.
- [Critical] In the error paths of command submission, priv->sp is cleared without holding cmd_lock, and the command structure is freed directly, causing a Use-After-Free.
- [High] A race condition allows qla_nvme_fcp_abort to spuriously abort a completely different, newly submitted command due to tag reuse (ABA problem). --
--- Patch [51]: [PATCH v6 51/56] scsi: qla2xxx: Initialize NVMe abort_work once at submission --- commit 9a9f1f14cd9974710e9176cf206ade9b1d04e0e9
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Initialize NVMe abort_work once at submission
This patch moves the initialization of priv->abort_work to the command submission path to avoid corrupting the workqueue list if an abort is issued more than once for the same command.
drivers/scsi/qla2xxx/qla_nvme.c static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport, · line 467
Quoted 11 lines
drivers/scsi/qla2xxx/qla_nvme.c +0
-1@@ -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]
If the transport layer calls the abort functions multiple times for the same command, is there a kref leak here?
Earlier in this function, we unconditionally increment the reference count via kref_get_unless_zero(&priv->sp->cmd_kref).
Since the work item is no longer re-initialized, schedule_work() will return false and do nothing if the work is already pending. However, the return value is ignored and the extra kref taken is never dropped.
Since the work function qla_nvme_abort_work() only executes once and drops a single kref, will this permanently hang the NVMe core's I/O queue by preventing the kref from ever reaching zero?
[ ... ]
drivers/scsi/qla2xxx/qla_nvme.c static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, · line 505
Quoted 7 lines
drivers/scsi/qla2xxx/qla_nvme.c +1
-0@@ -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;
[Severity: Critical]
Could this sequence cause a panic due to an uninitialized work item?
We publish the command state with priv->sp = sp explicitly before INIT_WORK() executes. Because the transport allocates the private data with kzalloc(), the work struct's function pointer is initially NULL.
If a concurrent error recovery thread calls qla_nvme_ls_abort() while qla_nvme_ls_req() is executing, it can observe priv->sp != NULL and call schedule_work(&priv->abort_work).
Will this queue a work item with a NULL function pointer, causing a kernel panic when the worker thread executes it?
[Severity: Critical]
This is a pre-existing issue, but does initializing the spinlock after publishing priv->sp lead to lock corruption?
Similar to the work item, priv->sp is exposed to concurrent abort handlers before spin_lock_init(&priv->cmd_lock) is called. A concurrent abort from nvme_fc_abort_lsops can see priv->sp != NULL and successfully acquire the 0-initialized lock.
If the submission thread then unconditionally resets the lock internals back to 0 while the abort handler is inside its critical section, will it cause memory corruption or lockdep panics when the abort handler tries to unlock it?
[Severity: Critical]
This is a pre-existing issue, but can the error path further down in this function cause a use-after-free if an abort runs concurrently?
If hardware submission fails, the error path in qla_nvme_ls_req() does this:
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS) {
...
sp->priv = NULL;
priv->sp = NULL;
qla2x00_rel_sp(sp);
return rval;
}It sets priv->sp = NULL without acquiring priv->cmd_lock, bypasses kref_put(), and immediately frees the command structure via qla2x00_rel_sp().
If a concurrent abort handler has already checked priv->sp != NULL and incremented the kref inside qla_nvme_ls_abort(), it is left holding a reference to freed memory. When the queued abort_work runs, won't it invoke abort logic on the freed command structure?
[ ... ]
drivers/scsi/qla2xxx/qla_nvme.c static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport, · line 549
Quoted 7 lines
drivers/scsi/qla2xxx/qla_nvme.c +0
-1@@ -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]
This is a pre-existing issue, but is qla_nvme_fcp_abort() vulnerable to a tag reuse race condition?
In the NVMe FC core, __nvme_fc_abort_op() initiates an abort without synchronizing with the I/O completion path. If a hardware completion interrupt fires and completes the request, the block layer can free and immediately reuse the same tag (and thus the same fd->private memory) for a completely new command.
When qla_nvme_fcp_abort() runs and acquires priv->cmd_lock:
static void qla_nvme_fcp_abort(...)
{
...
spin_lock_irqsave(&priv->cmd_lock, flags);it will see the new priv->sp. Does this cause a spurious abort of the newly submitted, innocent command?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=51
Nilesh Javali
maintainerPATCH v6 52/56 scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject
In reply to Nilesh Javaliqla_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.
--- drivers/scsi/qla2xxx/qla_nvme.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/scsi/qla2xxx/qla_nvme.c +10 -0
@@ -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); }
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 52/56] scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [Critical] This problem wasn't introduced by this patch, but the error path of qla_nvme_xmt_ls_rsp() frees 'uctx' without removing it from the 'fcport->unsol_ctx_head' list, causing a Use-After-Free list corruption.
- [Critical] This problem wasn't introduced by this patch, but concurrent lockless accesses to the doubly-linked list 'fcport->unsol_ctx_head' cause data races and list corruption. --
--- Patch [52]: [PATCH v6 52/56] scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject --- commit 26608c7972504e04bce429e36cbbdc786b32af3b
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Hold qpair lock when sending NVMe LS reject
This commit fixes an issue where qla_nvme_ls_reject_iocb() is called without holding the hardware lock in error paths and the DPC context. It takes the qp_lock_ptr lock around the two unlocked callers to prevent concurrent I/O submission from corrupting the ring producer state.
Quoted 12 lines
drivers/scsi/qla2xxx/qla_nvme.c +1
-0@@ -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;
[ ... ]
drivers/scsi/qla2xxx/qla_nvme.c static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport, · line 447
Quoted 8 lines
drivers/scsi/qla2xxx/qla_nvme.c +2
-0@@ -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);
[Severity: Critical]
This isn't a bug introduced by this patch, but on the error path of qla_nvme_xmt_ls_rsp(), does freeing uctx without removing it from the fcport->unsol_ctx_head list leave a dangling pointer?
When an unsolicited request arrives, uctx is allocated and added to the unsol_ctx_head list. If this error path is taken, kfree(uctx) runs but misses the list_del(&uctx->elem) step, which could corrupt the list and lead to a use-after-free when the next unsolicited request arrives and calls list_add_tail().
Quoted 2 lines
drivers/scsi/qla2xxx/qla_nvme.c +0
-0return rval; }
[ ... ]
Quoted 9 lines
drivers/scsi/qla2xxx/qla_nvme.c +1
-0@@ -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 ))
drivers/scsi/qla2xxx/qla_nvme.c qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item) · line 1325
Quoted 7 lines
drivers/scsi/qla2xxx/qla_nvme.c +2
-0@@ -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: Critical]
This is a pre-existing issue, but is it safe to call list_del(&uctx->elem) locklessly here?
It looks like list_add_tail() in qla2xxx_process_purls_iocb() modifies this shared fcport->unsol_ctx_head list, and list_del() is also called locklessly in qla_nvme_release_lsrsp_cmd_kref().
Could concurrent unsolicited LS requests being processed by the DPC thread and workqueues race on this doubly-linked list, causing list corruption?
Quoted 2 lines
drivers/scsi/qla2xxx/qla_nvme.c +0
-0kfree (uctx); }
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=52
Nilesh Javali
maintainerPATCH v6 53/56 scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak
In reply to Nilesh Javaliqla2x00_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().
--- drivers/scsi/qla2xxx/qla_bsg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/qla2xxx/qla_bsg.c +1 -1
@@ -2806,7 +2806,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" );
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 53/56] scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Multiple BSG handlers use uninitialized stack buffers for request/reply structures, causing kernel memory leaks, arbitrary hardware writes, and severe buffer overflows when users provide a short payload.
- [High] Modifying a DMA buffer with memset() after it has been mapped for DMA_FROM_DEVICE violates DMA ownership rules and causes cache coherency data corruption.
- [High] DMA mapping a misaligned buffer inside a __packed struct risks cache line sharing corruption and hardware DMA faults.
- [Medium] Unvalidated reply_payload_rcv_len can trigger a kernel WARN_ON in the block layer.
--
--- Patch [53]: [PATCH v6 53/56] scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak --- commit b2d4e000f67ba62a27fd752863bb10d9c1b2ea09
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Zero dport diagnostics buffer to avoid info leak
This patch changes the allocation of the qla_dport_diag response buffer from kmalloc_obj() to kzalloc_obj() in qla2x00_do_dport_diagnostics(). The change ensures the buffer is zero-initialized, preventing kernel heap contents from leaking to user space when copying the structure back.
drivers/scsi/qla2xxx/qla_bsg.c qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job) · line 2809
Quoted 10 lines
drivers/scsi/qla2xxx/qla_bsg.c +1
-1@@ -2806,7 +2806,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 is a pre-existing issue, but are we risking cache line sharing corruption and hardware DMA faults by DMA mapping the misaligned buffer inside this structure?
Looking at the structure definition:
drivers/scsi/qla2xxx/qla_bsg.h:struct qla_dport_diag {
uint16_t options;
uint32_t buf[16];
uint8_t unused[62];
} __packed;Because the struct is __packed, the buf array is forced to an unaligned 2-byte offset.
When buf is subsequently mapped for DMA in qla26xx_dport_diagnostics():
drivers/scsi/qla2xxx/qla_mbx.c:qla26xx_dport_diagnostics() {
...
dd_dma = dma_map_single(&vha->hw->pdev->dev, dd_buf, size,
DMA_FROM_DEVICE);
...
}Could unmapping or syncing this misaligned buffer on non-coherent architectures invalidate the entire cache line, thereby corrupting the adjacent options and unused fields? Furthermore, could providing a 2-byte aligned address to the HBA cause hardware DMA faults?
[Severity: High]
This isn't a bug introduced by this patch, but does the memset() in the diagnostics functions violate DMA ownership rules?
In qla26xx_dport_diagnostics():
drivers/scsi/qla2xxx/qla_mbx.c:qla26xx_dport_diagnostics() {
...
dd_dma = dma_map_single(&vha->hw->pdev->dev, dd_buf, size,
DMA_FROM_DEVICE);
...
memset(dd_buf, 0, size);
...
}A similar pattern exists in qla26xx_dport_diagnostics_v2().
The DMA API forbids the CPU from modifying a buffer while it is mapped for device DMA. On non-cache-coherent architectures, does the CPU write bring the cache line into the CPU cache and mark it as dirty, meaning that if it is evicted to RAM after the device completes its DMA writes, the CPU's zeroes might silently overwrite the device's diagnostic data?
Since the allocation in qla2x00_do_dport_diagnostics() is now using kzalloc_obj(), is this memset() still necessary, or can it be removed?
[Severity: Medium]
This is a pre-existing issue, but does setting the reply length unconditionally risk triggering a block layer WARN_ON if the user provides a short payload?
Later in qla2x00_do_dport_diagnostics():
drivers/scsi/qla2xxx/qla_bsg.c:qla2x00_do_dport_diagnostics() {
...
bsg_reply->reply_payload_rcv_len = sizeof(*dd);
...
}If a user submits a BSG job with a reply payload smaller than sizeof(*dd), will reply_payload_rcv_len exceed the allocated response length, triggering a WARN_ON(job->reply_payload_rcv_len > rsp_len) in the block layer?
[Severity: Critical]
This is a pre-existing issue, but do other BSG handlers have similar uninitialized stack buffer vulnerabilities?
Several handlers allocate structures on the stack without initializing them, and sg_copy_to_buffer() only populates the bytes provided by the user payload. If a user provides a short payload, variables might remain uninitialized stack garbage.
For example, in qla2x00_write_i2c():
drivers/scsi/qla2xxx/qla_bsg.c:qla2x00_write_i2c() {
...
memcpy(sfp, i2c->buffer, i2c->length);
...
}Could an uninitialized i2c->length cause an out-of-bounds read from the stack and an out-of-bounds write to the DMA pool allocation?
Similar issues appear to exist in:
- qla2x00_read_i2c() (memcpy overflowing the fixed-size stack array bsg)
- qla2x00_update_fru_versions() (uninitialized list->count dictating loop iterations)
- qla2x00_read_fru_status() (uninitialized stack buffer copied to user space)
- qla_edif_app_start() (uninitialized pad and reserved fields copied to user space)
Could a user issuing a BSG job with a truncated request payload trigger these out-of-bounds accesses or memory leaks?
Quoted 3 lines
drivers/scsi/qla2xxx/qla_bsg.c +0
-0if (!dd) {ql_log (ql_log_warn, vha,0x70db ,"Failed to allocate memory for dport.\n" );
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=53
Nilesh Javali
maintainerPATCH v6 54/56 scsi: qla2xxx: Fix BSG job leak on validate flash image error path
In reply to Nilesh Javaliqla28xx_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.
--- drivers/scsi/qla2xxx/qla_bsg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/scsi/qla2xxx/qla_bsg.c +2 -3
@@ -3796,9 +3796,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 ; }
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 54/56] scsi: qla2xxx: Fix BSG job leak on validate flash image error path
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing bounds check on request_len allows out-of-bounds heap read when accessing the variable-length vendor_cmd array from user-supplied BSG requests. --
--- Patch [54]: [PATCH v6 54/56] scsi: qla2xxx: Fix BSG job leak on validate flash image error path --- commit 9de1723bd73d3b6f0fef869a49941dbe6b59c23b
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Fix BSG job leak on validate flash image error path
qla28xx_validate_flash_image() returns QLA_SUCCESS (0) unconditionally, telling the FC BSG transport that the driver owns and will complete the request. But bsg_job_done() was guarded by "if (!rval)", so on the error path neither the driver nor the transport completes the job, leaking resources. This commit removes the guard and always calls bsg_job_done().
drivers/scsi/qla2xxx/qla_bsg.c static int qla28xx_validate_flash_image(struct bsg_job *bsg_job) · line 3800
Quoted 13 lines
drivers/scsi/qla2xxx/qla_bsg.c +2
-3@@ -3796,9 +3796,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);
[Severity: High]
This is a pre-existing issue, but does this BSG ioctl path allow an out-of-bounds heap read if userspace provides a maliciously small request_len?
When a process with CAP_SYS_RAWIO issues a BSG ioctl specifying FC_BSG_HST_VENDOR with a small request_len (e.g., 4 bytes), the transport layer expands cmdlen but never re-validates job->request_len:
drivers/scsi/scsi_transport_fc.c:fc_bsg_host_dispatch() {
...
cmdlen += sizeof(struct fc_bsg_host_vendor);
if ((shost->hostt->vendor_id == 0L) ||
(bsg_request->rqst_data.h_vendor.vendor_id !=
shost->hostt->vendor_id)) {
...
}This leads to an immediate out-of-bounds read of vendor_id. Later in the qla2xxx driver, the handler unconditionally reads vendor_cmd[0] before verifying the message code:
drivers/scsi/qla2xxx/qla_bsg.c:qla24xx_bsg_request() {
...
if (bsg_request->rqst_data.h_vendor.vendor_cmd[0] ==
QL_VND_MANAGE_HOST_PORT ||
bsg_request->rqst_data.h_vendor.vendor_cmd[0] ==
QL_VND_GET_HOST_STATS)
...
}And specifically for the validate flash image command, it blindly reads vendor_cmd[1] without verifying the request buffer is large enough:
drivers/scsi/qla2xxx/qla_bsg.c:qla28xx_do_validate_flash_image() {
...
img_idx = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
...
}Should there be a bounds check on request_len in fc_bsg_host_dispatch() or the driver to prevent this?
Quoted 3 lines
drivers/scsi/qla2xxx/qla_bsg.c +0
-0return QLA_SUCCESS ; }
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=54
Nilesh Javali
maintainerPATCH v6 55/56 scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions()
In reply to Nilesh Javaliqla2x00_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.
--- drivers/scsi/qla2xxx/qla_bsg.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/scsi/qla2xxx/qla_bsg.c +7 -0
@@ -1991,6 +1991,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,
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 55/56] scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions()
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] Heap and stack buffer overflows due to unvalidated length in I2C BSG handlers.
- [Medium] Missing payload length check against user input in FRU update/read/write functions.
- [Medium] Uninitialized heap memory leak to device in SFP write operations.
--
--- Patch [55]: [PATCH v6 55/56] scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions() --- commit cda96c9f52838a031ce5bc0e9a6594ece5956c88
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Bound image count in qla2x00_update_fru_versions()
This commit rejects BSG requests in qla2x00_update_fru_versions() where the declared count does not fit in the 256-byte stack buffer. This prevents a stack out-of-bounds read that could be sent to the device.
Quoted 5 lines
drivers/scsi/qla2xxx/qla_bsg.c +0
-0
drivers/scsi/qla2xxx/qla_bsg.c qla2x00_update_fru_versions(struct bsg_job *bsg_job) · line 2000
Quoted 10 lines
drivers/scsi/qla2xxx/qla_bsg.c +7
-0@@ -1991,6 +1991,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; + } +
[Severity: Medium]
This is a pre-existing issue, but does this function also need to validate the actual request payload length?
If a local user issues a request with a payload smaller than the required struct sizes, sg_copy_to_buffer() only copies the provided bytes, leaving the rest of the stack buffer bsg uninitialized:
drivers/scsi/qla2xxx/qla_bsg.c:qla2x00_update_fru_versions() {
...
sg_copy_to_buffer(bsg_job->request_payload.sg_list,
bsg_job->request_payload.sg_cnt, list, sizeof(bsg));
...
}The code then reads from this uninitialized memory (e.g. image->field_info) and passes it to mailbox commands, leaking kernel stack memory to the hardware device.
Can similar payload length validation issues occur in qla2x00_read_fru_status() and qla2x00_write_fru_status() where sg_copy_to_buffer() is also used?
drivers/scsi/qla2xxx/qla_bsg.c qla2x00_update_fru_versions(struct bsg_job *bsg_job) · line 2002
Quoted 2 lines
drivers/scsi/qla2xxx/qla_bsg.c +0
-0while (count--) {memcpy (sfp, &image->field_info,sizeof (image->field_info));
[Severity: Medium]
This isn't a bug introduced by this patch, but can this lead to an uninitialized heap memory leak?
Earlier in qla2x00_update_fru_versions(), sfp is allocated via dma_pool_alloc() from a 256-byte pool without zeroing it. Only 36 bytes of user data are copied into sfp.
If the user sets image->field_address.option to include BIT_0 and sets the first byte of field_info to 255, this length is overridden in qla2x00_write_sfp():
drivers/scsi/qla2xxx/qla_mbx.c:qla2x00_write_sfp() {
...
if (opt & BIT_0)
len = *sfp;
...
}Will the hardware then read 255 bytes from sfp, leaking 219 bytes of uninitialized kernel heap memory to the device?
drivers/scsi/qla2xxx/qla_bsg.c qla2x00_update_fru_versions(struct bsg_job *bsg_job) · line 2003
Quoted 1 line
drivers/scsi/qla2xxx/qla_bsg.c +0
-0rval = qla2x00_write_sfp(vha, sfp_dma, sfp,
[ ... ]
[Severity: High]
This is a pre-existing issue, but do the I2C BSG handlers have unbounded length checks leading to overflows?
In qla2x00_write_i2c(), an unbounded user-controlled i2c->length is used in a memcpy:
drivers/scsi/qla2xxx/qla_bsg.c:qla2x00_write_i2c() {
...
memcpy(sfp, i2c->buffer, i2c->length);
...
}If i2c->length is set to a large value (up to 65535), can this overflow the 256-byte heap allocation sfp and read out-of-bounds from the kernel stack?
Similarly, in qla2x00_read_i2c(), does passing an unvalidated length to memcpy() overflow the 256-byte stack array:
drivers/scsi/qla2xxx/qla_bsg.c:qla2x00_read_i2c() {
...
memcpy(i2c->buffer, sfp, i2c->length);
...
}Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=55
Nilesh Javali
maintainerPATCH v6 56/56 scsi: qla2xxx: Update version to 12.00.00.2607b1
In reply to Nilesh Javali--- drivers/scsi/qla2xxx/qla_version.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/scsi/qla2xxx/qla_version.h +5 -5
@@ -6,9 +6,9 @@/* * Driver version */ -#define QLA2XXX_VERSION "10.02.10.100-k" +#define QLA2XXX_VERSION "12.00.00.2607b1" -#define QLA_DRIVER_MAJOR_VER 10 -#define QLA_DRIVER_MINOR_VER 02 -#define QLA_DRIVER_PATCH_VER 10 -#define QLA_DRIVER_BETA_VER 100 +#define QLA_DRIVER_MAJOR_VER 12 +#define QLA_DRIVER_MINOR_VER 00 +#define QLA_DRIVER_PATCH_VER 00 +#define QLA_DRIVER_BETA_VER 2607
Signature · 1 line
2.47.3
[email protected]
AI reviewRe: [PATCH v6 56/56] scsi: qla2xxx: Update version to 12.00.00.2607b1
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] The new driver version string has an odd length, causing an infinite loop condition and…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The new driver version string has an odd length, causing an infinite loop condition and out-of-bounds read in qla82xx_set_driver_version.
- [Medium] The new QLA_DRIVER_BETA_VER and QLA2XXX_VERSION values exceed the 8-bit limits assumed by the minidump and firmware dump metadata generators, leading to corrupted version reporting. --
--- Patch [56]: [PATCH v6 56/56] scsi: qla2xxx: Update version to 12.00.00.2607b1 --- commit 7e58cb94f7bd9df990cb9116b395dd17502493c0
Author: Nilesh Javali <[email protected]>
scsi: qla2xxx: Update version to 12.00.00.2607b1
This commit updates the QLA2XXX driver version string and the corresponding major, minor, patch, and beta version macros.
drivers/scsi/qla2xxx/qla_version.h line 9
Quoted 10 lines
drivers/scsi/qla2xxx/qla_version.h +1
-1@@ -6,9 +6,9 @@/* * Driver version */ -#define QLA2XXX_VERSION "10.02.10.100-k" +#define QLA2XXX_VERSION "12.00.00.2607b1"
[Severity: High]
Does changing this version string to an odd length (15 bytes) cause a loop overrun and out-of-bounds read in qla82xx_set_driver_version()?
Looking at drivers/scsi/qla2xxx/qla_mbx.c:qla82xx_set_driver_version():
for (i = 4; i < 16 && len; i++, str++, len -= 2) {
mcp->mb[i] = le16_to_cpup(str);
mcp->out_mb |= 1<<i;
}Since len is initialized to the string length, an odd length causes len to step from 1 to -1. The loop condition && len will remain true when it goes negative, causing the loop to continue and read past the end of the string literal.
drivers/scsi/qla2xxx/qla_version.h line 14
Quoted 9 lines
drivers/scsi/qla2xxx/qla_version.h +4
-4-#define QLA_DRIVER_MAJOR_VER 10 -#define QLA_DRIVER_MINOR_VER 02 -#define QLA_DRIVER_PATCH_VER 10 -#define QLA_DRIVER_BETA_VER 100 +#define QLA_DRIVER_MAJOR_VER 12 +#define QLA_DRIVER_MINOR_VER 00 +#define QLA_DRIVER_PATCH_VER 00 +#define QLA_DRIVER_BETA_VER 2607
[Severity: Medium]
Does this new beta version value exceed 8-bit limits and corrupt the driver version metadata in diagnostic dumps?
In drivers/scsi/qla2xxx/qla_nx.c:qla82xx_md_collect(), the version components are packed into a 32-bit integer:
tmplt_hdr->driver_info[1] = (QLA_DRIVER_MAJOR_VER << 24) | (QLA_DRIVER_MINOR_VER << 16) | (QLA_DRIVER_PATCH_VER << 8) | QLA_DRIVER_BETA_VER;
Since 2607 (0x0A2F) is larger than 8 bits, the bitwise OR will overflow and overwrite the patch version byte.
Additionally, in drivers/scsi/qla2xxx/qla_tmpl.c:qla27xx_driver_info(), the %hhu format specifier is used to parse the string version:
WARN_ON_ONCE(sscanf(qla2x00_version_str, "%hhu.%hhu.%hhu.%hhu", v + 0, v + 1, v + 2, v + 3) != 4);
This will silently truncate the beta version 2607 to 47.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=56
Martin K. Petersen
AppliedNilesh,
Quoted 6 lines
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.
Applied to 7.3/scsi-staging, thanks!
Signature · 1 line
Martin K. Petersen