From 0bdf7d7ee75da076eabcfa9b5fadd0ed0524df43 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 27 Apr 2026 09:00:49 +0200 Subject: [PATCH 01/56] scsi: ufs: qcom: Unify user-visible "Qualcomm" name Various names for Qualcomm as a company are used in user-visible config options: QCOM, Qualcomm and Qualcomm Technologies. Switch to unified "Qualcomm" so it will be easier for users to identify the options when for example running menuconfig. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260427070048.18017-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig index 964ae70e7390..ff170c0b6da0 100644 --- a/drivers/ufs/host/Kconfig +++ b/drivers/ufs/host/Kconfig @@ -55,7 +55,7 @@ config SCSI_UFS_DWC_TC_PLATFORM If unsure, say N. config SCSI_UFS_QCOM - tristate "QCOM specific hooks to UFS controller platform driver" + tristate "Qualcomm specific hooks to UFS controller platform driver" depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM depends on GENERIC_MSI_IRQ depends on RESET_CONTROLLER From c7233b3d99db9760daf07c4e95daa9675c6c0cba Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 29 Apr 2026 17:15:37 +0200 Subject: [PATCH 02/56] scsi: advansys: Drop ISA_DMA_API remnants Support for ISA bus mastering was removed a few years ago, and the VLB mode does not use the ISA DMA API, so drop the dependency and the header inclusion. Fixes: 9b4c8eaa68d0 ("advansys: remove ISA support") Signed-off-by: Arnd Bergmann Reviewed-by: Johannes Thumshirn Link: https://patch.msgid.link/20260429151623.3899875-1-arnd@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/Kconfig | 1 - drivers/scsi/advansys.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index fc8e8b0bfa39..c3042393af23 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -474,7 +474,6 @@ config SCSI_ADVANSYS tristate "AdvanSys SCSI support" depends on SCSI depends on (ISA || EISA || PCI) && HAS_IOPORT - depends on ISA_DMA_API || !ISA help This is a driver for all SCSI host adapters manufactured by AdvanSys. It is documented in the kernel source in diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index fcf059bf41e8..5cdbf2bdb13d 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -36,7 +36,6 @@ #include #include -#include #include #include From 7787588db949a6caa7ca40bd6b67ecb75b68c932 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Sat, 25 Apr 2026 20:03:30 -0400 Subject: [PATCH 03/56] scsi: ncr53c8xx: Drop CONFIG_ prefix from Zalon-specific compiler defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kconfiglint reports: X001: CONFIG_NCR53C8XX_PREFETCH referenced in Makefile but not defined in any Kconfig X001: CONFIG_SCSI_NCR53C8XX_NO_WORD_TRANSFERS referenced in Makefile but not defined in any Kconfig The ncr53c8xx SCSI driver uses two preprocessor defines that carry the CONFIG_ prefix but are not defined in any Kconfig file: -DCONFIG_NCR53C8XX_PREFETCH -DCONFIG_SCSI_NCR53C8XX_NO_WORD_TRANSFERS These are hardcoded compiler flags in drivers/scsi/Makefile, passed only when CONFIG_SCSI_ZALON is enabled: ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \ := -DCONFIG_NCR53C8XX_PREFETCH -DSCSI_NCR_BIG_ENDIAN \ -DCONFIG_SCSI_NCR53C8XX_NO_WORD_TRANSFERS The source files ncr53c8xx.c and ncr53c8xx.h check these defines with #ifdef to enable script prefetching and disable 16-bit word transfers respectively — both specific to the PA-RISC Zalon SCSI controller's big-endian bus requirements. These defines have been present since the initial git import in commit 1da177e4c3f4 ("Linux-2.6.12-rc2"). They predate the modern Kconfig convention that CONFIG_ prefixed symbols should always originate from Kconfig. The third define on the same line, SCSI_NCR_BIG_ENDIAN, already correctly omits the CONFIG_ prefix. The CONFIG_ prefix is misleading: these are not user-configurable options and do not appear in any Kconfig menu. They are unconditionally enabled for all Zalon builds. Remove the CONFIG_ prefix from both symbols — renaming them to NCR53C8XX_PREFETCH and SCSI_NCR53C8XX_NO_WORD_TRANSFERS — to match the convention used by SCSI_NCR_BIG_ENDIAN on the same line and to avoid confusion with actual Kconfig-managed symbols. No functional change. Assisted-by: Claude:claude-opus-4-6 kconfiglint Signed-off-by: Sasha Levin Link: https://patch.msgid.link/20260426000330.56137-1-sashal@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/Makefile | 4 ++-- drivers/scsi/ncr53c8xx.c | 2 +- drivers/scsi/ncr53c8xx.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 16de3e41f94c..842c254bb226 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -177,8 +177,8 @@ sd_mod-$(CONFIG_BLK_DEV_ZONED) += sd_zbc.o sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \ - := -DCONFIG_NCR53C8XX_PREFETCH -DSCSI_NCR_BIG_ENDIAN \ - -DCONFIG_SCSI_NCR53C8XX_NO_WORD_TRANSFERS + := -DNCR53C8XX_PREFETCH -DSCSI_NCR_BIG_ENDIAN \ + -DSCSI_NCR53C8XX_NO_WORD_TRANSFERS CFLAGS_ncr53c8xx.o := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m) zalon7xx-objs := zalon.o ncr53c8xx.o diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 4a255aafed80..5369ca3fe4fd 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -1776,7 +1776,7 @@ struct ncb { ** return from the subroutine. */ -#ifdef CONFIG_NCR53C8XX_PREFETCH +#ifdef NCR53C8XX_PREFETCH #define PREFETCH_FLUSH_CNT 2 #define PREFETCH_FLUSH SCR_CALL, PADDRH (wait_dma), #else diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h index be38c902859e..2f6865ca1b87 100644 --- a/drivers/scsi/ncr53c8xx.h +++ b/drivers/scsi/ncr53c8xx.h @@ -397,7 +397,7 @@ #else -#ifdef CONFIG_SCSI_NCR53C8XX_NO_WORD_TRANSFERS +#ifdef SCSI_NCR53C8XX_NO_WORD_TRANSFERS /* Only 8 or 32 bit transfers allowed */ #define INW_OFF(o) (readb((char __iomem *)np->reg + ncr_offw(o)) << 8 | readb((char __iomem *)np->reg + ncr_offw(o) + 1)) #else @@ -405,7 +405,7 @@ #endif #define INL_OFF(o) readl_raw((char __iomem *)np->reg + (o)) -#ifdef CONFIG_SCSI_NCR53C8XX_NO_WORD_TRANSFERS +#ifdef SCSI_NCR53C8XX_NO_WORD_TRANSFERS /* Only 8 or 32 bit transfers allowed */ #define OUTW_OFF(o, val) do { writeb((char)((val) >> 8), (char __iomem *)np->reg + ncr_offw(o)); writeb((char)(val), (char __iomem *)np->reg + ncr_offw(o) + 1); } while (0) #else From c9ee94c7e2fb65a433b505d7bcf4c2b6ee81b86c Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 27 Apr 2026 09:31:14 +0800 Subject: [PATCH 04/56] scsi: ufs: dt-bindings: Add compatible for Nord UFS Host Controller Document UFS Host Controller on Qualcomm Nord SoC. Like the Eliza SoC, Nord has a multi-queue command (MCQ) register range in addition to the standard one, making both reg entries required. Reviewed-by: Krzysztof Kozlowski Reviewed-by: Manivannan Sadhasivam Signed-off-by: Shawn Guo Link: https://patch.msgid.link/20260427013115.231731-2-shengchao.guo@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml b/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml index f28641c6e68f..900d93b675cd 100644 --- a/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml +++ b/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml @@ -17,6 +17,7 @@ select: enum: - qcom,eliza-ufshc - qcom,kaanapali-ufshc + - qcom,nord-ufshc - qcom,sm8650-ufshc - qcom,sm8750-ufshc required: @@ -28,6 +29,7 @@ properties: - enum: - qcom,eliza-ufshc - qcom,kaanapali-ufshc + - qcom,nord-ufshc - qcom,sm8650-ufshc - qcom,sm8750-ufshc - const: qcom,ufshc @@ -74,6 +76,7 @@ allOf: contains: enum: - qcom,eliza-ufshc + - qcom,nord-ufshc then: properties: reg: From 7030e16247dc9fb044371141c513581067c8e574 Mon Sep 17 00:00:00 2001 From: Deepti Jaggi Date: Mon, 27 Apr 2026 09:31:15 +0800 Subject: [PATCH 05/56] scsi: ufs: dt-bindings: Add compatible for SA8797P UFS Host Controller SA8797P is the automotive variant of the Nord SoC. Like SA8255P, its platform firmware implements an SCMI server that manages UFS resources such as the PHY, clocks, regulators and resets via the SCMI power protocol. As a result, the OS-visible DT only describes the controller's MMIO, interrupt, IOMMU and power-domain interfaces, making SA8255P the appropriate fallback compatible. Signed-off-by: Deepti Jaggi Reviewed-by: Manivannan Sadhasivam Signed-off-by: Shawn Guo Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260427013115.231731-3-shengchao.guo@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- .../devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml b/Documentation/devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml index 75fae9f1eba7..db165a235cb6 100644 --- a/Documentation/devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml +++ b/Documentation/devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml @@ -11,7 +11,11 @@ maintainers: properties: compatible: - const: qcom,sa8255p-ufshc + oneOf: + - const: qcom,sa8255p-ufshc + - items: + - const: qcom,sa8797p-ufshc + - const: qcom,sa8255p-ufshc reg: maxItems: 1 From 45c9dee6d6531bf1d0e0dbf577fb59850e34f6d0 Mon Sep 17 00:00:00 2001 From: Sowon Na Date: Fri, 17 Apr 2026 17:44:50 +0530 Subject: [PATCH 06/56] scsi: ufs: exynos: dt-bindings: Add ExynosAutov920 compatible string Add samsung,exynosautov920-ufs compatible for ExynosAutov920 SoC. Acked-by: Krzysztof Kozlowski Signed-off-by: Sowon Na Signed-off-by: Alim Akhtar Reviewed-by: Alim Akhtar Link: https://patch.msgid.link/20260417121452.827054-3-alim.akhtar@samsung.com Signed-off-by: Martin K. Petersen --- Documentation/devicetree/bindings/ufs/samsung,exynos-ufs.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/ufs/samsung,exynos-ufs.yaml b/Documentation/devicetree/bindings/ufs/samsung,exynos-ufs.yaml index a7eb7ad85a94..710ce493f3b6 100644 --- a/Documentation/devicetree/bindings/ufs/samsung,exynos-ufs.yaml +++ b/Documentation/devicetree/bindings/ufs/samsung,exynos-ufs.yaml @@ -19,6 +19,7 @@ properties: - samsung,exynos7-ufs - samsung,exynosautov9-ufs - samsung,exynosautov9-ufs-vh + - samsung,exynosautov920-ufs - tesla,fsd-ufs reg: From 50349bd5d0ab6d6f7e106a6cb1cdbf2bcfb75e08 Mon Sep 17 00:00:00 2001 From: Sowon Na Date: Fri, 17 Apr 2026 17:44:51 +0530 Subject: [PATCH 07/56] scsi: ufs: exynos: Add support for ExynosAutov920 SoC Add a dedicated compatible and drv_data with associated hooks for ExynosAutov920 SoC. ExynosAutov920 has a different mask of UFS sharability from ExynosAutov9, so add related changes for the same. Signed-off-by: Sowon Na Signed-off-by: Alim Akhtar [Alim: fixed unintended changes, other fixes] Link: https://patch.msgid.link/20260417121452.827054-4-alim.akhtar@samsung.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-exynos.c | 110 ++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c index 77a6c8e44485..b2f65c465525 100644 --- a/drivers/ufs/host/ufs-exynos.c +++ b/drivers/ufs/host/ufs-exynos.c @@ -97,6 +97,10 @@ #define UFS_EXYNOSAUTO_RD_SHARABLE BIT(1) #define UFS_EXYNOSAUTO_SHARABLE (UFS_EXYNOSAUTO_WR_SHARABLE | \ UFS_EXYNOSAUTO_RD_SHARABLE) +#define UFS_EXYNOSAUTOV920_WR_SHARABLE BIT(3) +#define UFS_EXYNOSAUTOV920_RD_SHARABLE BIT(2) +#define UFS_EXYNOSAUTOV920_SHARABLE (UFS_EXYNOSAUTOV920_WR_SHARABLE |\ + UFS_EXYNOSAUTOV920_RD_SHARABLE) #define UFS_GS101_WR_SHARABLE BIT(1) #define UFS_GS101_RD_SHARABLE BIT(0) #define UFS_GS101_SHARABLE (UFS_GS101_WR_SHARABLE | \ @@ -417,6 +421,95 @@ static int exynos7_ufs_post_pwr_change(struct exynos_ufs *ufs, return 0; } +static int exynosautov920_ufs_pre_link(struct exynos_ufs *ufs) +{ + struct ufs_hba *hba = ufs->hba; + int i; + u32 tx_line_reset_period, rx_line_reset_period; + + rx_line_reset_period = (RX_LINE_RESET_TIME * ufs->mclk_rate) + / NSEC_PER_MSEC; + tx_line_reset_period = (TX_LINE_RESET_TIME * ufs->mclk_rate) + / NSEC_PER_MSEC; + + unipro_writel(ufs, 0x5f, 0x44); + + ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x40); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x202), 0x02); + + for_each_ufs_rx_lane(ufs, i) { + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD, i), + DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate)); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD_EN, i), 0x0); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE2, i), + (rx_line_reset_period >> 16) & 0xFF); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE1, i), + (rx_line_reset_period >> 8) & 0xFF); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE0, i), + (rx_line_reset_period) & 0xFF); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x2f, i), 0x69); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x84, i), 0x1); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x25, i), 0xf6); + } + + for_each_ufs_tx_lane(ufs, i) { + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD, i), + DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate)); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD_EN, i), + 0x02); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE2, i), + (tx_line_reset_period >> 16) & 0xFF); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE1, i), + (tx_line_reset_period >> 8) & 0xFF); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE0, i), + (tx_line_reset_period) & 0xFF); + + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x04, i), 0x1); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x7f, i), 0x0); + } + + ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x0); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0x0); + ufshcd_dme_set(hba, UIC_ARG_MIB(0xa011), 0x8000); + + return 0; +} + +static int exynosautov920_ufs_post_link(struct exynos_ufs *ufs) +{ + struct ufs_hba *hba = ufs->hba; + + ufshcd_dme_set(hba, UIC_ARG_MIB(0x9529), 0x1); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15a4), 0x3e8); + ufshcd_dme_set(hba, UIC_ARG_MIB(0x9529), 0x0); + + return 0; +} + +static int exynosautov920_ufs_pre_pwr_change(struct exynos_ufs *ufs, + struct ufs_pa_layer_attr *pwr) +{ + struct ufs_hba *hba = ufs->hba; + + ufshcd_dme_set(hba, UIC_ARG_MIB(0x15d4), 0x1); + + ufshcd_dme_set(hba, UIC_ARG_MIB(DL_FC0PROTTIMEOUTVAL), 8064); + ufshcd_dme_set(hba, UIC_ARG_MIB(DL_TC0REPLAYTIMEOUTVAL), 28224); + ufshcd_dme_set(hba, UIC_ARG_MIB(DL_AFC0REQTIMEOUTVAL), 20160); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA0), 12000); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA1), 32000); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA2), 16000); + + unipro_writel(ufs, 8064, UNIPRO_DME_POWERMODE_REQ_LOCALL2TIMER0); + unipro_writel(ufs, 28224, UNIPRO_DME_POWERMODE_REQ_LOCALL2TIMER1); + unipro_writel(ufs, 20160, UNIPRO_DME_POWERMODE_REQ_LOCALL2TIMER2); + unipro_writel(ufs, 12000, UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER0); + unipro_writel(ufs, 32000, UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER1); + unipro_writel(ufs, 16000, UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER2); + + return 0; +} + /* * exynos_ufs_auto_ctrl_hcc - HCI core clock control by h/w * Control should be disabled in the below cases @@ -2201,6 +2294,21 @@ static const struct exynos_ufs_drv_data gs101_ufs_drvs = { .suspend = gs101_ufs_suspend, }; +static const struct exynos_ufs_drv_data exynosautov920_ufs_drvs = { + .uic_attr = &exynos7_uic_attr, + .quirks = UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING, + .opts = EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL | + EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR | + EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX | + EXYNOS_UFS_OPT_TIMER_TICK_SELECT, + .iocc_mask = UFS_EXYNOSAUTOV920_SHARABLE, + .drv_init = exynosauto_ufs_drv_init, + .post_hce_enable = exynosauto_ufs_post_hce_enable, + .pre_link = exynosautov920_ufs_pre_link, + .post_link = exynosautov920_ufs_post_link, + .pre_pwr_change = exynosautov920_ufs_pre_pwr_change, +}; + static const struct of_device_id exynos_ufs_of_match[] = { { .compatible = "google,gs101-ufs", .data = &gs101_ufs_drvs }, @@ -2210,6 +2318,8 @@ static const struct of_device_id exynos_ufs_of_match[] = { .data = &exynosauto_ufs_drvs }, { .compatible = "samsung,exynosautov9-ufs-vh", .data = &exynosauto_ufs_vh_drvs }, + { .compatible = "samsung,exynosautov920-ufs", + .data = &exynosautov920_ufs_drvs }, { .compatible = "tesla,fsd-ufs", .data = &fsd_ufs_drvs }, {}, From f2cb7c01f48caffb38e12481949dea4f9beb65dc Mon Sep 17 00:00:00 2001 From: Can Guo Date: Fri, 24 Apr 2026 08:14:19 -0700 Subject: [PATCH 08/56] scsi: ufs: core: Introduce function ufshcd_query_attr_qword() Introduce a new generic function ufshcd_query_attr_qword() to handle quad-word (64-bit) UFS attribute operations. This consolidates the handling of 64-bit attributes which was previously scattered across multiple specialized functions. Reviewed-by: Peter Wang Signed-off-by: Can Guo Reviewed-by: Bean Huo Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260424151420.111675-2-can.guo@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-sysfs.c | 30 ++++++-- drivers/ufs/core/ufshcd-priv.h | 3 +- drivers/ufs/core/ufshcd.c | 126 +++++++++++++++++---------------- 3 files changed, 94 insertions(+), 65 deletions(-) diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index 99af3c73f1af..d9dc4cc3452e 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -594,8 +594,13 @@ static ssize_t device_lvl_exception_id_show(struct device *dev, u64 exception_id; int err; + if (hba->dev_info.wspecversion < 0x410) + return -EOPNOTSUPP; + ufshcd_rpm_get_sync(hba); - err = ufshcd_read_device_lvl_exception_id(hba, &exception_id); + err = ufshcd_query_attr_qword(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID, + 0, 0, &exception_id); ufshcd_rpm_put_sync(hba); if (err) @@ -1670,6 +1675,12 @@ static inline bool ufshcd_is_wb_attrs(enum attr_idn idn) idn <= QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE; } +static inline bool ufshcd_is_qword_attr(enum attr_idn idn) +{ + return idn == QUERY_ATTR_IDN_TIMESTAMP || + idn == QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID; +} + static int wb_read_resize_attrs(struct ufs_hba *hba, enum attr_idn idn, u32 *attr_val) { @@ -1736,6 +1747,7 @@ static ssize_t _name##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct ufs_hba *hba = dev_get_drvdata(dev); \ + u64 qword_value; \ u32 value; \ int ret; \ u8 index = 0; \ @@ -1748,14 +1760,24 @@ static ssize_t _name##_show(struct device *dev, \ if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \ index = ufshcd_wb_get_query_index(hba); \ ufshcd_rpm_get_sync(hba); \ - ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, \ - QUERY_ATTR_IDN##_uname, index, 0, &value); \ + if (ufshcd_is_qword_attr(QUERY_ATTR_IDN##_uname)) \ + ret = ufshcd_query_attr_qword(hba, \ + UPIU_QUERY_OPCODE_READ_ATTR, \ + QUERY_ATTR_IDN##_uname, \ + index, 0, &qword_value); \ + else \ + ret = ufshcd_query_attr(hba, \ + UPIU_QUERY_OPCODE_READ_ATTR, \ + QUERY_ATTR_IDN##_uname, index, 0, &value); \ ufshcd_rpm_put_sync(hba); \ if (ret) { \ ret = -EINVAL; \ goto out; \ } \ - ret = sysfs_emit(buf, "0x%08X\n", value); \ + if (ufshcd_is_qword_attr(QUERY_ATTR_IDN##_uname)) \ + ret = sysfs_emit(buf, "0x%016llX\n", qword_value); \ + else \ + ret = sysfs_emit(buf, "0x%08X\n", value); \ out: \ up(&hba->host_sem); \ return ret; \ diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 0a72148cb053..ed1adeb22ec6 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -60,6 +60,8 @@ int ufshcd_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode, u32 *attr_val); int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector, u32 *attr_val); +int ufshcd_query_attr_qword(struct ufs_hba *hba, enum query_opcode opcode, + enum attr_idn idn, u8 index, u8 sel, u64 *attr_val); int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, u8 index, bool *flag_res); void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit); @@ -106,7 +108,6 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, enum query_opcode desc_op); int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable); -int ufshcd_read_device_lvl_exception_id(struct ufs_hba *hba, u64 *exception_id); int ufshcd_uic_tx_eqtr(struct ufs_hba *hba, int gear); void ufshcd_apply_valid_tx_eq_settings(struct ufs_hba *hba); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 4805e40ed4d7..c92e0409c793 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -3611,6 +3611,67 @@ int ufshcd_query_attr_retry(struct ufs_hba *hba, return ret; } +/** + * ufshcd_query_attr_qword - Function of sending query requests for quad-word attributes + * @hba: per-adapter instance + * @opcode: attribute opcode + * @idn: attribute idn to access + * @index: index field + * @sel: selector field + * @attr_val: the attribute value after the query request completes + * + * Return: 0 for success, non-zero in case of failure. + */ +int ufshcd_query_attr_qword(struct ufs_hba *hba, enum query_opcode opcode, + enum attr_idn idn, u8 index, u8 sel, u64 *attr_val) +{ + struct utp_upiu_query_v4_0 *upiu_req; + struct utp_upiu_query_v4_0 *upiu_resp; + struct ufs_query_req *request = NULL; + struct ufs_query_res *response = NULL; + int err; + + if (!attr_val) { + dev_err(hba->dev, "%s: attribute value required for opcode 0x%x\n", + __func__, opcode); + return -EINVAL; + } + + ufshcd_dev_man_lock(hba); + + ufshcd_init_query(hba, &request, &response, opcode, idn, index, sel); + + switch (opcode) { + case UPIU_QUERY_OPCODE_WRITE_ATTR: + request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; + upiu_req = (struct utp_upiu_query_v4_0 *)&request->upiu_req; + put_unaligned_be64(*attr_val, &upiu_req->osf3); + break; + case UPIU_QUERY_OPCODE_READ_ATTR: + request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; + break; + default: + dev_err(hba->dev, "%s: Expected query attr opcode but got = 0x%.2x\n", + __func__, opcode); + err = -EINVAL; + goto out_unlock; + } + + err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, dev_cmd_timeout); + if (err) { + dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index %d, selector %d, err = %d\n", + __func__, opcode, idn, index, sel, err); + goto out_unlock; + } + + upiu_resp = (struct utp_upiu_query_v4_0 *)response; + *attr_val = get_unaligned_be64(&upiu_resp->osf3); + +out_unlock: + ufshcd_dev_man_unlock(hba); + return err; +} + /* * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; * < 0 if another error occurred. @@ -6224,46 +6285,6 @@ static void ufshcd_bkops_exception_event_handler(struct ufs_hba *hba) __func__, err); } -/* - * Return: 0 upon success; > 0 in case the UFS device reported an OCS error; - * < 0 if another error occurred. - */ -int ufshcd_read_device_lvl_exception_id(struct ufs_hba *hba, u64 *exception_id) -{ - struct utp_upiu_query_v4_0 *upiu_resp; - struct ufs_query_req *request = NULL; - struct ufs_query_res *response = NULL; - int err; - - if (hba->dev_info.wspecversion < 0x410) - return -EOPNOTSUPP; - - ufshcd_hold(hba); - mutex_lock(&hba->dev_cmd.lock); - - ufshcd_init_query(hba, &request, &response, - UPIU_QUERY_OPCODE_READ_ATTR, - QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID, 0, 0); - - request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; - - err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, dev_cmd_timeout); - - if (err) { - dev_err(hba->dev, "%s: failed to read device level exception %d\n", - __func__, err); - goto out; - } - - upiu_resp = (struct utp_upiu_query_v4_0 *)response; - *exception_id = get_unaligned_be64(&upiu_resp->osf3); -out: - mutex_unlock(&hba->dev_cmd.lock); - ufshcd_release(hba); - - return err; -} - static int __ufshcd_wb_toggle(struct ufs_hba *hba, bool set, enum flag_idn idn) { u8 index; @@ -9113,35 +9134,20 @@ static int ufshcd_device_params_init(struct ufs_hba *hba) static void ufshcd_set_timestamp_attr(struct ufs_hba *hba) { - int err; - struct ufs_query_req *request = NULL; - struct ufs_query_res *response = NULL; struct ufs_dev_info *dev_info = &hba->dev_info; - struct utp_upiu_query_v4_0 *upiu_data; + u64 ts_ns; + int err; if (dev_info->wspecversion < 0x400 || hba->dev_quirks & UFS_DEVICE_QUIRK_NO_TIMESTAMP_SUPPORT) return; - ufshcd_dev_man_lock(hba); - - ufshcd_init_query(hba, &request, &response, - UPIU_QUERY_OPCODE_WRITE_ATTR, - QUERY_ATTR_IDN_TIMESTAMP, 0, 0); - - request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; - - upiu_data = (struct utp_upiu_query_v4_0 *)&request->upiu_req; - - put_unaligned_be64(ktime_get_real_ns(), &upiu_data->osf3); - - err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, dev_cmd_timeout); - + ts_ns = ktime_get_real_ns(); + err = ufshcd_query_attr_qword(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, + QUERY_ATTR_IDN_TIMESTAMP, 0, 0, &ts_ns); if (err) dev_err(hba->dev, "%s: failed to set timestamp %d\n", __func__, err); - - ufshcd_dev_man_unlock(hba); } /** From 949af038b6d2a41c54502179c5a8ddfb3d57dd17 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Fri, 24 Apr 2026 08:14:20 -0700 Subject: [PATCH 09/56] scsi: ufs: core: Add support to retrieve and store TX Equalization settings Add support for UFS v5.0 JEDEC attributes qTxEQGnSettings and wTxEQGnSettingsExt to enable persistent storage and retrieval of optimal TX Equalization settings. This provides a fast-path for TX Equalization by reusing previously stored optimal settings, avoiding TX Equalization Training (EQTR) procedures during subsequent Power Mode changes. When no valid TX Equalization settings are found, fall back to full TX EQTR procedures and optionally save the results for future use. The validity of one set of TX Equalization settings is indicated by Bit[15] in wTxEQGnSettingsExt. Signed-off-by: Can Guo Reviewed-by: Peter Wang Reviewed-by: Bean Huo Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260424151420.111675-3-can.guo@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-txeq.c | 287 +++++++++++++++++++++++++++++++++ drivers/ufs/core/ufshcd-priv.h | 2 + drivers/ufs/core/ufshcd.c | 5 + include/ufs/ufs.h | 2 + include/ufs/ufshcd.h | 2 + 5 files changed, 298 insertions(+) diff --git a/drivers/ufs/core/ufs-txeq.c b/drivers/ufs/core/ufs-txeq.c index b2dc89124353..4b264adfdf49 100644 --- a/drivers/ufs/core/ufs-txeq.c +++ b/drivers/ufs/core/ufs-txeq.c @@ -14,6 +14,9 @@ #include #include "ufshcd-priv.h" +#define TX_EQ_SETTING_MASK 0x7 +#define TX_EQ_SETTINGS_VALID_BIT BIT(15) + static bool use_adaptive_txeq; module_param(use_adaptive_txeq, bool, 0644); MODULE_PARM_DESC(use_adaptive_txeq, "Find and apply optimal TX Equalization settings before changing Power Mode (default: false)"); @@ -40,6 +43,28 @@ static bool txeq_presets_selected[UFS_TX_EQ_PRESET_MAX] = {[0 ... (UFS_TX_EQ_PRE module_param_array(txeq_presets_selected, bool, NULL, 0644); MODULE_PARM_DESC(txeq_presets_selected, "Use only the selected Presets out of the 8 TX Equalization Presets for TX EQTR"); +static int txeq_setting_sel_set(const char *val, const struct kernel_param *kp) +{ + return param_set_uint_minmax(val, kp, 0, 1); +} + +static const struct kernel_param_ops txeq_setting_sel_ops = { + .set = txeq_setting_sel_set, + .get = param_get_uint, +}; + +static unsigned int txeq_setting_sel; +module_param_cb(txeq_setting_sel, &txeq_setting_sel_ops, &txeq_setting_sel, 0644); +MODULE_PARM_DESC(txeq_setting_sel, "The qTxEQGnSettings and wTxEQGnSettingsExt Attributes selector used to retrieve and store TX Equalization settings"); + +static bool retrieve_txeq_setting = true; +module_param(retrieve_txeq_setting, bool, 0644); +MODULE_PARM_DESC(retrieve_txeq_setting, "Retrieve TX Equalization settings from qTxEQGnSettings and wTxEQGnSettingsExt Attributes (default: true)"); + +static bool store_txeq_setting = true; +module_param(store_txeq_setting, bool, 0644); +MODULE_PARM_DESC(store_txeq_setting, "Store the optimal TX Equalization settings to qTxEQGnSettings and wTxEQGnSettingsExt Attributes (default: true)"); + /* * ufs_tx_eq_preset - Table of minimum required list of presets. * @@ -117,6 +142,126 @@ static const u32 pa_tx_eq_setting[UFS_HS_GEAR_MAX] = { PA_TXEQG6SETTING }; +/* + * Decode Device TX Equalization PreShoot value based on qTxEQGnSettings bit assignment: + * bit[3:0]: Device TX Logical LANE 0 PreShoot + * bit[7:4]: Device TX Logical LANE 1 PreShoot + */ +static inline u8 tx_eq_device_preshoot_decode(u64 eq, u8 lane) +{ + return (u8)((eq >> (lane * TX_HS_PRESHOOT_SHIFT)) & TX_EQ_SETTING_MASK); +} + +/* + * Decode Device TX Equalization DeEmphasis value based on qTxEQGnSettings bit assignment: + * bit[19:16]: Device TX Logical LANE 0 DeEmphasis + * bit[23:20]: Device TX Logical LANE 1 DeEmphasis + */ +static inline u8 tx_eq_device_deemphasis_decode(u64 eq, u8 lane) +{ + return (u8)((eq >> (lane * TX_HS_DEEMPHASIS_SHIFT + 16)) & TX_EQ_SETTING_MASK); +} + +/* + * Decode Host TX Equalization PreShoot value based on qTxEQGnSettings bit assignment: + * bit[35:32]: Host TX Logical LANE 0 PreShoot + * bit[39:36]: Host TX Logical LANE 1 PreShoot + */ +static inline u8 tx_eq_host_preshoot_decode(u64 eq, u8 lane) +{ + return (u8)((eq >> (lane * TX_HS_PRESHOOT_SHIFT + 32)) & TX_EQ_SETTING_MASK); +} + +/* + * Decode Host TX Equalization DeEmphasis value based on qTxEQGnSettings bit assignment: + * bit[51:48]: Host TX Logical LANE 0 DeEmphasis + * bit[55:52]: Host TX Logical LANE 1 DeEmphasis + */ +static inline u8 tx_eq_host_deemphasis_decode(u64 eq, u8 lane) +{ + return (u8)((eq >> (lane * TX_HS_DEEMPHASIS_SHIFT + 48)) & TX_EQ_SETTING_MASK); +} + +/* + * Decode Device TX precode_en indication based on wTxEQGnSettingsExt bit assignment: + * bit[0]: PreCodeEn for Device TX Logical LANE 0 + * bit[1]: PreCodeEn for Device TX Logical LANE 1 + */ +static inline bool tx_eq_device_precode_en_decode(u16 eq_ext, u8 lane) +{ + return eq_ext & BIT(lane); +} + +/* + * Decode Host TX precode_en indication based on wTxEQGnSettingsExt bit assignment: + * bit[4]: PreCodeEn for Device RX Logical LANE 0 + * bit[5]: PreCodeEn for Device RX Logical LANE 1 + */ +static inline bool tx_eq_host_precode_en_decode(u16 eq_ext, u8 lane) +{ + return eq_ext & BIT(lane + 4); +} + +/* + * Encode Device TX Equalization PreShoot value based on qTxEQGnSettings bit assignment: + * bit[3:0]: Device TX Logical LANE 0 PreShoot + * bit[7:4]: Device TX Logical LANE 1 PreShoot + */ +static inline u64 tx_eq_device_preshoot_encode(u64 val, u8 lane) +{ + return (val & TX_EQ_SETTING_MASK) << (lane * TX_HS_PRESHOOT_SHIFT); +} + +/* + * Encode Device TX Equalization DeEmphasis value based on qTxEQGnSettings bit assignment: + * bit[19:16]: Device TX Logical LANE 0 DeEmphasis + * bit[23:20]: Device TX Logical LANE 1 DeEmphasis + */ +static inline u64 tx_eq_device_deemphasis_encode(u64 val, u8 lane) +{ + return (val & TX_EQ_SETTING_MASK) << (lane * TX_HS_DEEMPHASIS_SHIFT + 16); +} + +/* + * Encode Host TX Equalization PreShoot value based on qTxEQGnSettings bit assignment: + * bit[35:32]: Host TX Logical LANE 0 PreShoot + * bit[39:36]: Host TX Logical LANE 1 PreShoot + */ +static inline u64 tx_eq_host_preshoot_encode(u64 val, u8 lane) +{ + return (val & TX_EQ_SETTING_MASK) << (lane * TX_HS_PRESHOOT_SHIFT + 32); +} + +/* + * Encode Host TX Equalization DeEmphasis value based on qTxEQGnSettings bit assignment: + * bit[51:48]: Host TX Logical LANE 0 DeEmphasis + * bit[55:52]: Host TX Logical LANE 1 DeEmphasis + */ +static inline u64 tx_eq_host_deemphasis_encode(u64 val, u8 lane) +{ + return (val & TX_EQ_SETTING_MASK) << (lane * TX_HS_DEEMPHASIS_SHIFT + 48); +} + +/* + * Encode Device precode_en based on wTxEQGnSettingsExt bit assignment: + * bit[0]: PreCodeEn for Device TX Logical LANE 0 + * bit[1]: PreCodeEn for Device TX Logical LANE 1 + */ +static inline u16 tx_eq_device_precode_en_encode(bool en, u8 lane) +{ + return (u16)en << lane; +} + +/* + * Encode Host precode_en based on wTxEQGnSettingsExt bit assignment: + * bit[4]: PreCodeEn for Device RX Logical LANE 0 + * bit[5]: PreCodeEn for Device RX Logical LANE 1 + */ +static inline u16 tx_eq_host_precode_en_encode(bool en, u8 lane) +{ + return (u16)en << (lane + 4); +} + /** * ufshcd_configure_precoding - Configure Pre-Coding for all active lanes * @hba: per adapter instance @@ -1164,6 +1309,7 @@ int ufshcd_config_tx_eq_settings(struct ufs_hba *hba, /* Mark TX Equalization settings as valid */ params->is_valid = true; + params->is_trained = true; params->is_applied = false; } @@ -1291,3 +1437,144 @@ int ufshcd_retrain_tx_eq(struct ufs_hba *hba, u32 gear) return ret; } + +/** + * ufshcd_extract_tx_eq_settings_attrs - Extract TX Equalization settings from UFS attributes + * @hba: per adapter instance + * @gear: target gear + * + * This function extracts previously stored TX Equalization settings from UFS + * attributes qTxEQGnSettings and wTxEQGnSettingsExt. These attributes contain + * the optimal TX Equalization parameters (PreShoot, DeEmphasis, and PreCoding + * enable) that were determined during a previous EQTR procedure. + * + * The function reads: + * 1. qTxEQGnSettings (64-bit): Main attribute containing PreShoot and + * DeEmphasis values for both host and device TX lanes + * 2. wTxEQGnSettingsExt (16-bit): Extended attribute containing PreCoding + * enable flags and validity indicator + */ +static void ufshcd_extract_tx_eq_settings_attrs(struct ufs_hba *hba, u8 gear) +{ + struct ufshcd_tx_eq_params *params; + u32 lane, eq_ext; + int ret; + u64 eq; + + ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_TX_EQ_GN_SETTINGS_EXT, gear - 1, + (u8)txeq_setting_sel, &eq_ext); + if (ret) + return; + + dev_dbg(hba->dev, "%s: HS-G%u wTxEQGnSettingsExt (Selector %u) = 0x%08x\n", + __func__, gear, txeq_setting_sel, eq_ext); + + if (!(eq_ext & TX_EQ_SETTINGS_VALID_BIT)) + return; + + ret = ufshcd_query_attr_qword(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_TX_EQ_GN_SETTINGS, + gear - 1, (u8)txeq_setting_sel, &eq); + if (ret) + return; + + dev_dbg(hba->dev, "%s: HS-G%u qTxEQGnSettings (Selector %u) = 0x%016llx\n", + __func__, gear, txeq_setting_sel, eq); + + params = &hba->tx_eq_params[gear - 1]; + + for (lane = 0; lane < UFS_MAX_LANES; lane++) { + params->host[lane].preshoot = tx_eq_host_preshoot_decode(eq, lane); + params->host[lane].deemphasis = tx_eq_host_deemphasis_decode(eq, lane); + params->host[lane].precode_en = tx_eq_host_precode_en_decode(eq_ext, lane); + + params->device[lane].preshoot = tx_eq_device_preshoot_decode(eq, lane); + params->device[lane].deemphasis = tx_eq_device_deemphasis_decode(eq, lane); + params->device[lane].precode_en = tx_eq_device_precode_en_decode(eq_ext, lane); + } + + params->is_valid = true; +} + +void ufshcd_retrieve_tx_eq_settings(struct ufs_hba *hba) +{ + u8 gear = (u8)adaptive_txeq_gear; + + if (!hba->max_pwr_info.is_valid || !ufshcd_is_tx_eq_supported(hba) || + !use_adaptive_txeq || !retrieve_txeq_setting) + return; + + for (; gear <= UFS_HS_GEAR_MAX; gear++) + ufshcd_extract_tx_eq_settings_attrs(hba, gear); +} + +/** + * ufshcd_update_tx_eq_settings_attrs - Update TX EQ settings in UFS attributes + * @hba: per adapter instance + * @gear: target gear + * + * This function stores the optimal TX Equalization settings obtained from + * TX EQTR procedure into UFS device attributes for future fast-path retrieval. + * The settings are stored in two complementary attributes: + * + * 1. qTxEQGnSettings (64-bit): Main attribute containing PreShoot and + * DeEmphasis values for both host and device TX lanes + * 2. wTxEQGnSettingsExt (16-bit): Extended attribute containing PreCoding + * enable flags and validity indicator + */ +static void ufshcd_update_tx_eq_settings_attrs(struct ufs_hba *hba, u8 gear) +{ + struct ufshcd_tx_eq_params *params; + u32 lane, eq_ext = 0; + u64 eq = 0; + int ret; + + params = &hba->tx_eq_params[gear - 1]; + if (!params->is_valid || !params->is_trained) + return; + + for (lane = 0; lane < UFS_MAX_LANES; lane++) { + eq |= tx_eq_host_preshoot_encode((u64)params->host[lane].preshoot, lane); + eq |= tx_eq_host_deemphasis_encode((u64)params->host[lane].deemphasis, lane); + eq_ext |= tx_eq_host_precode_en_encode(params->host[lane].precode_en, lane); + + eq |= tx_eq_device_preshoot_encode((u64)params->device[lane].preshoot, lane); + eq |= tx_eq_device_deemphasis_encode((u64)params->device[lane].deemphasis, lane); + eq_ext |= tx_eq_device_precode_en_encode(params->device[lane].precode_en, lane); + } + + /* Set validity flag to indicate valid settings are stored */ + eq_ext |= TX_EQ_SETTINGS_VALID_BIT; + + /* Write qTxEQGnSettings */ + ret = ufshcd_query_attr_qword(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, + QUERY_ATTR_IDN_TX_EQ_GN_SETTINGS, + gear - 1, (u8)txeq_setting_sel, &eq); + if (ret) + return; + + /* Write wTxEQGnSettingsExt */ + ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, + QUERY_ATTR_IDN_TX_EQ_GN_SETTINGS_EXT, gear - 1, + (u8)txeq_setting_sel, &eq_ext); + if (ret) + return; + + dev_dbg(hba->dev, "%s: Saved HS-G%u qTxEQGnSettings (Selector %u) = 0x%016llx\n", + __func__, gear, txeq_setting_sel, eq); + dev_dbg(hba->dev, "%s: Saved HS-G%u wTxEQGnSettingsExt (Selector %u) = 0x%08x\n", + __func__, gear, txeq_setting_sel, eq_ext); +} + +void ufshcd_store_tx_eq_settings(struct ufs_hba *hba) +{ + u8 gear = (u8)adaptive_txeq_gear; + + if (!hba->max_pwr_info.is_valid || !ufshcd_is_tx_eq_supported(hba) || + !use_adaptive_txeq || !store_txeq_setting) + return; + + for (; gear <= UFS_HS_GEAR_MAX; gear++) + ufshcd_update_tx_eq_settings_attrs(hba, gear); +} diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index ed1adeb22ec6..70f90d97f217 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -118,6 +118,8 @@ void ufshcd_print_tx_eq_params(struct ufs_hba *hba); bool ufshcd_is_txeq_presets_used(struct ufs_hba *hba); bool ufshcd_is_txeq_preset_selected(u8 preshoot, u8 deemphasis); int ufshcd_retrain_tx_eq(struct ufs_hba *hba, u32 gear); +void ufshcd_retrieve_tx_eq_settings(struct ufs_hba *hba); +void ufshcd_store_tx_eq_settings(struct ufs_hba *hba); /* Wrapper functions for safely calling variant operations */ static inline const char *ufshcd_get_var_name(struct ufs_hba *hba) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index c92e0409c793..a6026cc4b2f4 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -9128,6 +9128,8 @@ static int ufshcd_device_params_init(struct ufs_hba *hba) dev_err(hba->dev, "%s: Failed getting max supported power mode\n", __func__); + + ufshcd_retrieve_tx_eq_settings(hba); out: return ret; } @@ -10748,6 +10750,9 @@ static void ufshcd_wl_shutdown(struct scsi_device *sdev) /* Turn on everything while shutting down */ ufshcd_rpm_get_sync(hba); + + ufshcd_store_tx_eq_settings(hba); + scsi_device_quiesce(sdev); shost_for_each_device(sdev, hba->host) { if (sdev == hba->ufs_device_wlun) diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index 602aa34c9822..0d48e137d66d 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -191,6 +191,8 @@ enum attr_idn { QUERY_ATTR_IDN_WB_BUF_RESIZE_HINT = 0x3C, QUERY_ATTR_IDN_WB_BUF_RESIZE_EN = 0x3D, QUERY_ATTR_IDN_WB_BUF_RESIZE_STATUS = 0x3E, + QUERY_ATTR_IDN_TX_EQ_GN_SETTINGS = 0x47, + QUERY_ATTR_IDN_TX_EQ_GN_SETTINGS_EXT = 0x48, }; /* Descriptor idn for Query requests */ diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index cfbc75d8df83..f48d6416e299 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -358,6 +358,7 @@ struct ufshcd_tx_eqtr_record { * @eqtr_record: Pointer to TX EQTR record * @is_valid: True if parameter contains valid TX Equalization settings * @is_applied: True if settings have been applied to UniPro of both sides + * @is_trained: True if parameters obtained from TX EQTR procedure */ struct ufshcd_tx_eq_params { struct ufshcd_tx_eq_settings host[UFS_MAX_LANES]; @@ -365,6 +366,7 @@ struct ufshcd_tx_eq_params { struct ufshcd_tx_eqtr_record *eqtr_record; bool is_valid; bool is_applied; + bool is_trained; }; /** From 195254adeddc30c5a892a1cc9528a6ed5e841224 Mon Sep 17 00:00:00 2001 From: Evgenii Burenchev Date: Wed, 29 Apr 2026 12:52:12 +0300 Subject: [PATCH 10/56] scsi: snic: vnic_dev: Remove dead store in vnic_dev_discover_res() The assignment 'len = count' for RES_TYPE_INTR_PBA_LEGACY, RES_TYPE_DEVCMD, and RES_TYPE_DEVCMD2 cases is never used. Drop the unused assignments to fix the following static analyzer warning. No functional change. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Evgenii Burenchev Acked-by: Narsimhulu Musini Link: https://patch.msgid.link/20260429095212.11251-1-evg28bur@yandex.ru Signed-off-by: Martin K. Petersen --- drivers/scsi/snic/vnic_dev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/snic/vnic_dev.c b/drivers/scsi/snic/vnic_dev.c index ed7771e62854..22303f827583 100644 --- a/drivers/scsi/snic/vnic_dev.c +++ b/drivers/scsi/snic/vnic_dev.c @@ -132,7 +132,6 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, case RES_TYPE_INTR_PBA_LEGACY: case RES_TYPE_DEVCMD: case RES_TYPE_DEVCMD2: - len = count; break; default: From 2a18c57560f454e2e63373ecf00e4a6fb0265600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 5 May 2026 10:28:52 +0200 Subject: [PATCH 11/56] scsi: ufs: tc-dwc-g210-pci: Simplify initialization of pci_device_id array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A list initializer is hard to parse for a human if they don't see or know the order of the members of struct pci_device_id. So use the PCI_VDEVICE macro which is much more idiomatic and skip assigning explicit zeros. There are no changes to the compiled result of the array; verified with builds for x86 and arm64. Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/ff015bf46ad395702f40c85c8359fd24957e7224.1777968942.git.u.kleine-koenig@baylibre.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/tc-dwc-g210-pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/host/tc-dwc-g210-pci.c b/drivers/ufs/host/tc-dwc-g210-pci.c index 0167d8bef71a..c6d89f9c44ae 100644 --- a/drivers/ufs/host/tc-dwc-g210-pci.c +++ b/drivers/ufs/host/tc-dwc-g210-pci.c @@ -114,8 +114,8 @@ static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = { }; static const struct pci_device_id tc_dwc_g210_pci_tbl[] = { - { PCI_VENDOR_ID_SYNOPSYS, 0xB101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_SYNOPSYS, 0xB102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VDEVICE(SYNOPSYS, 0xB101) }, + { PCI_VDEVICE(SYNOPSYS, 0xB102) }, { } /* terminate list */ }; From 8ef4c72dbbfda41b8f83a9b5a275feaf4a30ea21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Tue, 5 May 2026 10:28:53 +0200 Subject: [PATCH 12/56] scsi: ufs: ufshcd-pci: Use PCI_VDEVICE and named initializers for pci array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pci_device_id array uses a mixture of ways to initialize ufshcd_pci_tbl[]. List initializers are hard to read unless you memoized the order of the struct members. Use the PCI_VDEVICE for all entries and a named initializer for .driver_data. This allows to idiomatically assign the members without using zeros to fill the fields before .driver_data (either explicitly or hidding in PCI_VDEVICE()). There are no changes to the compiled result of the array; verified with builds for x86 and arm64. Signed-off-by: Uwe Kleine-König (The Capable Hub) Reviewed-by: Adrian Hunter Link: https://patch.msgid.link/6cac1c22381f7026edad9854d70833381d14929a.1777968942.git.u.kleine-koenig@baylibre.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufshcd-pci.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/ufs/host/ufshcd-pci.c b/drivers/ufs/host/ufshcd-pci.c index effa3c7a01c5..13293e83064c 100644 --- a/drivers/ufs/host/ufshcd-pci.c +++ b/drivers/ufs/host/ufshcd-pci.c @@ -680,21 +680,20 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = { }; static const struct pci_device_id ufshcd_pci_tbl[] = { - { PCI_VENDOR_ID_REDHAT, 0x0013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - (kernel_ulong_t)&ufs_qemu_hba_vops }, - { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VDEVICE(INTEL, 0x9DFA), (kernel_ulong_t)&ufs_intel_cnl_hba_vops }, - { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_ehl_hba_vops }, - { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_ehl_hba_vops }, - { PCI_VDEVICE(INTEL, 0x98FA), (kernel_ulong_t)&ufs_intel_lkf_hba_vops }, - { PCI_VDEVICE(INTEL, 0x51FF), (kernel_ulong_t)&ufs_intel_adl_hba_vops }, - { PCI_VDEVICE(INTEL, 0x54FF), (kernel_ulong_t)&ufs_intel_adl_hba_vops }, - { PCI_VDEVICE(INTEL, 0x7E47), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, - { PCI_VDEVICE(INTEL, 0xA847), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, - { PCI_VDEVICE(INTEL, 0x7747), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, - { PCI_VDEVICE(INTEL, 0xE447), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, - { PCI_VDEVICE(INTEL, 0x4D47), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, - { PCI_VDEVICE(INTEL, 0xD335), (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { PCI_VDEVICE(REDHAT, 0x0013), .driver_data = (kernel_ulong_t)&ufs_qemu_hba_vops }, + { PCI_VDEVICE(SAMSUNG, 0xC00C), .driver_data = 0 }, + { PCI_VDEVICE(INTEL, 0x9DFA), .driver_data = (kernel_ulong_t)&ufs_intel_cnl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x4B41), .driver_data = (kernel_ulong_t)&ufs_intel_ehl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x4B43), .driver_data = (kernel_ulong_t)&ufs_intel_ehl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x98FA), .driver_data = (kernel_ulong_t)&ufs_intel_lkf_hba_vops }, + { PCI_VDEVICE(INTEL, 0x51FF), .driver_data = (kernel_ulong_t)&ufs_intel_adl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x54FF), .driver_data = (kernel_ulong_t)&ufs_intel_adl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x7E47), .driver_data = (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { PCI_VDEVICE(INTEL, 0xA847), .driver_data = (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x7747), .driver_data = (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { PCI_VDEVICE(INTEL, 0xE447), .driver_data = (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x4D47), .driver_data = (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { PCI_VDEVICE(INTEL, 0xD335), .driver_data = (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, { } /* terminate list */ }; From 036218473a8467493860df84602a7825b71385af Mon Sep 17 00:00:00 2001 From: Md Shofiqul Islam Date: Wed, 6 May 2026 12:45:04 +0300 Subject: [PATCH 13/56] scsi: core: scsi_scan: Fix typo in comment Fix spelling mistake in comment: - initialze -> initialize Signed-off-by: Md Shofiqul Islam Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260506094504.2235-1-shofiqtest@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index ef22a4228b85..a35a5f777d16 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -858,7 +858,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, } /** - * scsi_add_lun - allocate and fully initialze a scsi_device + * scsi_add_lun - allocate and fully initialize a scsi_device * @sdev: holds information to be stored in the new scsi_device * @inq_result: holds the result of a previous INQUIRY to the LUN * @bflags: black/white list flag From 73322071418ec3ad5e4d9cdf783890d7f2ae9777 Mon Sep 17 00:00:00 2001 From: Md Shofiqul Islam Date: Wed, 6 May 2026 03:49:48 +0300 Subject: [PATCH 14/56] scsi: storvsc: Replace symbolic permissions with octal Symbolic permissions like S_IRUGO and S_IWUSR are not preferred by checkpatch. Replace with their octal equivalents: - S_IRUGO|S_IWUSR -> 0644 - S_IRUGO -> 0444 Signed-off-by: Md Shofiqul Islam Reviewed-by: Long Li Link: https://patch.msgid.link/20260506004948.2172-1-shofiqtest@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/storvsc_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 6977ca8a0658..571ea549152b 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -156,7 +156,7 @@ static bool hv_dev_is_fc(struct hv_device *hv_dev); #define STORVSC_LOGGING_WARN 2 static int logging_level = STORVSC_LOGGING_ERROR; -module_param(logging_level, int, S_IRUGO|S_IWUSR); +module_param(logging_level, int, 0644); MODULE_PARM_DESC(logging_level, "Logging level, 0 - None, 1 - Error (default), 2 - Warning."); @@ -345,17 +345,17 @@ static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth) static int storvsc_vcpus_per_sub_channel = 4; static unsigned int storvsc_max_hw_queues; -module_param(storvsc_ringbuffer_size, int, S_IRUGO); +module_param(storvsc_ringbuffer_size, int, 0444); MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)"); module_param(storvsc_max_hw_queues, uint, 0644); MODULE_PARM_DESC(storvsc_max_hw_queues, "Maximum number of hardware queues"); -module_param(storvsc_vcpus_per_sub_channel, int, S_IRUGO); +module_param(storvsc_vcpus_per_sub_channel, int, 0444); MODULE_PARM_DESC(storvsc_vcpus_per_sub_channel, "Ratio of VCPUs to subchannels"); static int ring_avail_percent_lowater = 10; -module_param(ring_avail_percent_lowater, int, S_IRUGO); +module_param(ring_avail_percent_lowater, int, 0444); MODULE_PARM_DESC(ring_avail_percent_lowater, "Select a channel if available ring size > this in percent"); From 1039939c52f27667c819537ce5ca231805ca40b8 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Thu, 7 May 2026 16:34:10 +0200 Subject: [PATCH 15/56] scsi: scsi_transport_srp: Move long delayed work to system_dfl_long_wq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the code enqueue work items using {queue|mod}_delayed_work(), using system_long_wq. This workqueue should be used when long works are expected and it is a per-cpu workqueue. The function(s) end up calling __queue_delayed_work(), which set a global timer that could fire anywhere, enqueuing the work where the timer fired. Unbound works could benefit from scheduler task placement, to optimize performance and power consumption. Long work shouldn't stick to a single CPU. Recently, a new unbound workqueue specific for long running work has been added:     c116737e972e ("workqueue: Add system_dfl_long_wq for long unbound works") Since the workqueue work doesn't rely on per-cpu variables, there is no obvious reason that justify the use of a per-cpu workqueue. So change system_long_wq with system_dfl_long_wq so that the work may benefit from scheduler task placement. Signed-off-by: Marco Crivellari Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260507143410.337267-1-marco.crivellari@suse.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_srp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index d71ab5fdb758..a61cbb079ab4 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -234,7 +234,7 @@ static ssize_t store_reconnect_delay(struct device *dev, if (rport->reconnect_delay <= 0 && delay > 0 && rport->state != SRP_RPORT_RUNNING) { - queue_delayed_work(system_long_wq, &rport->reconnect_work, + queue_delayed_work(system_dfl_long_wq, &rport->reconnect_work, delay * HZ); } else if (delay <= 0) { cancel_delayed_work(&rport->reconnect_work); @@ -390,7 +390,7 @@ static void srp_reconnect_work(struct work_struct *work) delay = rport->reconnect_delay * clamp(rport->failed_reconnects - 10, 1, 100); if (delay > 0) - queue_delayed_work(system_long_wq, + queue_delayed_work(system_dfl_long_wq, &rport->reconnect_work, delay * HZ); } } @@ -474,7 +474,7 @@ static void __srp_start_tl_fail_timers(struct srp_rport *rport) if (rport->state == SRP_RPORT_LOST) return; if (delay > 0) - queue_delayed_work(system_long_wq, &rport->reconnect_work, + queue_delayed_work(system_dfl_long_wq, &rport->reconnect_work, 1UL * delay * HZ); if ((fast_io_fail_tmo >= 0 || dev_loss_tmo >= 0) && srp_rport_set_state(rport, SRP_RPORT_BLOCKED) == 0) { @@ -482,11 +482,11 @@ static void __srp_start_tl_fail_timers(struct srp_rport *rport) rport->state); scsi_block_targets(shost, &shost->shost_gendev); if (fast_io_fail_tmo >= 0) - queue_delayed_work(system_long_wq, + queue_delayed_work(system_dfl_long_wq, &rport->fast_io_fail_work, 1UL * fast_io_fail_tmo * HZ); if (dev_loss_tmo >= 0) - queue_delayed_work(system_long_wq, + queue_delayed_work(system_dfl_long_wq, &rport->dev_loss_work, 1UL * dev_loss_tmo * HZ); } From 53f5cce2efc7af85a15ca224c660c397332f19e1 Mon Sep 17 00:00:00 2001 From: Wang Zihan Date: Sat, 2 May 2026 14:07:03 +0800 Subject: [PATCH 16/56] scsi: st: Fix typo in documentation Correct "form" to "from" in drive buffers description. Signed-off-by: Wang Zihan Link: https://patch.msgid.link/tencent_818C822F215676B9B14011B88848609BD309@qq.com Signed-off-by: Martin K. Petersen --- Documentation/scsi/st.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/scsi/st.rst b/Documentation/scsi/st.rst index b4a092faa9c8..539ff06daf5e 100644 --- a/Documentation/scsi/st.rst +++ b/Documentation/scsi/st.rst @@ -93,7 +93,7 @@ optionally written. In both cases end of data is signified by returning zero bytes for two consecutive reads. Writing filemarks without the immediate bit set in the SCSI command block acts -as a synchronization point, i.e., all remaining data form the drive buffers is +as a synchronization point, i.e., all remaining data from the drive buffers is written to tape before the command returns. This makes sure that write errors are caught at that point, but this takes time. In some applications, several consecutive files must be written fast. The MTWEOFI operation can be used to From 250ba648f42d571e08e0bd95fa32953e7577001d Mon Sep 17 00:00:00 2001 From: Wang Yan Date: Mon, 11 May 2026 17:30:30 +0800 Subject: [PATCH 17/56] scsi: libiscsi: Fix spelling and format errors Fix two issues in libiscsi.c: - Correct typo "numer" to "number" in iscsi_session_setup() comment - Fix format string "seconds\n." to "seconds.\n" in recv timeout warning Signed-off-by: Wang Yan Reviewed-by: Mike Christie Reviewed-by: Chris Leech Link: https://patch.msgid.link/20260511093030.63542-1-wangyan01@kylinos.cn Signed-off-by: Martin K. Petersen --- drivers/scsi/libiscsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 25857d6ed6e8..160f02f2f51d 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -3012,7 +3012,7 @@ static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost) * This can be used by software iscsi_transports that allocate * a session per scsi host. * - * Callers should set cmds_max to the largest total numer (mgmt + scsi) of + * Callers should set cmds_max to the largest total number (mgmt + scsi) of * tasks they support. The iscsi layer reserves ISCSI_MGMT_CMDS_MAX tasks * for nop handling and login/logout requests. */ @@ -3307,7 +3307,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) if (conn->ping_timeout && !conn->recv_timeout) { iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of " - "zero. Using 5 seconds\n."); + "zero. Using 5 seconds.\n"); conn->recv_timeout = 5; } From 2cc8a6cf8a801065b68550d5af33f62999ce15f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20=28The=20Capable=20Hub=29?= Date: Mon, 27 Apr 2026 19:45:46 +0200 Subject: [PATCH 18/56] scsi: mvsas: Don't emit __LINE__ in debug messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __LINE__ changes quite easily for cleanup commits. So when checking if a cleanup patch introduces changes to the resulting binary each usage of __LINE__ is source of annoyance. So instead of __FILE__ and __LINE__ emit __func__ to give at least some more indication about where the messages originates from than __FILE__ alone; with that and the actual message the situation should be clear enough. While at it reduce duplication by implementing mv_dprintk() using mv_printk(). Signed-off-by: Uwe Kleine-König (The Capable Hub) Link: https://patch.msgid.link/20260427174545.2014499-2-u.kleine-koenig@baylibre.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mvsas/mv_sas.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index 09ce3f2241f2..7521f969aa87 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -35,10 +35,10 @@ #define MVS_ID_NOT_MAPPED 0x7f #define WIDE_PORT_MAX_PHY 4 #define mv_printk(fmt, arg ...) \ - printk(KERN_DEBUG"%s %d:" fmt, __FILE__, __LINE__, ## arg) + printk(KERN_DEBUG "%s: " fmt, __func__, ## arg) #ifdef MV_DEBUG -#define mv_dprintk(format, arg...) \ - printk(KERN_DEBUG"%s %d:" format, __FILE__, __LINE__, ## arg) +#define mv_dprintk(fmt, arg...) \ + mv_printk(fmt, ## arg) #else #define mv_dprintk(format, arg...) no_printk(format, ## arg) #endif From 67b85a88265df19f049241d8c00571a5408f4eeb Mon Sep 17 00:00:00 2001 From: Yihang Li Date: Sat, 25 Apr 2026 16:20:56 +0800 Subject: [PATCH 19/56] scsi: hisi_sas: Add slave_destroy interface for v3 hw WARNING is triggered when executing link reset of remote PHY and rmmod SAS driver simultaneously. Following is the WARNING log: WARNING: CPU: 61 PID: 21818 at drivers/base/core.c:1347 __device_links_no_driver+0xb4/0xc0 Call trace: __device_links_no_driver+0xb4/0xc0 device_links_driver_cleanup+0xb0/0xfc __device_release_driver+0x198/0x23c device_release_driver+0x38/0x50 bus_remove_device+0x130/0x140 device_del+0x184/0x434 __scsi_remove_device+0x118/0x150 scsi_remove_target+0x1bc/0x240 sas_rphy_remove+0x90/0x94 sas_rphy_delete+0x24/0x3c sas_destruct_devices+0x64/0xa0 [libsas] sas_revalidate_domain+0xe4/0x150 [libsas] process_one_work+0x1e0/0x46c worker_thread+0x15c/0x464 kthread+0x160/0x170 ret_from_fork+0x10/0x20 ---[ end trace 71e059eb58f85d4a ]--- During SAS phy up, link->status is set to DL_STATE_AVAILABLE in device_links_driver_bound, then this setting influences __device_links_no_driver() before driver rmmod and caused WARNING. Add the slave_destroy interface to make sure link is removed after flush workque. Fixes: 16fd4a7c5917 ("scsi: hisi_sas: Add device link between SCSI devices and hisi_hba") Signed-off-by: Yihang Li Link: https://patch.msgid.link/20260425082056.2749910-1-liyihang9@huawei.com Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index fda07b193137..c7430f7c4048 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -2977,7 +2977,7 @@ static int sdev_configure_v3_hw(struct scsi_device *sdev, return 0; if (!device_link_add(&sdev->sdev_gendev, dev, - DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE)) { + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE)) { if (pm_runtime_enabled(dev)) { dev_info(dev, "add device link failed, disable runtime PM for the host\n"); pm_runtime_disable(dev); @@ -2987,6 +2987,15 @@ static int sdev_configure_v3_hw(struct scsi_device *sdev, return 0; } +static void hisi_sas_sdev_destroy(struct scsi_device *sdev) +{ + struct Scsi_Host *shost = dev_to_shost(&sdev->sdev_gendev); + struct hisi_hba *hisi_hba = shost_priv(shost); + struct device *dev = hisi_hba->dev; + + device_link_remove(&sdev->sdev_gendev, dev); +} + static struct attribute *host_v3_hw_attrs[] = { &dev_attr_phy_event_threshold.attr, &dev_attr_intr_conv_v3_hw.attr, @@ -3401,6 +3410,7 @@ static const struct scsi_host_template sht_v3_hw = { .sg_tablesize = HISI_SAS_SGE_PAGE_CNT, .sg_prot_tablesize = HISI_SAS_SGE_PAGE_CNT, .sdev_init = hisi_sas_sdev_init, + .sdev_destroy = hisi_sas_sdev_destroy, .shost_groups = host_v3_hw_groups, .sdev_groups = sdev_groups_v3_hw, .tag_alloc_policy_rr = true, From 2a8fbcfb04aa9db189bfa3842d4f586aecd0e631 Mon Sep 17 00:00:00 2001 From: Kumar Meiyappan Date: Thu, 16 Apr 2026 15:37:57 +0000 Subject: [PATCH 20/56] scsi: pm8001: Reject firmware update in fatal error state pm8001_store_update_fw() allows a firmware update request even when the controller has already entered a fatal error state. Firmware update is not valid once the controller is in that state, and attempting it can lead to a call trace. Reject the request early by checking controller_fatal_error, set the firmware status to FAIL_PARAMETERS, and return -EINVAL. Signed-off-by: Kumar Meiyappan Signed-off-by: Sagar Biradar Link: https://patch.msgid.link/20260416153757.414896-1-sagar.biradar@microchip.com Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_ctl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index cbfda8c04e95..bb38b2d63acb 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -826,6 +826,14 @@ static ssize_t pm8001_store_update_fw(struct device *cdev, goto out; } + if (pm8001_ha->controller_fatal_error) { + pm8001_dbg(pm8001_ha, FAIL, + "controller in fatal error state, firmware update rejected\n"); + pm8001_ha->fw_status = FAIL_PARAMETERS; + ret = -EINVAL; + goto out; + } + for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) { if (!memcmp(flash_command_table[i].command, cmd_ptr, strlen(cmd_ptr))) { From aa3b8f56ef27ed72394a752820abdec4608b731c Mon Sep 17 00:00:00 2001 From: Kumar Meiyappan Date: Thu, 16 Apr 2026 15:46:50 +0000 Subject: [PATCH 21/56] scsi: pm8001: Reject non-fatal dump when controller is crashed pm80xx_get_non_fatal_dump() can be called even after the controller has entered a fatal error state. In that case the forensic memory contents are not safe to access for a non-fatal dump request, and attempting to do so can trigger a call trace. Check controller_fatal_error before reading the non-fatal dump buffer and return -EINVAL when the controller is already in a crashed state. This prevents non-fatal dump collection from running in an invalid controller state. Signed-off-by: Kumar Meiyappan Signed-off-by: Sagar Biradar Link: https://patch.msgid.link/20260416154650.415624-1-sagar.biradar@microchip.com Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm80xx_hwi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 954f307352e6..2c0fa7ab33d2 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -401,6 +401,13 @@ ssize_t pm80xx_get_non_fatal_dump(struct device *cdev, char *buf_copy = buf; temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr; + + if (pm8001_ha->controller_fatal_error) { + pm8001_dbg(pm8001_ha, FAIL, + "non-fatal dump not available in fatal error state\n"); + return -EINVAL; + } + if (++pm8001_ha->non_fatal_count == 1) { if (pm8001_ha->chip_id == chip_8001) { snprintf(pm8001_ha->forensic_info.data_buf.direct_data, From e72323f3b09f9c890fa93a74197bbc290d39d981 Mon Sep 17 00:00:00 2001 From: Palash Kambar Date: Thu, 23 Apr 2026 15:50:22 +0530 Subject: [PATCH 22/56] scsi: ufs: core: Configure only active lanes during link The number of connected lanes detected during UFS link startup can be fewer than the lanes specified in the device tree. The current driver logic attempts to configure all lanes defined in the device tree, regardless of their actual availability. This mismatch may cause failures during power mode changes. Hence, Add a check during link startup to ensure that only the lanes actually discovered are considered valid. If a mismatch is detected, fail the initialization early, preventing the driver from entering an unsupported configuration that could cause power mode transition failures. Reviewed-by: Bart Van Assche Reviewed-by: Shawn Lin Reviewed-by: Manivannan Sadhasivam Signed-off-by: Palash Kambar Link: https://patch.msgid.link/20260423102023.3779489-2-palash.kambar@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index a6026cc4b2f4..1aad1c03c3fc 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5218,6 +5218,35 @@ void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val) } EXPORT_SYMBOL_GPL(ufshcd_update_evt_hist); +static int ufshcd_validate_link_params(struct ufs_hba *hba) +{ + int ret, val; + + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), + &val); + if (ret) + return ret; + + if (val != hba->lanes_per_direction) { + dev_err(hba->dev, "Tx lane mismatch [config,reported] [%d,%d]\n", + hba->lanes_per_direction, val); + return -ENOLINK; + } + + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), + &val); + if (ret) + return ret; + + if (val != hba->lanes_per_direction) { + dev_err(hba->dev, "Rx lane mismatch [config,reported] [%d,%d]\n", + hba->lanes_per_direction, val); + return -ENOLINK; + } + + return 0; +} + /** * ufshcd_link_startup - Initialize unipro link startup * @hba: per adapter instance @@ -5291,6 +5320,10 @@ static int ufshcd_link_startup(struct ufs_hba *hba) goto out; } + ret = ufshcd_validate_link_params(hba); + if (ret) + goto out; + /* Include any host controller configuration via UIC commands */ ret = ufshcd_vops_link_startup_notify(hba, POST_CHANGE); if (ret) From 76417038c4d61fc3d407625c0b9332942f13e142 Mon Sep 17 00:00:00 2001 From: Palash Kambar Date: Thu, 23 Apr 2026 15:50:23 +0530 Subject: [PATCH 23/56] scsi: ufs: ufs-qcom: Enable Auto Hibern8 clock request support On platforms that support Auto Hibern8 (AH8), the UFS controller can autonomously de-assert clk_req signals to the Global Clock Controller when entering the Hibern8 state. This allows Global Clock Controller (GCC) to gate unused clocks, improving power efficiency. Enable the Clock Request feature by setting the UFS_HW_CLK_CTRL_EN bit in the UFS_AH8_CFG register, as recommended in the Hardware Programming Guidelines. Reviewed-by: Manivannan Sadhasivam Signed-off-by: Palash Kambar Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260423102023.3779489-3-palash.kambar@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 10 ++++++++++ drivers/ufs/host/ufs-qcom.h | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index bc037db46624..c084ccc72523 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -705,6 +705,13 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, bool is_pre_scale_up, unsign return 0; } +static void ufs_qcom_link_startup_post_change(struct ufs_hba *hba) +{ + if (ufshcd_is_auto_hibern8_supported(hba)) + ufshcd_rmwl(hba, UFS_HW_CLK_CTRL_EN, UFS_HW_CLK_CTRL_EN, + UFS_AH8_CFG); +} + static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { @@ -730,6 +737,9 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, */ err = ufshcd_disable_host_tx_lcc(hba); + break; + case POST_CHANGE: + ufs_qcom_link_startup_post_change(hba); break; default: break; diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 5d083331a7f4..e20b3ca50577 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -268,6 +268,17 @@ enum { */ #define NUM_TX_R1W1 13 +/* bit definitions for UFS_AH8_CFG register */ +#define CC_UFS_SYS_CLK_REQ_EN BIT(2) +#define CC_UFS_ICE_CORE_CLK_REQ_EN BIT(3) +#define CC_UFS_UNIPRO_CORE_CLK_REQ_EN BIT(4) +#define CC_UFS_AUXCLK_REQ_EN BIT(5) + +#define UFS_HW_CLK_CTRL_EN (CC_UFS_SYS_CLK_REQ_EN |\ + CC_UFS_ICE_CORE_CLK_REQ_EN |\ + CC_UFS_UNIPRO_CORE_CLK_REQ_EN |\ + CC_UFS_AUXCLK_REQ_EN) + static inline void ufs_qcom_get_controller_revision(struct ufs_hba *hba, u8 *major, u16 *minor, u16 *step) From 016d484531e3169cd7bcb26e0ac2c5523080809f Mon Sep 17 00:00:00 2001 From: Piotr Zarycki Date: Thu, 23 Apr 2026 10:13:43 +0200 Subject: [PATCH 24/56] scsi: isci: Remove unused macro scu_get_command_request_logical_port() The macro scu_get_command_request_logical_port() has never been used since it was introduced. Signed-off-by: Piotr Zarycki Link: https://patch.msgid.link/20260423081343.1813002-1-piotr.zarycki@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/isci/scu_task_context.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/isci/scu_task_context.h b/drivers/scsi/isci/scu_task_context.h index 582d22d54689..e56cd0fdc35f 100644 --- a/drivers/scsi/isci/scu_task_context.h +++ b/drivers/scsi/isci/scu_task_context.h @@ -211,8 +211,6 @@ typedef enum { #define SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT 12 #define SCU_CONTEXT_COMMAND_LOGICAL_PORT_MASK 0x00007000 -#define scu_get_command_reqeust_logical_port(x) \ - ((x) & SCU_CONTEXT_COMMAND_LOGICAL_PORT_MASK) #define MAKE_SCU_CONTEXT_COMMAND_TYPE(type) \ From 09be9d404f42fd2e7d4d378cae07499879f837f4 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 17 May 2026 19:15:47 +0200 Subject: [PATCH 25/56] scsi: scsi_ioctl: Use strnlen() in scsi_ioctl_get_pci() Use strnlen() to limit string scanning to 20 characters. Reformat the code and use tabs instead of spaces while at it. [mkp: tweaked comment formatting] Signed-off-by: Thorsten Blum Reviewed-by: John Garry Link: https://patch.msgid.link/20260517171546.2304-2-thorsten.blum@linux.dev Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_ioctl.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 0ddc95bafc71..c14f81403a09 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -176,10 +176,13 @@ static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg) name = dev_name(dev); - /* compatibility with old ioctl which only returned - * 20 characters */ - return copy_to_user(arg, name, min(strlen(name), (size_t)20)) - ? -EFAULT: 0; + /* + * Compatibility with old ioctl which only returned 20 characters. + */ + if (copy_to_user(arg, name, strnlen(name, 20))) + return -EFAULT; + + return 0; } static int sg_get_version(int __user *p) From 8933fa6695aaea6559d3469581139a4c1f427369 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Fri, 1 May 2026 06:16:40 -0700 Subject: [PATCH 26/56] scsi: ufs: core: Add a quirk for extended TX EQTR Adapt L0L1L2L3 length Add a quirk to support TX Equalization Training (EQTR) using Adapt L0L1L2L3 length which is larger than what is allowed by M-PHY spec ver 6.0. Signed-off-by: Can Guo Reviewed-by: Bean Huo Reviewed-by: Bart Van Assche Reviewed-by: Peter Wang Reviewed-by: Ziqi Chen Link: https://patch.msgid.link/20260501131641.826258-2-can.guo@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-txeq.c | 8 ++++++-- include/ufs/ufshcd.h | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/ufs/core/ufs-txeq.c b/drivers/ufs/core/ufs-txeq.c index 4b264adfdf49..aa64f2bf4f1e 100644 --- a/drivers/ufs/core/ufs-txeq.c +++ b/drivers/ufs/core/ufs-txeq.c @@ -885,7 +885,9 @@ static int ufshcd_setup_tx_eqtr_adapt_length(struct ufs_hba *hba, if (adapt_l0l1l2l3_cap_local > ADAPT_L0L1L2L3_LENGTH_MAX) { dev_err(hba->dev, "local RX_HS_G%u_ADAPT_INITIAL_L0L1L2L3_CAP (0x%x) exceeds MAX\n", gear, adapt_l0l1l2l3_cap_local); - return -EINVAL; + + if (!(hba->quirks & UFSHCD_QUIRK_EXTENDED_TX_EQTR_ADAPT_LENGTH_L0L1L2L3)) + return -EINVAL; } ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PEERRXHSG6ADAPTINITIALL0L1L2L3), @@ -896,7 +898,9 @@ static int ufshcd_setup_tx_eqtr_adapt_length(struct ufs_hba *hba, if (adapt_l0l1l2l3_cap_peer > ADAPT_L0L1L2L3_LENGTH_MAX) { dev_err(hba->dev, "peer RX_HS_G%u_ADAPT_INITIAL_L0L1L2L3_CAP (0x%x) exceeds MAX\n", gear, adapt_l0l1l2l3_cap_peer); - return -EINVAL; + + if (!(hba->quirks & UFSHCD_QUIRK_EXTENDED_TX_EQTR_ADAPT_LENGTH_L0L1L2L3)) + return -EINVAL; } t_adapt_l0l1l2l3_local = adapt_cap_to_t_adapt_l0l1l2l3(adapt_l0l1l2l3_cap_local); diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index f48d6416e299..3eaae082329c 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -806,6 +806,13 @@ enum ufshcd_quirks { * delay after enabling VCC to ensure it's stable. */ UFSHCD_QUIRK_VCC_ON_DELAY = 1 << 27, + + /* + * This quirk indicates that Host supports TX Equalization Training + * (EQTR) using Adapt L0L1L2L3 length which is larger than what is + * allowed by M-PHY spec ver 6.0. + */ + UFSHCD_QUIRK_EXTENDED_TX_EQTR_ADAPT_LENGTH_L0L1L2L3 = 1 << 28, }; enum ufshcd_caps { From 0f51fd84684316375d5c191a1ec5e18743fb1601 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Fri, 1 May 2026 06:16:41 -0700 Subject: [PATCH 27/56] scsi: ufs: ufs-qcom: Use quirk EXTENDED_TX_EQTR_ADAPT_LENGTH_L0L1L2L3 Use UFSHCD_QUIRK_EXTENDED_TX_EQTR_ADAPT_LENGTH_L0L1L2L3 for UFS Hosts HW major version 0x7 & minor version 0x1. Signed-off-by: Can Guo Reviewed-by: Ziqi Chen Reviewed-by: Bean Huo Link: https://patch.msgid.link/20260501131641.826258-3-can.guo@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index c084ccc72523..2940d64a04ea 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1315,6 +1315,9 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) if (host->hw_ver.major > 0x3) hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; + if (host->hw_ver.major == 0x7 && host->hw_ver.minor == 0x1) + hba->quirks |= UFSHCD_QUIRK_EXTENDED_TX_EQTR_ADAPT_LENGTH_L0L1L2L3; + if (drvdata && drvdata->quirks) hba->quirks |= drvdata->quirks; } From f199cee401f7dc7280c8ed070d2433478253b665 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 20 May 2026 10:14:53 -0700 Subject: [PATCH 28/56] scsi: scsi_debug: Remove unused variable sdebug_any_injecting_opt The static variable sdebug_any_injecting_opt is no longer read. Commit 3a90a63d02b8 ("scsi: scsi_debug: every_nth triggered error injection") removed all code that reads this variable. Hence, also remove this variable itself. Remove SDEBUG_OPT_ALL_INJECTING because there is no code left that uses this constant if sdebug_any_injecting_opt is removed. This has been detected by building the scsi_debug driver with the git HEAD version of Clang and with W=1. Signed-off-by: Bart Van Assche Reviewed-by: John Garry Link: https://patch.msgid.link/20260520171454.4035623-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 1515495fd9ea..a2f85ee1ae57 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -233,13 +233,6 @@ struct tape_block { #define SDEBUG_OPT_UNALIGNED_WRITE 0x20000 #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \ SDEBUG_OPT_RESET_NOISE) -#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \ - SDEBUG_OPT_TRANSPORT_ERR | \ - SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \ - SDEBUG_OPT_SHORT_TRANSFER | \ - SDEBUG_OPT_HOST_BUSY | \ - SDEBUG_OPT_CMD_ABORT | \ - SDEBUG_OPT_UNALIGNED_WRITE) #define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \ SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR) @@ -955,7 +948,6 @@ static bool sdebug_removable = DEF_REMOVABLE; static bool sdebug_clustering; static bool sdebug_host_lock = DEF_HOST_LOCK; static bool sdebug_strict = DEF_STRICT; -static bool sdebug_any_injecting_opt; static bool sdebug_no_rwlock; static bool sdebug_verbose; static bool have_dif_prot; @@ -7528,7 +7520,6 @@ static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, return -EINVAL; sdebug_opts = opts; sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); - sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); if (sdebug_every_nth != 0) tweak_cmnd_count(); return length; @@ -7748,7 +7739,6 @@ static ssize_t opts_store(struct device_driver *ddp, const char *buf, opts_done: sdebug_opts = opts; sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); - sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); tweak_cmnd_count(); return count; } @@ -9659,7 +9649,6 @@ static int sdebug_driver_probe(struct device *dev) scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); - sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); if (sdebug_every_nth) /* need stats counters for every_nth */ sdebug_statistics = true; error = scsi_add_host(hpnt, &sdbg_host->dev); From c1f7275b613b5bb140efe22071167ed6c68c9a05 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 19 May 2026 22:21:24 +0200 Subject: [PATCH 29/56] scsi: megaraid_mbox: Reduce stack usage in megaraid_cmm_register() The megaraid_cmm_register() function has a local copy of mraid_mmadp_t on the stack that gets copied into the actual structure used at runtime. When -fsanitize=thread is enabled, this causes the per-function stack frame to grow beyond the warning limit: megaraid_mbox.c: In function 'megaraid_cmm_register': megaraid_mbox.c:3472:1: error: the frame size of 1312 bytes is larger than 1280 bytes [-Werror=frame-larger-than=] Refactor this by moving the allocation into the caller to save the extra on-stack copy of the structure. Signed-off-by: Arnd Bergmann Link: https://patch.msgid.link/20260519202143.1305850-1-arnd@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_mbox.c | 26 ++++++++++++++--------- drivers/scsi/megaraid/megaraid_mm.c | 30 +++++++-------------------- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 06cf94ee4e36..ce89032a5a74 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -3396,7 +3396,7 @@ static int megaraid_cmm_register(adapter_t *adapter) { mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - mraid_mmadp_t adp; + mraid_mmadp_t *adp; scb_t *scb; mbox_ccb_t *ccb; int rval; @@ -3404,11 +3404,16 @@ megaraid_cmm_register(adapter_t *adapter) // Allocate memory for the base list of scb for management module. adapter->uscb_list = kzalloc_objs(scb_t, MBOX_MAX_USER_CMDS); + adp = kzalloc_obj(*adp); - if (adapter->uscb_list == NULL) { + if (!adapter->uscb_list || !adp) { con_log(CL_ANN, (KERN_WARNING "megaraid: out of memory, %s %d\n", __func__, __LINE__)); + + kfree(adapter->uscb_list); + kfree(adp); + return -1; } @@ -3452,20 +3457,21 @@ megaraid_cmm_register(adapter_t *adapter) list_add_tail(&scb->list, &adapter->uscb_pool); } - adp.unique_id = adapter->unique_id; - adp.drvr_type = DRVRTYPE_MBOX; - adp.drvr_data = (unsigned long)adapter; - adp.pdev = adapter->pdev; - adp.issue_uioc = megaraid_mbox_mm_handler; - adp.timeout = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; - adp.max_kioc = MBOX_MAX_USER_CMDS; + adp->unique_id = adapter->unique_id; + adp->drvr_type = DRVRTYPE_MBOX; + adp->drvr_data = (unsigned long)adapter; + adp->pdev = adapter->pdev; + adp->issue_uioc = megaraid_mbox_mm_handler; + adp->timeout = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; + adp->max_kioc = MBOX_MAX_USER_CMDS; - if ((rval = mraid_mm_register_adp(&adp)) != 0) { + if ((rval = mraid_mm_register_adp(adp)) != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid mbox: did not register with CMM\n")); kfree(adapter->uscb_list); + kfree(adp); } return rval; diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index 538da0e98131..60db48dc8f3a 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -898,42 +898,28 @@ hinfo_to_cinfo(mraid_hba_info_t *hinfo, mcontroller_t *cinfo) /** * mraid_mm_register_adp - Registration routine for low level drivers - * @lld_adp : Adapter object + * @adapter : Adapter object */ int -mraid_mm_register_adp(mraid_mmadp_t *lld_adp) +mraid_mm_register_adp(mraid_mmadp_t *adapter) { - mraid_mmadp_t *adapter; mbox64_t *mbox_list; uioc_t *kioc; uint32_t rval; int i; - if (lld_adp->drvr_type != DRVRTYPE_MBOX) + if (adapter->drvr_type != DRVRTYPE_MBOX) return (-EINVAL); - adapter = kzalloc_obj(mraid_mmadp_t); - - if (!adapter) - return -ENOMEM; - - - adapter->unique_id = lld_adp->unique_id; - adapter->drvr_type = lld_adp->drvr_type; - adapter->drvr_data = lld_adp->drvr_data; - adapter->pdev = lld_adp->pdev; - adapter->issue_uioc = lld_adp->issue_uioc; - adapter->timeout = lld_adp->timeout; - adapter->max_kioc = lld_adp->max_kioc; adapter->quiescent = 1; /* * Allocate single blocks of memory for all required kiocs, * mailboxes and passthru structures. */ - adapter->kioc_list = kmalloc_objs(uioc_t, lld_adp->max_kioc); - adapter->mbox_list = kmalloc_objs(mbox64_t, lld_adp->max_kioc); + adapter->kioc_list = kmalloc_objs(uioc_t, adapter->max_kioc); + adapter->mbox_list = kmalloc_objs(mbox64_t, adapter->max_kioc); adapter->pthru_dma_pool = dma_pool_create("megaraid mm pthru pool", &adapter->pdev->dev, sizeof(mraid_passthru_t), @@ -956,11 +942,11 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp) */ INIT_LIST_HEAD(&adapter->kioc_pool); spin_lock_init(&adapter->kioc_pool_lock); - sema_init(&adapter->kioc_semaphore, lld_adp->max_kioc); + sema_init(&adapter->kioc_semaphore, adapter->max_kioc); mbox_list = (mbox64_t *)adapter->mbox_list; - for (i = 0; i < lld_adp->max_kioc; i++) { + for (i = 0; i < adapter->max_kioc; i++) { kioc = adapter->kioc_list + i; kioc->cmdbuf = (uint64_t)(unsigned long)(mbox_list + i); @@ -997,7 +983,7 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp) pthru_dma_pool_error: - for (i = 0; i < lld_adp->max_kioc; i++) { + for (i = 0; i < adapter->max_kioc; i++) { kioc = adapter->kioc_list + i; if (kioc->pthru32) { dma_pool_free(adapter->pthru_dma_pool, kioc->pthru32, From 727e78887e62e16be30ec7ecf62017f0a86d53bd Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 19 May 2026 14:21:27 -0700 Subject: [PATCH 30/56] scsi: ufs: core: Inline two functions related to UIC commands The implementation of the two functions ufshcd_get_uic_cmd_result() and ufshcd_get_dme_attr_val() is very short. Additionally, both functions only have one caller. Inline both functions to make the code shorter. Reviewed-by: Peter Wang Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260519212135.3130556-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 1aad1c03c3fc..f3e226e47c90 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -912,33 +912,6 @@ static inline int ufshcd_get_lists_status(u32 reg) return !((reg & UFSHCD_STATUS_READY) == UFSHCD_STATUS_READY); } -/** - * ufshcd_get_uic_cmd_result - Get the UIC command result - * @hba: Pointer to adapter instance - * - * This function gets the result of UIC command completion - * - * Return: 0 on success; non-zero value on error. - */ -static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba) -{ - return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) & - MASK_UIC_COMMAND_RESULT; -} - -/** - * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command - * @hba: Pointer to adapter instance - * - * This function gets UIC command argument3 - * - * Return: 0 on success; non-zero value on error. - */ -static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba) -{ - return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3); -} - /** * ufshcd_get_req_rsp - returns the TR response transaction type * @ucd_rsp_ptr: pointer to response UPIU @@ -5810,8 +5783,14 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status); if (intr_status & UIC_COMMAND_COMPL) { - cmd->argument2 |= ufshcd_get_uic_cmd_result(hba); - cmd->argument3 = ufshcd_get_dme_attr_val(hba); + /* + * Store the UIC command result in the lowest byte of + * cmd->argument2. + */ + cmd->argument2 |= ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) & + MASK_UIC_COMMAND_RESULT; + /* Store the DME attribute value in cmd->argument3. */ + cmd->argument3 = ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3); if (!hba->uic_async_done) cmd->cmd_active = false; complete(&cmd->done); From 9fb4c793223b618da6bee50840746522a7da226e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 19 May 2026 14:21:28 -0700 Subject: [PATCH 31/56] scsi: ufs: core: Complain if UIC argument 2 is invalid According to the UFSHCI standard, the lowest byte of UIC argument 2 is an output value. Additionally, ufshcd_uic_cmd_compl() is based on the assumption that the lowest byte of UIC argument 2 is zero. Hence, complain if the result byte is set when a UIC command is submitted. Reviewed-by: Peter Wang Signed-off-by: Bart Van Assche Link: https://patch.msgid.link/20260519212135.3130556-3-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index f3e226e47c90..cfb362fe9784 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2571,6 +2571,7 @@ ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) lockdep_assert_held(&hba->uic_cmd_mutex); WARN_ON(hba->active_uic_cmd); + WARN_ON_ONCE(uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT); hba->active_uic_cmd = uic_cmd; From f8380c57dcff5ac3b32393a05ff6a6ff0108bf3e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 19 May 2026 14:21:29 -0700 Subject: [PATCH 32/56] scsi: ufs: core: Optimize ufshcd_add_uic_command_trace() Use cached values in ufshcd_add_uic_command_trace() instead of calling readl() when tracing command submission (UFS_CMD_SEND). Signed-off-by: Bart Van Assche Reviewed-by: Peter Wang Link: https://patch.msgid.link/20260519212135.3130556-4-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index cfb362fe9784..c1a0a79e386d 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -460,20 +460,24 @@ static void ufshcd_add_uic_command_trace(struct ufs_hba *hba, const struct uic_command *ucmd, enum ufs_trace_str_t str_t) { - u32 cmd; + u32 cmd, arg1, arg2, arg3; if (!trace_ufshcd_uic_command_enabled()) return; - if (str_t == UFS_CMD_SEND) + if (str_t == UFS_CMD_SEND) { cmd = ucmd->command; - else + arg1 = ucmd->argument1; + arg2 = ucmd->argument2; + arg3 = ucmd->argument3; + } else { cmd = ufshcd_readl(hba, REG_UIC_COMMAND); + arg1 = ufshcd_readl(hba, REG_UIC_COMMAND_ARG_1); + arg2 = ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2); + arg3 = ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3); + } - trace_ufshcd_uic_command(hba, str_t, cmd, - ufshcd_readl(hba, REG_UIC_COMMAND_ARG_1), - ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2), - ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3)); + trace_ufshcd_uic_command(hba, str_t, cmd, arg1, arg2, arg3); } static void ufshcd_add_command_trace(struct ufs_hba *hba, struct scsi_cmnd *cmd, From b1968f46509e077d3241ac509e41fd14ec2395db Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 15 May 2026 13:52:19 -0700 Subject: [PATCH 33/56] scsi: core: target: Add INQUIRY-related constants to scsi_common.h Move three constants from target/target_core_base.h into scsi/scsi_common.h. Add three new constants in the scsi_common.h header file. This patch prepares for using these constants in the SCSI core. Signed-off-by: Bart Van Assche Tested-by: Brian Bunker Link: https://patch.msgid.link/20260515205222.1754621-2-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- include/scsi/scsi_common.h | 8 ++++++++ include/target/target_core_base.h | 5 +---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/scsi/scsi_common.h b/include/scsi/scsi_common.h index fb58715fac86..00c8a16d3cd2 100644 --- a/include/scsi/scsi_common.h +++ b/include/scsi/scsi_common.h @@ -10,6 +10,14 @@ #include #include +/* From the standard INQUIRY data description in SPC-6. */ +#define INQUIRY_VENDOR_OFFSET 8 +#define INQUIRY_VENDOR_LEN 8 +#define INQUIRY_MODEL_OFFSET 16 +#define INQUIRY_MODEL_LEN 16 +#define INQUIRY_REVISION_OFFSET 32 +#define INQUIRY_REVISION_LEN 4 + enum scsi_pr_type { SCSI_PR_WRITE_EXCLUSIVE = 0x01, SCSI_PR_EXCLUSIVE_ACCESS = 0x03, diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 9a0e9f9e1ec4..002b0fc57587 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -8,6 +8,7 @@ #include #include /* struct semaphore */ #include +#include #define TARGET_CORE_VERSION "v5.0" @@ -46,10 +47,6 @@ /* Used by transport_get_inquiry_vpd_device_ident() */ #define INQUIRY_VPD_DEVICE_IDENTIFIER_LEN 254 -#define INQUIRY_VENDOR_LEN 8 -#define INQUIRY_MODEL_LEN 16 -#define INQUIRY_REVISION_LEN 4 - /* Attempts before moving from SHORT to LONG */ #define PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD 3 #define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT 3 /* In milliseconds */ From 28ff38b9d8e1a189606e36319401dc98419a3746 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 15 May 2026 13:52:20 -0700 Subject: [PATCH 34/56] scsi: core: Use the INQUIRY-related constants Use symbolic names instead of numeric constants to access the vendor and model information. Signed-off-by: Bart Van Assche Tested-by: Brian Bunker Link: https://patch.msgid.link/20260515205222.1754621-3-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index a35a5f777d16..b0473f4595c1 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -728,9 +728,13 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, } if (result == 0) { - scsi_sanitize_inquiry_string(&inq_result[8], 8); - scsi_sanitize_inquiry_string(&inq_result[16], 16); - scsi_sanitize_inquiry_string(&inq_result[32], 4); + scsi_sanitize_inquiry_string(&inq_result[INQUIRY_VENDOR_OFFSET], + INQUIRY_VENDOR_LEN); + scsi_sanitize_inquiry_string(&inq_result[INQUIRY_MODEL_OFFSET], + INQUIRY_MODEL_LEN); + scsi_sanitize_inquiry_string( + &inq_result[INQUIRY_REVISION_OFFSET], + INQUIRY_REVISION_LEN); response_len = inq_result[4] + 5; if (response_len > 255) @@ -743,8 +747,9 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, * corresponding bit fields in scsi_device, so bflags * need not be passed as an argument. */ - *bflags = scsi_get_device_flags(sdev, &inq_result[8], - &inq_result[16]); + *bflags = scsi_get_device_flags(sdev, + &inq_result[INQUIRY_VENDOR_OFFSET], + &inq_result[INQUIRY_MODEL_OFFSET]); /* When the first pass succeeds we gain information about * what larger transfer lengths might work. */ From 20fd1648f35399f114351b67c14ff8d3233a30e2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 15 May 2026 13:52:21 -0700 Subject: [PATCH 35/56] scsi: core: Convert INQUIRY information Currently the vendor, model, and revision members of struct scsi_device are pointers to fixed-length strings that are not NUL-terminated. Fixed-precision format specifiers (e.g., "%.8s") are required whenever they are printed and strncmp() must be used to compare these fields. This is error-prone. Convert these fields to fixed-size character arrays within struct scsi_device. Remove an !sdev->model check because sdev->model is now guaranteed not to be NULL. This patch fixes a bug in the qla2xxx driver. It makes the following code safe: if (state_flags & BIT_4) scmd_printk(KERN_WARNING, cp, "Unsupported device '%s' found.\n", cp->device->vendor); Signed-off-by: Bart Van Assche Tested-by: Brian Bunker Link: https://patch.msgid.link/20260515205222.1754621-4-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/hwmon/drivetemp.c | 5 +---- drivers/scsi/scsi_scan.c | 18 ++++++++++++------ include/scsi/scsi_device.h | 7 ++++--- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/hwmon/drivetemp.c b/drivers/hwmon/drivetemp.c index 002e0660a0b8..efe8b229bdbe 100644 --- a/drivers/hwmon/drivetemp.c +++ b/drivers/hwmon/drivetemp.c @@ -306,13 +306,10 @@ static bool drivetemp_sct_avoid(struct drivetemp_data *st) struct scsi_device *sdev = st->sdev; unsigned int ctr; - if (!sdev->model) - return false; - /* * The "model" field contains just the raw SCSI INQUIRY response * "product identification" field, which has a width of 16 bytes. - * This field is space-filled, but is NOT NULL-terminated. + * This field is space-filled and NUL-terminated. */ for (ctr = 0; ctr < ARRAY_SIZE(sct_avoid_models); ctr++) if (!strncmp(sdev->model, sct_avoid_models[ctr], diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index b0473f4595c1..7e60e3a4bca6 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -292,9 +292,9 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, if (!sdev) goto out; - sdev->vendor = scsi_null_device_strs; - sdev->model = scsi_null_device_strs; - sdev->rev = scsi_null_device_strs; + strscpy(sdev->vendor, scsi_null_device_strs); + strscpy(sdev->model, scsi_null_device_strs); + strscpy(sdev->rev, scsi_null_device_strs); sdev->host = shost; sdev->queue_ramp_up_period = SCSI_DEFAULT_RAMP_UP_PERIOD; sdev->id = starget->id; @@ -910,9 +910,15 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, if (sdev->inquiry == NULL) return SCSI_SCAN_NO_RESPONSE; - sdev->vendor = (char *) (sdev->inquiry + 8); - sdev->model = (char *) (sdev->inquiry + 16); - sdev->rev = (char *) (sdev->inquiry + 32); + strscpy(sdev->vendor, sdev->inquiry + INQUIRY_VENDOR_OFFSET); + strscpy(sdev->model, sdev->inquiry + INQUIRY_MODEL_OFFSET); + /* + * memcpy() instead of strscpy() because strscpy() would read past + * the end of sdev->inquiry if its length is exactly 36 bytes. + */ + memcpy(sdev->rev, sdev->inquiry + INQUIRY_REVISION_OFFSET, + INQUIRY_REVISION_LEN); + sdev->rev[INQUIRY_REVISION_LEN] = '\0'; sdev->is_ata = strncmp(sdev->vendor, "ATA ", 8) == 0; if (sdev->is_ata) { diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 9c2a7bbe5891..029f5115b2ea 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -137,9 +138,9 @@ struct scsi_device { struct mutex inquiry_mutex; unsigned char inquiry_len; /* valid bytes in 'inquiry' */ unsigned char * inquiry; /* INQUIRY response data */ - const char * vendor; /* [back_compat] point into 'inquiry' ... */ - const char * model; /* ... after scan; point to static string */ - const char * rev; /* ... "nullnullnullnull" before scan */ + char vendor[INQUIRY_VENDOR_LEN + 1]; + char model[INQUIRY_MODEL_LEN + 1]; + char rev[INQUIRY_REVISION_LEN + 1]; #define SCSI_DEFAULT_VPD_LEN 255 /* default SCSI VPD page size (max) */ struct scsi_vpd __rcu *vpd_pg0; From 57db1307afb1f83d45f5ff53b93f8d040100d13e Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Wed, 13 May 2026 19:42:35 +0200 Subject: [PATCH 36/56] scsi: smartpqi: Use shost_to_hba() in pqi_scan_finished() shost_to_hba() is used everywhere except to obtain pqi_ctrl_info from shosti, except in pqi_scan_finished(), where shost_priv() is used. This causes one pointer dereference to be missed, as shost->hostdata is a pointer in smartpqi. Fix it. Fixes: 6c223761eb54 ("smartpqi: initial commit of Microsemi smartpqi driver") Signed-off-by: Martin Wilck Reviewed-by: Don Brace Cc: Don Brace Cc: storagedev@microchip.com Cc: stable@vger.kernel.org Reviewed-by: Hannes Reinecke Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Link: https://patch.msgid.link/20260513174236.430465-2-mwilck@suse.com Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index b4ed991976d0..65ff50982978 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -2642,7 +2642,7 @@ static int pqi_scan_finished(struct Scsi_Host *shost, { struct pqi_ctrl_info *ctrl_info; - ctrl_info = shost_priv(shost); + ctrl_info = shost_to_hba(shost); return !mutex_is_locked(&ctrl_info->scan_mutex); } From 8c292e89bd831c8a13e92f3429ef66bbe0b83677 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Wed, 13 May 2026 19:42:36 +0200 Subject: [PATCH 37/56] scsi: Revert "scsi: Fix sas_user_scan() to handle wildcard and multi-channel scans" This reverts commit 37c4e72b0651e7697eb338cd1fb09feef472cc1a. Said commit causes excessive resource usage and even system freeze with some controllers, e.g. smartpqi and hisi_sas. The justification provided by the patch authors [1] was supporting a special mode of the mpi3mr and mpt3sas, so-called "Tri-mode", in which NVMe drives are exposed as SCSI devices on a separate channel. While that's useful for these drivers, it seems wrong to cause major breakage for other drivers for the sake of this feature. [1] https://lore.kernel.org/linux-scsi/CAFdVvOwjy+2ORJ6uJkspiLTPF05481U7gcS4QohFOFGPqAs8ig@mail.gmail.com/ Fixes: 37c4e72b0651 ("scsi: Fix sas_user_scan() to handle wildcard and multi-channel scans") Signed-off-by: Martin Wilck Cc: Don Brace Cc: storagedev@microchip.com Cc: Ranjan Kumar Cc: Sathya Prakash Veerichetty Cc: Kashyap Desai Cc: Sumit Saxena Cc: mpi3mr-linuxdrv.pdl@broadcom.com Cc: MPT-FusionLinux.pdl@broadcom.com Cc: Yihang Li Reviewed-by: Christoph Hellwig Link: https://patch.msgid.link/20260513174236.430465-3-mwilck@suse.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 2 +- drivers/scsi/scsi_transport_sas.c | 60 +++++++------------------------ 2 files changed, 13 insertions(+), 49 deletions(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 7e60e3a4bca6..e27da038603a 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1921,7 +1921,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, return 0; } -EXPORT_SYMBOL(scsi_scan_host_selected); + static void scsi_sysfs_add_devices(struct Scsi_Host *shost) { struct scsi_device *sdev; diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 13412702188e..d8f2377b017f 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -40,8 +40,6 @@ #include #include "scsi_sas_internal.h" -#include "scsi_priv.h" - struct sas_host_attrs { struct list_head rphy_list; struct mutex lock; @@ -1685,22 +1683,6 @@ int scsi_is_sas_rphy(const struct device *dev) } EXPORT_SYMBOL(scsi_is_sas_rphy); -static void scan_channel_zero(struct Scsi_Host *shost, uint id, u64 lun) -{ - struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); - struct sas_rphy *rphy; - - list_for_each_entry(rphy, &sas_host->rphy_list, list) { - if (rphy->identify.device_type != SAS_END_DEVICE || - rphy->scsi_target_id == -1) - continue; - - if (id == SCAN_WILD_CARD || id == rphy->scsi_target_id) { - scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, - lun, SCSI_SCAN_MANUAL); - } - } -} /* * SCSI scan helper @@ -1710,41 +1692,23 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, uint id, u64 lun) { struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); - int res = 0; - int i; + struct sas_rphy *rphy; - switch (channel) { - case 0: - mutex_lock(&sas_host->lock); - scan_channel_zero(shost, id, lun); - mutex_unlock(&sas_host->lock); - break; + mutex_lock(&sas_host->lock); + list_for_each_entry(rphy, &sas_host->rphy_list, list) { + if (rphy->identify.device_type != SAS_END_DEVICE || + rphy->scsi_target_id == -1) + continue; - case SCAN_WILD_CARD: - mutex_lock(&sas_host->lock); - scan_channel_zero(shost, id, lun); - mutex_unlock(&sas_host->lock); - - for (i = 1; i <= shost->max_channel; i++) { - res = scsi_scan_host_selected(shost, i, id, lun, - SCSI_SCAN_MANUAL); - if (res) - goto exit_scan; + if ((channel == SCAN_WILD_CARD || channel == 0) && + (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { + scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, + lun, SCSI_SCAN_MANUAL); } - break; - - default: - if (channel <= shost->max_channel) { - res = scsi_scan_host_selected(shost, channel, id, lun, - SCSI_SCAN_MANUAL); - } else { - res = -EINVAL; - } - break; } + mutex_unlock(&sas_host->lock); -exit_scan: - return res; + return 0; } From be8fcd4a8217a916344c88a4b1b84f5736dda17e Mon Sep 17 00:00:00 2001 From: Ionut Nechita Date: Tue, 19 May 2026 16:52:33 +0300 Subject: [PATCH 38/56] scsi: sas: Skip opt_sectors when DMA reports no real optimization hint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sas_host_setup() unconditionally sets shost->opt_sectors from dma_opt_mapping_size(). When the IOMMU is disabled or in passthrough mode and no DMA ops provide an opt_mapping_size callback, dma_opt_mapping_size() returns min(dma_max_mapping_size(), SIZE_MAX) which equals dma_max_mapping_size() — a hard upper bound, not an optimization hint. On a Dell PowerEdge R750 with mpt3sas (Broadcom SAS3816, FW 33.15.00.00) and intel_iommu=off the following values are observed: dma_opt_mapping_size() = dma_max_mapping_size() (no real hint) shost->max_sectors = 32767 opt_sectors = min(32767, huge >> 9) = 32767 optimal_io_size = 32767 << 9 = 16776704 → round_down(16776704, 4096) = 16773120 The SAS disk (SAMSUNG MZILT800HBHQ0D3) does not report an Optimal Transfer Length in VPD page B0, so sdkp->opt_xfer_blocks remains 0. sd_revalidate_disk() then uses min_not_zero(0, opt_sectors) = opt_sectors, propagating the bogus value into the block device's optimal_io_size (visible as OPT-IO = 16773120 in lsblk --topology). mkfs.xfs picks up optimal_io_size and minimum_io_size and computes: swidth = 16773120 / 4096 = 4095 sunit = 8192 / 4096 = 2 Since 4095 % 2 != 0, XFS rejects the geometry: SB stripe unit sanity check failed This makes it impossible to create XFS filesystems (e.g. for /var/lib/docker) during system bootstrap. Fix this by introducing a sas_dma_setup_opt_sectors() helper that sets opt_sectors only when dma_opt_mapping_size() is strictly less than dma_max_mapping_size(), indicating a genuine DMA optimization constraint. The helper computes min(opt_sectors, max_sectors) first, then rounds down to a power of two so that filesystem geometry calculations always produce clean results. When the two DMA values are equal, no backend provided a real hint, so opt_sectors stays at 0 ("no preference"). [mkp: implemented hch's suggestion] Fixes: 4cbfca5f7750 ("scsi: scsi_transport_sas: cap shost opt_sectors according to DMA optimal limit") Cc: stable@vger.kernel.org Reviewed-by: John Garry Signed-off-by: Ionut Nechita Reviewed-by: Christoph Hellwig Link: https://patch.msgid.link/20260519135238.373784-2-ionut.nechita@windriver.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_transport_sas.c | 41 +++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index d8f2377b017f..d689b9ed08a6 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -220,12 +221,45 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) * SAS host attributes */ +/* + * Set shost->opt_sectors from the DMA optimal mapping size, but only + * when dma_opt_mapping_size() is strictly less than dma_max_mapping_size(), + * indicating a genuine optimization hint from an IOMMU or DMA backend. + * When the two are equal (e.g. IOMMU disabled / passthrough), no real + * hint exists, so leave opt_sectors at 0 to avoid bogus optimal_io_size + * values that break filesystem geometry (e.g. mkfs.xfs stripe alignment). + */ +static void sas_dma_setup_opt_sectors(struct Scsi_Host *shost) +{ + struct device *dma_dev = shost->dma_dev; + size_t opt = dma_opt_mapping_size(dma_dev); + size_t max = dma_max_mapping_size(dma_dev); + unsigned int opt_sectors; + + /* opt >= max means no real hint was provided by the DMA layer */ + if (opt >= max) + return; + + /* Clamp to max_sectors to avoid overflow in sector arithmetic */ + opt_sectors = min_t(unsigned int, opt >> SECTOR_SHIFT, + shost->max_sectors); + + /* Guard against zero before rounddown_pow_of_two() */ + if (!opt_sectors) + return; + + /* + * Round down to power-of-two so filesystem geometry calculations + * (e.g. XFS stripe width/unit) always produce clean divisors. + */ + shost->opt_sectors = rounddown_pow_of_two(opt_sectors); +} + static int sas_host_setup(struct transport_container *tc, struct device *dev, struct device *cdev) { struct Scsi_Host *shost = dev_to_shost(dev); struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); - struct device *dma_dev = shost->dma_dev; INIT_LIST_HEAD(&sas_host->rphy_list); mutex_init(&sas_host->lock); @@ -237,10 +271,7 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev, dev_printk(KERN_ERR, dev, "fail to a bsg device %d\n", shost->host_no); - if (dma_dev->dma_mask) { - shost->opt_sectors = min_t(unsigned int, shost->max_sectors, - dma_opt_mapping_size(dma_dev) >> SECTOR_SHIFT); - } + sas_dma_setup_opt_sectors(shost); return 0; } From 06a34d9c1f47b923bb554de25406a5251b047379 Mon Sep 17 00:00:00 2001 From: Daejun Park Date: Wed, 20 May 2026 16:00:09 +0900 Subject: [PATCH 39/56] scsi: ufs: core: Skip link param validation when lanes_per_direction is unset ufshcd_validate_link_params(), added by commit e72323f3b09f ("scsi: ufs: core: Configure only active lanes during link"), is called unconditionally from ufshcd_link_startup() and fails link startup with -ENOLINK when the connected lane count read from the device differs from hba->lanes_per_direction. lanes_per_direction is only set by ufshcd-pltfrm (default 2, or the "lanes-per-direction" devicetree property); ufshcd-pci controllers (e.g. Intel) leave it 0. As the device always reports >= 1 connected lanes, the check can never match and link startup always fails. Reproduced with QEMU's UFS device. Skip the check when lanes_per_direction is unset: with no expected value to validate against, restore the behaviour from before that commit. Fixes: e72323f3b09f ("scsi: ufs: core: Configure only active lanes during link") Signed-off-by: Daejun Park Reviewed-by: Bart Van Assche Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20260520070009epcms2p6542f3abb7660839e9d8140b3f2f145c3@epcms2p6 Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index c1a0a79e386d..1061e20786fa 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5200,6 +5200,16 @@ static int ufshcd_validate_link_params(struct ufs_hba *hba) { int ret, val; + /* + * lanes_per_direction is only populated by the platform glue (it + * defaults to 2 or is read from the "lanes-per-direction" devicetree + * property). Controllers probed via ufshcd-pci leave it unset (0), in + * which case there is no expected lane count to validate the connected + * lanes against. Skip the check instead of failing link startup. + */ + if (!hba->lanes_per_direction) + return 0; + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), &val); if (ret) From 056fca1f276fa41792838d5eb88e316dd81c982d Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Fri, 22 May 2026 22:02:41 -0700 Subject: [PATCH 40/56] scsi: lpfc: Turn lpfc_queue q_pgs into a flexible array The q_pgs pointer was assigned to point at the trailing memory allocated past the struct. Convert it to a proper C99 flexible array member and use struct_size() for the allocation. Assisted-by: Claude:Opus-4.7 Signed-off-by: Rosen Penev Reviewed-by: Justin Tee Link: https://patch.msgid.link/20260523050241.190239-1-rosenp@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 3 +-- drivers/scsi/lpfc/lpfc_sli4.h | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index d38fb374b379..0e56e7034566 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -15875,7 +15875,7 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size, if (pgcnt > phba->sli4_hba.pc_sli4_params.wqpcnt) pgcnt = phba->sli4_hba.pc_sli4_params.wqpcnt; - queue = kzalloc_node(sizeof(*queue) + (sizeof(void *) * pgcnt), + queue = kzalloc_node(struct_size(queue, q_pgs, pgcnt), GFP_KERNEL, cpu_to_node(cpu)); if (!queue) return NULL; @@ -15892,7 +15892,6 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size, * resources, the free routine needs to know what was allocated. */ queue->page_count = pgcnt; - queue->q_pgs = (void **)&queue[1]; queue->entry_cnt_per_pg = hw_page_size / entry_size; queue->entry_size = entry_size; queue->entry_count = entry_count; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 2744786d9c94..e2b95fb50d55 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -280,9 +280,10 @@ struct lpfc_queue { uint64_t isr_timestamp; struct lpfc_queue *assoc_qp; struct list_head _poll_list; - void **q_pgs; /* array to index entries per page */ enum lpfc_poll_mode poll_mode; + + void *q_pgs[]; /* array to index entries per page */ }; struct lpfc_sli4_link { From 1b6f03b7ae9ee27054c55bb55a69d05555a78516 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 30 May 2026 22:45:48 +0300 Subject: [PATCH 41/56] scsi: pm8001: Fix error code in non_fatal_log_show() The non_fatal_log_show() function is supposed to return negative error codes on failure. But because the error codes are saved in a u32 and then cast to signed long, they end up being high positive values instead of negative. Remove the intermediary u32 variable to fix this bug. Fixes: dba2cc03b9db ("scsi: pm80xx: sysfs attribute for non fatal dump") Signed-off-by: Dan Carpenter Acked-by: Jack Wang Link: https://patch.msgid.link/ahs-bEsBJH0KhnsX@stanley.mountain Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_ctl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index bb38b2d63acb..a27f3287748e 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -588,10 +588,7 @@ static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL); static ssize_t non_fatal_log_show(struct device *cdev, struct device_attribute *attr, char *buf) { - u32 count; - - count = pm80xx_get_non_fatal_dump(cdev, attr, buf); - return count; + return pm80xx_get_non_fatal_dump(cdev, attr, buf); } static DEVICE_ATTR_RO(non_fatal_log); From c39a9a02bc5d841c116dc03c264eb9ceecde806e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 1 Jun 2026 23:02:04 +0200 Subject: [PATCH 42/56] scsi: megaraid_mbox: Avoid double kfree() Smatch found a double-free after my recent change: drivers/scsi/megaraid/megaraid_mbox.c:3474 megaraid_cmm_register() error: double free of 'adp' (line 3468) Since the object is no longer allocated in megaraid_cmm_register(), remove the kfree() as well. Fixes: c1f7275b613b ("scsi: megaraid_mbox: Reduce stack usage in megaraid_cmm_register()") Reported-by: Dan Carpenter Signed-off-by: Arnd Bergmann Link: https://patch.msgid.link/20260601210216.846809-1-arnd@kernel.org Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_mm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index 60db48dc8f3a..e572665903d2 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -998,8 +998,6 @@ mraid_mm_register_adp(mraid_mmadp_t *adapter) dma_pool_destroy(adapter->pthru_dma_pool); - kfree(adapter); - return rval; } From 4cf752f6b99ab63506cde5a611d4219e97adbd84 Mon Sep 17 00:00:00 2001 From: Chanwoo Lee Date: Fri, 29 May 2026 10:07:39 +0900 Subject: [PATCH 43/56] scsi: ufs: core: Fix NULL pointer dereference in scsi_cmd_priv() calls ufshcd_tag_to_cmd() may return NULL if no command is associated with the given tag. However, several callers dereference the returned cmd pointer via scsi_cmd_priv() without checking for NULL first, leading to a potential NULL pointer dereference. Fix this by adding NULL checks for cmd before calling scsi_cmd_priv() and moving the lrbp initialization after the NULL check. Signed-off-by: Chanwoo Lee Reviewed-by: Peter Wang Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260529010739.295391-1-cw9316.lee@samsung.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-mcq.c | 7 ++++++- drivers/ufs/core/ufshcd.c | 13 +++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index c1b1d67a1ddc..13b60a2d06db 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -637,7 +637,7 @@ static bool ufshcd_mcq_sqe_search(struct ufs_hba *hba, struct ufs_hw_queue *hwq, int task_tag) { struct scsi_cmnd *cmd = ufshcd_tag_to_cmd(hba, task_tag); - struct ufshcd_lrb *lrbp = scsi_cmd_priv(cmd); + struct ufshcd_lrb *lrbp; struct utp_transfer_req_desc *utrd; __le64 cmd_desc_base_addr; bool ret = false; @@ -647,6 +647,11 @@ static bool ufshcd_mcq_sqe_search(struct ufs_hba *hba, if (hba->quirks & UFSHCD_QUIRK_MCQ_BROKEN_RTC) return true; + if (!cmd) + return false; + + lrbp = scsi_cmd_priv(cmd); + mutex_lock(&hwq->sq_mutex); ufshcd_mcq_sq_stop(hba, hwq); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 1061e20786fa..9b6cb6b569bc 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -7903,8 +7903,12 @@ static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long bitmap) for_each_set_bit(tag, &bitmap, hba->nutrs) { struct scsi_cmnd *cmd = ufshcd_tag_to_cmd(hba, tag); - struct ufshcd_lrb *lrbp = scsi_cmd_priv(cmd); + struct ufshcd_lrb *lrbp; + if (!cmd) + continue; + + lrbp = scsi_cmd_priv(cmd); lrbp->req_abort_skip = true; } } @@ -7925,11 +7929,16 @@ static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long bitmap) int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) { struct scsi_cmnd *cmd = ufshcd_tag_to_cmd(hba, tag); - struct ufshcd_lrb *lrbp = scsi_cmd_priv(cmd); + struct ufshcd_lrb *lrbp; int err; int poll_cnt; u8 resp = 0xF; + if (!cmd) + return -EINVAL; + + lrbp = scsi_cmd_priv(cmd); + for (poll_cnt = 100; poll_cnt; poll_cnt--) { err = ufshcd_issue_tm_cmd(hba, lrbp->lun, tag, UFS_QUERY_TASK, &resp); From 2483ae0a56231a915c706411421c6c002a2bf83e Mon Sep 17 00:00:00 2001 From: Chanwoo Lee Date: Wed, 27 May 2026 18:21:34 +0900 Subject: [PATCH 44/56] scsi: ufs: Fix wrong value printed in unexpected UPIU response case In ufshcd_transfer_rsp_status(), the default case of the inner switch statement prints the UPIU response code when an unexpected response is received. However, the code was printing 'result' variable which is always 0 at that point, making the error message useless for debugging. Fix this by printing the actual UPIU response code returned by ufshcd_get_req_rsp(). Fixes: 08108d31129a ("scsi: ufs: Improve type safety") Signed-off-by: Chanwoo Lee Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260527092134.275887-1-cw9316.lee@samsung.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 9b6cb6b569bc..3441e874eacc 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -5716,7 +5716,7 @@ static inline int ufshcd_transfer_rsp_status(struct ufs_hba *hba, default: dev_err(hba->dev, "Unexpected request response code = %x\n", - result); + ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr)); result = DID_ERROR << 16; break; } From 6bfc4bfd041d7ddeab9791f0592284585e960be4 Mon Sep 17 00:00:00 2001 From: Chanwoo Lee Date: Fri, 29 May 2026 15:15:00 +0900 Subject: [PATCH 45/56] scsi: ufs: Remove unnecessary return in void vops wrappers ufshcd_vops_exit(), ufshcd_vops_setup_task_mgmt(), and ufshcd_vops_hibern8_notify() use 'return hba->vops->xxx()' while other void vops wrappers call without return. Remove the unnecessary return keywords for consistency. Signed-off-by: Chanwoo Lee Reviewed-by: Peter Wang Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260529061503.301182-1-cw9316.lee@samsung.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd-priv.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 70f90d97f217..e55c2a02c1f5 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -132,7 +132,7 @@ static inline const char *ufshcd_get_var_name(struct ufs_hba *hba) static inline void ufshcd_vops_exit(struct ufs_hba *hba) { if (hba->vops && hba->vops->exit) - return hba->vops->exit(hba); + hba->vops->exit(hba); } static inline u32 ufshcd_vops_get_ufs_hci_version(struct ufs_hba *hba) @@ -211,7 +211,7 @@ static inline void ufshcd_vops_setup_task_mgmt(struct ufs_hba *hba, int tag, u8 tm_function) { if (hba->vops && hba->vops->setup_task_mgmt) - return hba->vops->setup_task_mgmt(hba, tag, tm_function); + hba->vops->setup_task_mgmt(hba, tag, tm_function); } static inline void ufshcd_vops_hibern8_notify(struct ufs_hba *hba, @@ -219,7 +219,7 @@ static inline void ufshcd_vops_hibern8_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { if (hba->vops && hba->vops->hibern8_notify) - return hba->vops->hibern8_notify(hba, cmd, status); + hba->vops->hibern8_notify(hba, cmd, status); } static inline int ufshcd_vops_apply_dev_quirks(struct ufs_hba *hba) From 0600eec09ad6cc5ba3ca78aceb6fa8dcbad010bb Mon Sep 17 00:00:00 2001 From: Chanwoo Lee Date: Fri, 29 May 2026 15:16:19 +0900 Subject: [PATCH 46/56] scsi: ufs: Remove redundant vops NULL check and trivial wrapper ufshcd_variant_hba_init/exit() check 'if (!hba->vops)' before calling vops wrappers, but the wrappers already do NULL check internally. Remove the redundant checks. Also remove ufshcd_variant_hba_exit() entirely since it only wraps ufshcd_vops_exit() with no added value. Signed-off-by: Chanwoo Lee Reviewed-by: Peter Wang Reviewed-by: Bart Van Assche Link: https://patch.msgid.link/20260529061623.301291-1-cw9316.lee@samsung.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 3441e874eacc..60ec2c63c2d8 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -9854,28 +9854,15 @@ static int ufshcd_init_clocks(struct ufs_hba *hba) static int ufshcd_variant_hba_init(struct ufs_hba *hba) { - int err = 0; + int err = ufshcd_vops_init(hba); - if (!hba->vops) - goto out; - - err = ufshcd_vops_init(hba); if (err) dev_err_probe(hba->dev, err, "%s: variant %s init failed with err %d\n", __func__, ufshcd_get_var_name(hba), err); -out: return err; } -static void ufshcd_variant_hba_exit(struct ufs_hba *hba) -{ - if (!hba->vops) - return; - - ufshcd_vops_exit(hba); -} - static int ufshcd_hba_init(struct ufs_hba *hba) { int err; @@ -9943,7 +9930,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba) if (hba->eh_wq) destroy_workqueue(hba->eh_wq); ufs_debugfs_hba_exit(hba); - ufshcd_variant_hba_exit(hba); + ufshcd_vops_exit(hba); ufshcd_setup_vreg(hba, false); ufshcd_setup_clocks(hba, false); ufshcd_setup_hba_vreg(hba, false); From b65b608eb8ff3507676491b28acaf496b1c347f2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 2 Jun 2026 10:51:25 -0700 Subject: [PATCH 47/56] scsi: mailmap: Update Avri Altman's email address Avri Altman's email address changed from @wdc.com into @sandisk.com. Add this information in the .mailmap file such that scripts/get_maintainer.pl produces the correct email address for UFS kernel patches. Cc: Avri Altman Cc: Avri Altman Signed-off-by: Bart Van Assche Acked-by: Avri Altman Link: https://patch.msgid.link/b71be634e78d3a51048ec28fac2eaedb52d6cb09.1780422652.git.bvanassche@acm.org Signed-off-by: Martin K. Petersen --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 34acd34bbf9b..d5844d97b3ff 100644 --- a/.mailmap +++ b/.mailmap @@ -116,6 +116,7 @@ Asutosh Das Atish Patra Atish Patra Avaneesh Kumar Dwivedi +Avri Altman Axel Dyks Axel Lin Balakrishna Godavarthi From 63977ab3c6a07e5f50c95d0c8fd83d37d56812a8 Mon Sep 17 00:00:00 2001 From: Palash Kambar Date: Tue, 26 May 2026 14:39:55 +0530 Subject: [PATCH 48/56] scsi: ufs: qcom: dt-bindings: Document the Hawi UFS controller Document the UFS Controller on the Hawi Platform. Reviewed-by: Manivannan Sadhasivam Signed-off-by: Palash Kambar Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260526090956.2340262-3-palash.kambar@oss.qualcomm.com Signed-off-by: Martin K. Petersen --- Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml b/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml index 900d93b675cd..b441f0d26081 100644 --- a/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml +++ b/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml @@ -16,6 +16,7 @@ select: contains: enum: - qcom,eliza-ufshc + - qcom,hawi-ufshc - qcom,kaanapali-ufshc - qcom,nord-ufshc - qcom,sm8650-ufshc @@ -28,6 +29,7 @@ properties: items: - enum: - qcom,eliza-ufshc + - qcom,hawi-ufshc - qcom,kaanapali-ufshc - qcom,nord-ufshc - qcom,sm8650-ufshc From 3c08f6034d7459f6d4d5c1599de7bb42c1d89521 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Thu, 4 Jun 2026 23:43:56 +0000 Subject: [PATCH 49/56] scsi: scsi_debug: Fix one-partition tape setup bounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tape setup path uses one tape_block entry as the end-of-data marker after the usable tape blocks. For the one-partition layout, partition 0 uses all TAPE_UNITS data slots and partition 1's marker is written at tape_blocks[0] + TAPE_UNITS. Only TAPE_UNITS entries are allocated, so that marker write is one element past the allocation during device initialization before any command is issued. Allocate one extra tape_block entry for the marker. This keeps the existing partitioning paths unchanged while providing backing storage for the sentinel. Assisted-by: Codex:gpt-5.5-cyber-preview Signed-off-by: Samuel Moelius Reviewed-by: Kai Mäkisara Link: https://patch.msgid.link/20260604234724.1936118-1-sam.moelius@trailofbits.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index a2f85ee1ae57..bb6b0e7fb910 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -6640,7 +6640,7 @@ static int scsi_debug_sdev_configure(struct scsi_device *sdp, if (sdebug_ptype == TYPE_TAPE) { if (!devip->tape_blocks[0]) { devip->tape_blocks[0] = - kzalloc_objs(struct tape_block, TAPE_UNITS); + kzalloc_objs(struct tape_block, TAPE_UNITS + 1); if (!devip->tape_blocks[0]) return 1; } From 7e161211f1dd5288b4ea802b30e70ef919ebc3da Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Fri, 5 Jun 2026 22:16:47 +1000 Subject: [PATCH 50/56] scsi: target: Fix hexadecimal CHAP_I handling A mutual CHAP handshake requires target processing of an initiator-sent CHAP_I identifier. The RFC 3720 specification states: 11.1.4. Challenge Handshake Authentication Protocol (CHAP) ... CHAP_A= CHAP_I= CHAP_C= ... Where N, (A,A1,A2), I, C, and R are (correspondingly) the Name, Algorithm, Identifier, Challenge, and Response as defined in [RFC1994], N is a text string, A,A1,A2, and I are numbers CHAP_I parsing currently calls extract_param(), which returns the @identifier string (stripped of any 0b/0B or 0x/0X prefix) and a @type which indicates DECIMAL, HEX, or BASE64 encoding (based on any stripped prefix). Any HEX encoded CHAP_I string is further processed via: ret = kstrtoul(&identifier[2], 0, &id); This is incorrect for two reasons: * The @identifier string has already been stripped of the 0x/0X prefix, so skipping the first two bytes omits part of the number. * The kstrtoul() call specifies a base of 0, which will see &identifier[2] parsed as a decimal, unless a '0x' or (octal) '0' is erroneously present at that offset. Fix this by passing the (zero-offset) identifier string to kstrtoul() along with a base=16 parameter. Also add an explicit error handler for BASE64 encoding. Hex-encoded CHAP_I handling can be testing using the libiscsi EncodedI test linked below. Reported-by: Sashiko (gemini/gemini-3.1-pro-preview) Link: https://sashiko.dev/#/patchset/20260521151121.808477-1-hossu.alexandru%40gmail.com Link: https://github.com/sahlberg/libiscsi/pull/473 Fixes: 85db7391310b ("scsi: target: iscsi: Validate CHAP_R length before base64 decode") Signed-off-by: David Disseldorp Reviewed-by: Lee Duncan Reviewed-by: John Garry Link: https://patch.msgid.link/20260605122019.24146-2-ddiss@suse.de Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_auth.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index a3ad2d244dbe..5858cc308979 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -438,9 +438,11 @@ static int chap_server_compute_hash( } if (type == HEX) - ret = kstrtoul(&identifier[2], 0, &id); + ret = kstrtoul(identifier, 16, &id); + else if (type == DECIMAL) + ret = kstrtoul(identifier, 10, &id); else - ret = kstrtoul(identifier, 0, &id); + ret = -EINVAL; if (ret < 0) { pr_err("kstrtoul() failed for CHAP identifier: %d\n", ret); From cf14fc2be868840c4c9e0e46a472995798b59712 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Fri, 5 Jun 2026 22:16:48 +1000 Subject: [PATCH 51/56] scsi: target: Use constant-time crypto_memneq() for CHAP digests A constant-time memory comparison is more suitable than plain memcmp() for authentication digest comparison. CHAP digests use an authenticator-provided random challenge, so any timing side-channel shouldn't be easily exploitable. Reported-by: Sashiko (gemini/gemini-3.1-pro-preview) Link: https://sashiko.dev/#/patchset/20260521151121.808477-1-hossu.alexandru%40gmail.com Signed-off-by: David Disseldorp Reviewed-by: Lee Duncan Link: https://patch.msgid.link/20260605122019.24146-3-ddiss@suse.de Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_auth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index 5858cc308979..f3c0cdd31830 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -9,6 +9,7 @@ ******************************************************************************/ #include +#include #include #include #include @@ -408,7 +409,7 @@ static int chap_server_compute_hash( pr_debug("[server] %s Server Digest: %s\n", chap->digest_name, response); - if (memcmp(server_digest, client_digest, chap->digest_size) != 0) { + if (crypto_memneq(server_digest, client_digest, chap->digest_size)) { pr_debug("[server] %s Digests do not match!\n\n", chap->digest_name); goto out; From 5d5221f8a4064a256b9499485a9f8c6f530f21dc Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Fri, 29 May 2026 22:56:02 +0200 Subject: [PATCH 52/56] scsi: devinfo: Broaden Promise VTrak E310/E610 identification The Promise VTrak Ex10 series share the same hardware base and firmware. Consequently all interface variants, whether fibre channel ("f") or SAS ("s") in dual/single controller, exhibit the same SCSI behavior. Instead of adding separate blacklist entries for every specific model variant (such as E610f, E610s, E310f, E310s), consolidate and broaden the match strings to "VTrak E310" and "VTrak E610". Cc: Alexander Perlis Cc: Nikkos Svoboda Cc: Martin Wilck Cc: Benjamin Marzinski Cc: Christophe Varoqui Cc: Christoph Hellwig Cc: James E.J. Bottomley Cc: Martin K. Petersen Cc: SCSI-ML Cc: DM_DEVEL-ML Signed-off-by: Xose Vazquez Perez Reviewed-by: Martin Wilck Link: https://patch.msgid.link/20260529205602.177515-1-xose.vazquez@gmail.com Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_devinfo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index c6defe1c3152..15ffbe93ac72 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -218,8 +218,8 @@ static struct { {"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"Promise", "VTrak E310f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC}, - {"Promise", "VTrak E610f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC}, + {"Promise", "VTrak E310", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC}, + {"Promise", "VTrak E610", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC}, {"Promise", "", NULL, BLIST_SPARSELUN}, {"QEMU", "QEMU CD-ROM", NULL, BLIST_SKIP_VPD_PAGES}, {"QNAP", "iSCSI Storage", NULL, BLIST_MAX_1024}, From 01d5e237b33931b970dd190dd6a19c5ef32c105d Mon Sep 17 00:00:00 2001 From: Hongjie Fang Date: Fri, 5 Jun 2026 19:20:34 +0800 Subject: [PATCH 53/56] scsi: ufs: core: Handle PM commands timeout before SCSI EH A PM START STOP sent from the UFS well-known LU resume path can race with SCSI EH: The "wl resume" task flow is: __ufshcd_wl_resume() ufshcd_set_dev_pwr_mode(UFS_ACTIVE_PWR_MODE) ufshcd_execute_start_stop() scsi_execute_cmd() blk_execute_rq <-- wait scsi_check_passthrough() <-- may retry START STOP If the first START STOP time out, SCSI EH may already recover the link and reset the device before scsi_execute_cmd() returns: scsi_timeout() scsi_eh_scmd_add() scsi_error_handler() scsi_unjam_host() scsi_eh_ready_devs() scsi_eh_host_reset() ufshcd_eh_host_reset_handler() if (hba->pm_op_in_progress) ufshcd_link_recovery() ufshcd_device_reset() ufshcd_host_reset_and_restore() ... scsi_eh_flush_done_q() <-- wakeup "wl resume" task ... <-- host still in SHOST_RECOVERY scsi_restart_operations() A later passthrough retry can then run while the host is still in SHOST_RECOVERY and hit the SCMD_FAIL_IF_RECOVERING path: scsi_queue_rq() if (scsi_host_in_recovery(shost) && cmd->flags & SCMD_FAIL_IF_RECOVERING) return BLK_STS_OFFLINE That retry completes with DID_ERROR or DID_NO_CONNECT even though EH may already have restored the device to an operational ACTIVE state. Handle these PM timeouts directly from ufshcd_eh_timed_out() instead. After ufshcd_link_recovery(), complete the timed-out command immediately if it has not been completed already. For regular SCSI commands, complete them with DID_REQUEUE to match the existing MCQ force-completion semantics and allow scsi_execute_cmd() to retry if needed. For reserved internal device-management commands, finish the request with DID_TIME_OUT without calling ufshcd_release_scsi_cmd() since those commands use different resource lifetime rules. The system_suspending flag is no longer needed because PM command timeout handling now uses pm_op_in_progress. Fixes: b8c3a7bac9b6 ("scsi: ufs: Have midlayer retry start stop errors") Signed-off-by: Hongjie Fang Reviewed-by: Bart Van Assche Reviewed-by: Peter Wang Link: https://patch.msgid.link/20260605112034.3802540-1-hongjiefang@asrmicro.com Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 34 +++++++++++++++++++++++++++------- include/ufs/ufshcd.h | 3 --- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 60ec2c63c2d8..2bbab3b2f656 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -9484,22 +9484,44 @@ static enum scsi_timeout_action ufshcd_eh_timed_out(struct scsi_cmnd *scmd) { struct ufs_hba *hba = shost_priv(scmd->device->host); - if (!hba->system_suspending) { + if (!hba->pm_op_in_progress) { /* Activate the error handler in the SCSI core. */ return SCSI_EH_NOT_HANDLED; } /* - * If we get here we know that no TMFs are outstanding and also that - * the only pending command is a START STOP UNIT command. Handle the - * timeout of that command directly to prevent a deadlock between + * Handle the timeout directly to prevent a deadlock between * ufshcd_set_dev_pwr_mode() and ufshcd_err_handler(). */ ufshcd_link_recovery(hba); dev_info(hba->dev, "%s() finished; outstanding_tasks = %#lx.\n", __func__, hba->outstanding_tasks); - return scsi_host_busy(hba->host) ? SCSI_EH_RESET_TIMER : SCSI_EH_DONE; + /* + * ufshcd_link_recovery() may already have completed @scmd, e.g. via + * the existing MCQ force-completion path. + */ + if (!test_bit(SCMD_STATE_COMPLETE, &scmd->state)) { + if (!hba->mcq_enabled) { + unsigned long flags; + struct request *rq = scsi_cmd_to_rq(scmd); + + spin_lock_irqsave(&hba->outstanding_lock, flags); + __clear_bit(rq->tag, &hba->outstanding_reqs); + spin_unlock_irqrestore(&hba->outstanding_lock, flags); + } + + if (ufshcd_is_scsi_cmd(scmd)) { + set_host_byte(scmd, DID_REQUEUE); + ufshcd_release_scsi_cmd(hba, scmd); + } else { + set_host_byte(scmd, DID_TIME_OUT); + } + + scsi_done(scmd); + } + + return SCSI_EH_DONE; } static const struct attribute_group *ufshcd_driver_groups[] = { @@ -10523,7 +10545,6 @@ static int ufshcd_wl_suspend(struct device *dev) hba = shost_priv(sdev->host); down(&hba->host_sem); - hba->system_suspending = true; if (pm_runtime_suspended(dev)) goto out; @@ -10565,7 +10586,6 @@ static int ufshcd_wl_resume(struct device *dev) hba->curr_dev_pwr_mode, hba->uic_link_state); if (!ret) hba->is_sys_suspended = false; - hba->system_suspending = false; up(&hba->host_sem); return ret; } diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 3eaae082329c..248d0a5bef40 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1029,8 +1029,6 @@ enum ufshcd_mcq_opr { * @caps: bitmask with information about UFS controller capabilities * @devfreq: frequency scaling information owned by the devfreq core * @clk_scaling: frequency scaling information owned by the UFS driver - * @system_suspending: system suspend has been started and system resume has - * not yet finished. * @is_sys_suspended: UFS device has been suspended because of system suspend * @urgent_bkops_lvl: keeps track of urgent bkops level for device * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for @@ -1206,7 +1204,6 @@ struct ufs_hba { struct devfreq *devfreq; struct ufs_clk_scaling clk_scaling; - bool system_suspending; bool is_sys_suspended; enum bkops_status urgent_bkops_lvl; From 9d87e0db00e9a2d281d11ae226eaf4d9b47376e2 Mon Sep 17 00:00:00 2001 From: Rajeshkumar Sambandham Date: Tue, 2 Jun 2026 15:29:31 +0530 Subject: [PATCH 54/56] scsi: ufs: ufs-pci: Add AMD device ID support Add PCI device ID 0x1022:0x1B29 for AMD UFS controllers. Signed-off-by: Rajeshkumar Sambandham Reviewed-by: Adrian Hunter Link: https://patch.msgid.link/20260602095931.2869516-1-Rajeshkumar.Sambandham@amd.com Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufshcd-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ufs/host/ufshcd-pci.c b/drivers/ufs/host/ufshcd-pci.c index 13293e83064c..f2433879b0eb 100644 --- a/drivers/ufs/host/ufshcd-pci.c +++ b/drivers/ufs/host/ufshcd-pci.c @@ -694,6 +694,7 @@ static const struct pci_device_id ufshcd_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0xE447), .driver_data = (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, { PCI_VDEVICE(INTEL, 0x4D47), .driver_data = (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, { PCI_VDEVICE(INTEL, 0xD335), .driver_data = (kernel_ulong_t)&ufs_intel_mtl_hba_vops }, + { PCI_VDEVICE(AMD, 0x1B29), .driver_data = 0 }, { } /* terminate list */ }; From fc6f9719e68d4133f2a373e1c6826fdef8bb1a34 Mon Sep 17 00:00:00 2001 From: William Theesfeld Date: Tue, 2 Jun 2026 07:19:12 -0400 Subject: [PATCH 55/56] scsi: lpfc: Fix spelling mistakes in comments Comment-only changes across the lpfc driver, found by running scripts/checkpatch.pl with the kernel's scripts/spelling.txt list against drivers/scsi/lpfc/. No functional impact. v1 covered a single site in lpfc_bsg.c. v2 expands to all checkpatch-detected comment misspellings across the driver, per review feedback from Justin Tee on the v1 thread. Identifiers that happen to match common-typo entries (e.g. LSEXP_CANT_GIVE_DATA, LPFC_FC_LA_TOP_UNKOWN) are intentionally left untouched, as renaming them would change the driver's internal API. Signed-off-by: William Theesfeld Reviewed-by: Justin Tee Link: https://patch.msgid.link/20260602111912.23864-1-william@theesfeld.net Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 10 +++++----- drivers/scsi/lpfc/lpfc_bsg.c | 6 +++--- drivers/scsi/lpfc/lpfc_els.c | 2 +- drivers/scsi/lpfc/lpfc_hbadisc.c | 12 ++++++------ drivers/scsi/lpfc/lpfc_hw4.h | 2 +- drivers/scsi/lpfc/lpfc_init.c | 12 ++++++------ drivers/scsi/lpfc/lpfc_scsi.c | 12 ++++++------ drivers/scsi/lpfc/lpfc_sli.c | 22 +++++++++++----------- drivers/scsi/lpfc/lpfc_sli4.h | 2 +- 9 files changed, 40 insertions(+), 40 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index c91fa44b12d4..f4e8164b94ab 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -84,7 +84,7 @@ const char *const trunk_errmsg[] = { /* map errcode */ }; /** - * lpfc_jedec_to_ascii - Hex to ascii convertor according to JEDEC rules + * lpfc_jedec_to_ascii - Hex to ascii converter according to JEDEC rules * @incr: integer to convert. * @hdw: ascii string holding converted integer plus a string terminator. * @@ -1748,12 +1748,12 @@ lpfc_issue_reset(struct device *dev, struct device_attribute *attr, } /** - * lpfc_sli4_pdev_status_reg_wait - Wait for pdev status register for readyness + * lpfc_sli4_pdev_status_reg_wait - Wait for pdev status register for readiness * @phba: lpfc_hba pointer. * * Description: * SLI4 interface type-2 device to wait on the sliport status register for - * the readyness after performing a firmware reset. + * the readiness after performing a firmware reset. * * Returns: * zero for success, -EPERM when port does not have privilege to perform the @@ -5403,7 +5403,7 @@ lpfc_vport_param_store(max_scsicmpl_time); static DEVICE_ATTR_RW(lpfc_max_scsicmpl_time); /* -# lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value +# lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgment. Value # range is [0,1]. Default value is 0. */ LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support"); @@ -5482,7 +5482,7 @@ LPFC_ATTR_R(multi_ring_support, 1, 1, 2, "Determines number of primary " /* # lpfc_multi_ring_rctl: If lpfc_multi_ring_support is enabled, this # identifies what rctl value to configure the additional ring for. -# Value range is [1,0xff]. Default value is 4 (Unsolicated Data). +# Value range is [1,0xff]. Default value is 4 (Unsolicited Data). */ LPFC_ATTR_R(multi_ring_rctl, FC_RCTL_DD_UNSOL_DATA, 1, 255, "Identifies RCTL for additional ring configuration"); diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 7406dfa60016..c95165905483 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -2066,12 +2066,12 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job) if (rc) goto job_done; - /* indicate we are in loobpack diagnostic mode */ + /* indicate we are in loopback diagnostic mode */ spin_lock_irq(&phba->hbalock); phba->link_flag |= LS_LOOPBACK_MODE; spin_unlock_irq(&phba->hbalock); - /* reset port to start frome scratch */ + /* reset port to start from scratch */ rc = lpfc_selective_reset(phba); if (rc) goto job_done; @@ -5003,7 +5003,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct bsg_job *job, } else if (phba->sli_rev == LPFC_SLI_REV4) { /* Let type 4 (well known data) through because the data is * returned in varwords[4-8] - * otherwise check the recieve length and fetch the buffer addr + * otherwise check the receive length and fetch the buffer addr */ if ((pmb->mbxCommand == MBX_DUMP_MEMORY) && (pmb->un.varDmp.type != DMP_WELL_KNOWN)) { diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 4e3fe89283e4..52fc5058976d 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4850,7 +4850,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, case IOSTAT_LS_RJT: stat.un.ls_rjt_error_be = cpu_to_be32(ulp_word4); - /* Added for Vendor specifc support + /* Added for Vendor specific support * Just keep retrying for these Rsn / Exp codes */ if (test_bit(FC_PT2PT, &vport->fc_flag) && diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index f3a85f6c796e..c9b02d2c6305 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1845,7 +1845,7 @@ lpfc_copy_fcf_record(struct lpfc_fcf_rec *fcf_rec, * @flag: flag bits to be set to the driver fcf record. * * This routine updates the driver FCF record from the new HBA FCF record - * together with the address mode, vlan_id, and other informations. This + * together with the address mode, vlan_id, and other information. This * routine is called with the hbalock held. **/ static void @@ -2120,7 +2120,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, /** * lpfc_check_pending_fcoe_event - Check if there is pending fcoe event. * @phba: pointer to lpfc hba data structure. - * @unreg_fcf: Unregister FCF if FCF table need to be re-scaned. + * @unreg_fcf: Unregister FCF if FCF table need to be re-scanned. * * This function check if there is any fcoe event pending while driver * scan FCF entries. If there is any pending event, it will restart the @@ -2290,7 +2290,7 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, * @vlan_id: the lowest vlan identifier associated to this fcf record. * @next_fcf_index: the index to the next fcf record in hba's fcf table. * - * This routine logs the detailed FCF record if the LOG_FIP loggin is + * This routine logs the detailed FCF record if the LOG_FIP login is * enabled. **/ static void @@ -3475,7 +3475,7 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) phba->fc_edtov = ed_tov; phba->fc_ratov = (2 * ed_tov) / 1000; if (phba->fc_ratov < FF_DEF_RATOV) { - /* RA_TOV should be atleast 10sec for initial flogi */ + /* RA_TOV should be at least 10sec for initial flogi */ phba->fc_ratov = FF_DEF_RATOV; } @@ -5239,7 +5239,7 @@ lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, * Free rpi associated with LPFC_NODELIST entry. * This routine is called if the driver initiates a LOGO that completes * successfully, and we are waiting to PLOGI back to the remote NPort. - * In addition, it is called after we receive and unsolicated ELS cmd, + * In addition, it is called after we receive and unsolicited ELS cmd, * send back a rsp, the rsp completes and we are waiting to PLOGI back * to the remote NPort. */ @@ -6551,7 +6551,7 @@ lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did) return ndlp; } -/* This routine releases all resources associated with a specifc NPort's ndlp +/* This routine releases all resources associated with a specific NPort's ndlp * and mempool_free's the nodelist. */ static void diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index f91bde4a6c38..41fa8f3329da 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -3256,7 +3256,7 @@ struct lpfc_mbx_memory_dump_type3 { /* - * Tranceiver codes Fibre Channel SFF-8472 + * Transceiver codes Fibre Channel SFF-8472 * Table 3.5. */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 968a25235a2d..82af59c913e9 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4103,7 +4103,7 @@ lpfc_sli4_els_sgl_update(struct lpfc_hba *phba) &phba->sli4_hba.lpfc_els_sgl_list); spin_unlock_irq(&phba->sli4_hba.sgl_list_lock); } else if (els_xri_cnt < phba->sli4_hba.els_xri_cnt) { - /* els xri-sgl shrinked */ + /* els xri-sgl shrunk */ xri_cnt = phba->sli4_hba.els_xri_cnt - els_xri_cnt; lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "3158 ELS xri-sgl count decreased from " @@ -8024,7 +8024,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) * Initialize driver internal slow-path work queues */ - /* Driver internel slow-path CQ Event pool */ + /* Driver internal slow-path CQ Event pool */ INIT_LIST_HEAD(&phba->sli4_hba.sp_cqe_event_pool); /* Response IOCB work queue list */ INIT_LIST_HEAD(&phba->sli4_hba.sp_queue_event); @@ -9740,7 +9740,7 @@ lpfc_create_bootstrap_mbox(struct lpfc_hba *phba) * Initialize the bootstrap mailbox pointers now so that the register * operations are simple later. The mailbox dma address is required * to be 16-byte aligned. Also align the virtual memory as each - * maibox is copied into the bmbx mailbox region before issuing the + * mailbox is copied into the bmbx mailbox region before issuing the * command to the port. */ phba->sli4_hba.bmbx.dmabuf = dmabuf; @@ -10206,7 +10206,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) goto read_cfg_out; } - /* search for fc_fcoe resrouce descriptor */ + /* search for fc_fcoe resource descriptor */ get_func_cfg = &pmb->u.mqe.un.get_func_cfg; pdesc_0 = (char *)&get_func_cfg->func_cfg.desc[0]; @@ -10414,7 +10414,7 @@ lpfc_alloc_io_wq_cq(struct lpfc_hba *phba, int idx) * * Return codes * 0 - successful - * -ENOMEM - No availble memory + * -ENOMEM - No available memory * -EIO - The mailbox failed to complete successfully. **/ int @@ -12490,7 +12490,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) /* If so, find a new_cpup that is on the SAME * phys_id as cpup. start_cpu will start where we - * left off so all unassigned entries don't get assgined + * left off so all unassigned entries don't get assigned * the IRQ of the first entry. */ new_cpu = start_cpu; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 1dce33b79beb..f2cab134af7f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -2497,7 +2497,7 @@ lpfc_bg_scsi_adjust_dl(struct lpfc_hba *phba, /* * If we are in DIF Type 1 mode every data block has a 8 byte - * DIF (trailer) attached to it. Must ajust FCP data length + * DIF (trailer) attached to it. Must adjust FCP data length * to account for the protection data. */ fcpdl += (fcpdl / scsi_prot_interval(sc)) * 8; @@ -2596,7 +2596,7 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, lpfc_cmd->prot_seg_cnt = protsegcnt; /* - * There is a minimun of 4 BPLs used for every + * There is a minimum of 4 BPLs used for every * protection data segment. */ if ((lpfc_cmd->prot_seg_cnt * 4) > @@ -2678,7 +2678,7 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, /* * This function calcuates the T10 DIF guard tag - * on the specified data using a CRC algorithmn + * on the specified data using a CRC algorithm * using crc_t10dif. */ static uint16_t @@ -2694,7 +2694,7 @@ lpfc_bg_crc(uint8_t *data, int count) /* * This function calcuates the T10 DIF guard tag - * on the specified data using a CSUM algorithmn + * on the specified data using a CSUM algorithm * using ip_compute_csum. */ static uint16_t @@ -3378,7 +3378,7 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, lpfc_cmd->prot_seg_cnt = protsegcnt; /* - * There is a minimun of 3 SGEs used for every + * There is a minimum of 3 SGEs used for every * protection data segment. */ if (((lpfc_cmd->prot_seg_cnt * 3) > @@ -5712,7 +5712,7 @@ lpfc_taskmgmt_name(uint8_t task_mgmt_cmd) * @vport: The virtual port for which this call is being executed. * @lpfc_cmd: Pointer to lpfc_io_buf data structure. * - * This routine checks the FCP RSP INFO to see if the tsk mgmt command succeded + * This routine checks the FCP RSP INFO to see if the tsk mgmt command succeeded * * Return code : * 0x2003 - Error diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 0e56e7034566..62a30a92b792 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1155,9 +1155,9 @@ lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, * * This function takes the hbalock. * The active bit is always set in the active rrq xri_bitmap even - * if there is no slot avaiable for the other rrq information. + * if there is no slot available for the other rrq information. * - * returns 0 rrq actived for this xri + * returns 0 rrq activated for this xri * < 0 No memory or invalid ndlp. **/ int @@ -4827,11 +4827,11 @@ lpfc_sli_brdready_s4(struct lpfc_hba *phba, uint32_t mask) } /** - * lpfc_sli_brdready - Wrapper func for checking the hba readyness + * lpfc_sli_brdready - Wrapper func for checking the hba readiness * @phba: Pointer to HBA context object. * @mask: Bit mask to be checked. * - * This routine wraps the actual SLI3 or SLI4 hba readyness check routine + * This routine wraps the actual SLI3 or SLI4 hba readiness check routine * from the API jump table function pointer from the lpfc_hba struct. **/ int @@ -8512,7 +8512,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) if (unlikely(rc)) return -ENODEV; - /* Check the HBA Host Status Register for readyness */ + /* Check the HBA Host Status Register for readiness */ rc = lpfc_sli4_post_status_check(phba); if (unlikely(rc)) return -ENODEV; @@ -9984,7 +9984,7 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) phba->sli.mbox_active = mboxq; spin_unlock_irqrestore(&phba->hbalock, iflag); - /* wait for bootstrap mbox register for readyness */ + /* wait for bootstrap mbox register for readiness */ rc = lpfc_sli4_wait_bmbx_ready(phba, mboxq); if (rc) goto exit; @@ -13955,7 +13955,7 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) * device-level interrupt handler. When the PCI slot is in error recovery * or the HBA is undergoing initialization, the interrupt handler will not * process the interrupt. The SCSI FCP fast-path ring event are handled in - * the intrrupt context. This function is called without any lock held. + * the interrupt context. This function is called without any lock held. * It gets the hbalock to access and update SLI data structures. * * This function returns IRQ_HANDLED when interrupt is handled else it @@ -15561,7 +15561,7 @@ lpfc_sli4_dly_hba_process_cq(struct work_struct *work) * device-level interrupt handler. When the PCI slot is in error recovery * or the HBA is undergoing initialization, the interrupt handler will not * process the interrupt. The SCSI FCP fast-path ring event are handled in - * the intrrupt context. This function is called without any lock held. + * the interrupt context. This function is called without any lock held. * It gets the hbalock to access and update SLI data structures. Note that, * the FCP EQ to FCP CQ are one-to-one map such that the FCP EQ index is * equal to that of FCP CQ index. @@ -16003,7 +16003,7 @@ lpfc_dpp_wc_map(struct lpfc_hba *phba, uint8_t dpp_barset) * On success this function will return a zero. If unable to allocate * enough memory this function will return -ENOMEM. If a mailbox command * fails this function will return -ENXIO. Note: on ENXIO, some EQs may - * have had their delay multipler changed. + * have had their delay multiplier changed. **/ void lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, @@ -20452,7 +20452,7 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba) /* * If next fcf index is not found check if there are lower * Priority level fcf's in the fcf_priority list. - * Set up the rr_bmask with all of the avaiable fcf bits + * Set up the rr_bmask with all of the available fcf bits * at that level and continue the selection process. */ } while (lpfc_check_next_fcf_pri_level(phba)); @@ -21696,7 +21696,7 @@ void lpfc_adjust_high_watermark(struct lpfc_hba *phba, u32 hwqid) * @phba: pointer to lpfc hba data structure. * @hwqid: belong to which HWQ. * - * This routine is called from hearbeat timer when pvt_pool is idle. + * This routine is called from heartbeat timer when pvt_pool is idle. * All free XRIs are moved from private to public pool on hwqid with 2 steps. * The first step moves (all - low_watermark) amount of XRIs. * The second step moves the rest of XRIs. diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index e2b95fb50d55..cf61370ad025 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -336,7 +336,7 @@ struct lpfc_fcf { #define FCF_AVAILABLE 0x01 /* FCF available for discovery */ #define FCF_REGISTERED 0x02 /* FCF registered with FW */ #define FCF_SCAN_DONE 0x04 /* FCF table scan done */ -#define FCF_IN_USE 0x08 /* Atleast one discovery completed */ +#define FCF_IN_USE 0x08 /* At Least one discovery completed */ #define FCF_INIT_DISC 0x10 /* Initial FCF discovery */ #define FCF_DEAD_DISC 0x20 /* FCF DEAD fast FCF failover discovery */ #define FCF_ACVL_DISC 0x40 /* All CVL fast FCF failover discovery */ From 7c08d430835a90414cd962e3a9602e5b002dee3b Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sat, 30 May 2026 00:23:47 -0500 Subject: [PATCH 56/56] scsi: target: Remove tcm_loop target reset handling tcm_loop_target_reset is supposed to handle all the LUNs on a target but it's only doing a TMR_LUN_RESET so only that one LUN is handled. This will cause us to return early while IOs to other LUNs are still hung in lower layers. This just removes the target reset handler for the driver because LIO doesn't support target resets and for the common case where this is run from the scsi-ml error hamdler we have already tried an abort and lun reset so waiting again is most likely useless. Fixes: 1333eee56cdf ("scsi: target: tcm_loop: Drain commands in target_reset handler") Signed-off-by: Mike Christie Reviewed-by: Hannes Reinecke Link: https://patch.msgid.link/20260530052349.5134-1-michael.christie@oracle.com Signed-off-by: Martin K. Petersen --- drivers/target/loopback/tcm_loop.c | 64 ------------------------------ 1 file changed, 64 deletions(-) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index a25fd826b542..f8902087c6c9 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -270,69 +270,6 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; } -static bool tcm_loop_flush_work_iter(struct request *rq, void *data) -{ - struct scsi_cmnd *sc = blk_mq_rq_to_pdu(rq); - struct tcm_loop_cmd *tl_cmd = scsi_cmd_priv(sc); - struct se_cmd *se_cmd = &tl_cmd->tl_se_cmd; - - flush_work(&se_cmd->work); - return true; -} - -static int tcm_loop_target_reset(struct scsi_cmnd *sc) -{ - struct tcm_loop_hba *tl_hba; - struct tcm_loop_tpg *tl_tpg; - struct Scsi_Host *sh = sc->device->host; - int ret; - - /* - * Locate the tcm_loop_hba_t pointer - */ - tl_hba = *(struct tcm_loop_hba **)shost_priv(sh); - if (!tl_hba) { - pr_err("Unable to perform device reset without active I_T Nexus\n"); - return FAILED; - } - /* - * Locate the tl_tpg pointer from TargetID in sc->device->id - */ - tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; - if (!tl_tpg) - return FAILED; - - /* - * Issue a LUN_RESET to drain all commands that the target core - * knows about. This handles commands not yet marked CMD_T_COMPLETE. - */ - ret = tcm_loop_issue_tmr(tl_tpg, sc->device->lun, 0, TMR_LUN_RESET); - if (ret != TMR_FUNCTION_COMPLETE) - return FAILED; - - /* - * Flush any deferred target core completion work that may still be - * queued. Commands that already had CMD_T_COMPLETE set before the TMR - * are skipped by the TMR drain, but their async completion work - * (transport_lun_remove_cmd → percpu_ref_put, release_cmd → scsi_done) - * may still be pending in target_completion_wq. - * - * The SCSI EH will reuse in-flight scsi_cmnd structures for recovery - * commands (e.g. TUR) immediately after this handler returns SUCCESS — - * if deferred work is still pending, the memset in queuecommand would - * zero the se_cmd while the work accesses it, leaking the LUN - * percpu_ref and hanging configfs unlink forever. - * - * Use blk_mq_tagset_busy_iter() to find all started requests and - * flush_work() on each — the same pattern used by mpi3mr, scsi_debug, - * and other SCSI drivers to drain outstanding commands during reset. - */ - blk_mq_tagset_busy_iter(&sh->tag_set, tcm_loop_flush_work_iter, NULL); - - tl_tpg->tl_transport_status = TCM_TRANSPORT_ONLINE; - return SUCCESS; -} - static const struct scsi_host_template tcm_loop_driver_template = { .show_info = tcm_loop_show_info, .proc_name = "tcm_loopback", @@ -341,7 +278,6 @@ static const struct scsi_host_template tcm_loop_driver_template = { .change_queue_depth = scsi_change_queue_depth, .eh_abort_handler = tcm_loop_abort_task, .eh_device_reset_handler = tcm_loop_device_reset, - .eh_target_reset_handler = tcm_loop_target_reset, .this_id = -1, .sg_tablesize = 256, .max_sectors = 0xFFFF,