[GIT PULL] SCSI fixes for 7.3-rc1+
From: James Bottomley
Date: Sat Sep 05 2026 - 12:17:52 EST
The following changes since commit cee9395acd8043be0644b25c34bfa86623f2b935:
Linux 7.3-rc1 (2026-08-30 13:34:40 -0700)
are available in the Git repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git/ tags/scsi-fixes
for you to fetch changes up to af8c27375733fb6a6df9fa484cda77cc3dd0cb80:
scsi: megaraid_sas: Limit NVMe request size to the PRP chain frame (2026-09-02 12:13:15 -0400)
----------------------------------------------------------------
2 enhancements to add support and MCQ for additional Intel 4.0
controller types. The rest are all driver fixes, the largest of which is
the mpi3mr target use after free fix, follwed by a similar TOCTOU fix
for io_uring passthrough in bsg.
----------------------------------------------------------------
Ivy Lopez (1):
scsi: mpt3sas: Avoid out-of-bounds cpumask_of_node() call in _base_assign_reply_queues()
Laurence Oberman (1):
scsi: mpi3mr: Fix use-after-free on tgt_dev->starget during target device refresh/update
Linmao Li (1):
scsi: fnic: Initialize the NVMe local port info before registering
Maurizio Lombardi (1):
scsi: target: iscsi: Fix hang for aborted WRITE_PENDING commands
Milan P. Gandhi (2):
scsi: mpi3mr: Fix NULL pointer dereference in mpi3mr_sas_port_add()
scsi: mpi3mr: Fix target device refcount leak in mpi3mr_sas_port_add()
Muhammad Falak R Wani (2):
scsi: ibmvfc: Fix kernel-doc name for ibmvfc_scsi_relogin()
scsi: ibmvfc: Document protocol parameter of ibmvfc_alloc_target()
Nitin Rawat (2):
scsi: ufs: ufs-qcom: Restore HS/LS link startup mode for Qualcomm UFS controller v6.2+
scsi: ufs: ufs-qcom: Fix sequential read variance
Rahul Chandelkar (1):
scsi: bsg: Fix TOCTOU in io_uring passthrough command setup
Runyu Xiao (1):
scsi: pm8001: Use rollback index when freeing MSI-X vectors
Sujal Tuladhar (1):
scsi: target: iscsi: Reserve a terminator byte for the login payload
Thomas Lamprecht (1):
scsi: megaraid_sas: Limit NVMe request size to the PRP chain frame
Xu Rao (1):
scsi: sg: Report request-table problems when any status is set
Yang Xiuwei (1):
scsi: bsg: Cap io_uring sense copy to max_response_len
sangram kumar yerra (2):
scsi: ufs: ufs-pci: Add support for Intel UFS 4.0 HS-Gear5
scsi: ufs: ufs-pci: Add MCQ support for Intel UFS 4.0 controllers
drivers/scsi/fnic/fnic_nvme.c | 2 +-
drivers/scsi/ibmvscsi/ibmvfc-core.c | 3 +-
drivers/scsi/megaraid/megaraid_sas_base.c | 13 ++++++-
drivers/scsi/mpi3mr/mpi3mr_os.c | 45 +++++++++++++++++------
drivers/scsi/mpi3mr/mpi3mr_transport.c | 8 +++++
drivers/scsi/mpt3sas/mpt3sas_base.c | 5 ++-
drivers/scsi/pm8001/pm8001_init.c | 4 +--
drivers/scsi/scsi_bsg.c | 47 ++++++++++++++----------
drivers/target/iscsi/iscsi_target.c | 4 ++-
drivers/target/iscsi/iscsi_target_login.c | 2 +-
drivers/ufs/host/ufs-qcom.c | 17 ++++++---
drivers/ufs/host/ufs-qcom.h | 1 +
drivers/ufs/host/ufshcd-pci.c | 59 +++++++++++++++++++++++++++++++
13 files changed, 170 insertions(+), 40 deletions(-)
---
diff --git a/drivers/scsi/fnic/fnic_nvme.c b/drivers/scsi/fnic/fnic_nvme.c
index b237948dcafd..00d9d5d439a3 100644
--- a/drivers/scsi/fnic/fnic_nvme.c
+++ b/drivers/scsi/fnic/fnic_nvme.c
@@ -2216,7 +2216,7 @@ int nvfnic_add_tport(struct fnic *fnic, struct fnic_tport_s *tport,
int nvfnic_add_lport(struct fnic *fnic)
{
- struct nvme_fc_port_info pinfo;
+ struct nvme_fc_port_info pinfo = {};
struct fnic_iport_s *iport = &fnic->iport;
int ret = 0;
diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c b/drivers/scsi/ibmvscsi/ibmvfc-core.c
index b3bc3ce872d6..3534ac45e9b8 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc-core.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c
@@ -1894,7 +1894,7 @@ static void ibmvfc_log_error(struct ibmvfc_event *evt)
}
/**
- * ibmvfc_relogin - Log back into the specified device
+ * ibmvfc_scsi_relogin - Log back into the specified device
* @sdev: scsi device struct
*
**/
@@ -4987,6 +4987,7 @@ static void ibmvfc_tgt_query_target(struct ibmvfc_target *tgt)
* ibmvfc_alloc_target - Allocate and initialize an ibmvfc target
* @vhost: ibmvfc host struct
* @target: Holds SCSI ID to allocate target forand the WWPN
+ * @protocol: protocol of the target to allocate
*
* Returns:
* 0 on success / other on failure
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index f0152b043e18..b95f187297ae 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -1973,12 +1973,23 @@ megasas_set_nvme_device_properties(struct scsi_device *sdev,
{
struct megasas_instance *instance;
u32 mr_nvme_pg_size;
+ u64 max_prp_io;
instance = (struct megasas_instance *)sdev->host->hostdata;
mr_nvme_pg_size = max_t(u32, instance->nvme_page_size,
MR_DEFAULT_NVME_PAGE_SIZE);
- lim->max_hw_sectors = max_io_size / 512;
+ /*
+ * megasas_make_prp_nvme() builds the PRP list in cmd->sg_frame without
+ * bounding it against that buffer, and spends one entry per page of
+ * it on the chain pointer. Cap the transfer at what the buffer holds,
+ * less one page for lists that start off a page boundary.
+ */
+ max_prp_io = (u64)((instance->max_chain_frame_sz / sizeof(u64)) -
+ (instance->max_chain_frame_sz / mr_nvme_pg_size) - 1) *
+ mr_nvme_pg_size;
+
+ lim->max_hw_sectors = min_t(u64, max_io_size, max_prp_io) >> SECTOR_SHIFT;
lim->virt_boundary_mask = mr_nvme_pg_size - 1;
}
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index f80a21ec161b..0f7380448718 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -1094,10 +1094,13 @@ static void mpi3mr_refresh_tgtdevs(struct mpi3mr_ioc *mrioc)
{
struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next;
struct mpi3mr_stgt_priv_data *tgt_priv;
+ struct scsi_target *starget;
+ unsigned long flags;
dprint_reset(mrioc, "refresh target devices: check for removals\n");
list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
list) {
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
if (((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) ||
tgtdev->is_hidden) &&
tgtdev->host_exposed && tgtdev->starget &&
@@ -1106,6 +1109,7 @@ static void mpi3mr_refresh_tgtdevs(struct mpi3mr_ioc *mrioc)
tgt_priv->dev_removed = 1;
atomic_set(&tgt_priv->block_io, 0);
}
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
}
list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
@@ -1127,15 +1131,25 @@ static void mpi3mr_refresh_tgtdevs(struct mpi3mr_ioc *mrioc)
tgtdev = NULL;
list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
if ((tgtdev->dev_handle != MPI3MR_INVALID_DEV_HANDLE) &&
- !tgtdev->is_hidden) {
- if (!tgtdev->host_exposed)
+ !tgtdev->is_hidden) {
+ if (!tgtdev->host_exposed) {
mpi3mr_report_tgtdev_to_host(mrioc,
- tgtdev->perst_id);
- else if (tgtdev->starget)
- starget_for_each_device(tgtdev->starget,
- (void *)tgtdev, mpi3mr_update_sdev);
- }
+ tgtdev->perst_id);
+ continue;
+ }
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ starget = tgtdev->starget;
+ if (starget)
+ get_device(&starget->dev);
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+ if (starget) {
+ starget_for_each_device(starget, (void *)tgtdev,
+ mpi3mr_update_sdev);
+ put_device(&starget->dev);
+ }
+ }
}
+ dprint_reset(mrioc, "refresh target devices: done\n");
}
/**
@@ -1515,6 +1529,8 @@ static void mpi3mr_devinfochg_evt_bh(struct mpi3mr_ioc *mrioc,
struct mpi3_device_page0 *dev_pg0)
{
struct mpi3mr_tgt_dev *tgtdev = NULL;
+ struct scsi_target *starget;
+ unsigned long flags;
u16 dev_handle = 0, perst_id = 0;
perst_id = le16_to_cpu(dev_pg0->persistent_id);
@@ -1535,9 +1551,18 @@ static void mpi3mr_devinfochg_evt_bh(struct mpi3mr_ioc *mrioc,
mpi3mr_report_tgtdev_to_host(mrioc, perst_id);
if (tgtdev->is_hidden && tgtdev->host_exposed)
mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
- if (!tgtdev->is_hidden && tgtdev->host_exposed && tgtdev->starget)
- starget_for_each_device(tgtdev->starget, (void *)tgtdev,
- mpi3mr_update_sdev);
+ if (!tgtdev->is_hidden && tgtdev->host_exposed) {
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ starget = tgtdev->starget;
+ if (starget)
+ get_device(&starget->dev);
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+ if (starget) {
+ starget_for_each_device(starget, (void *)tgtdev,
+ mpi3mr_update_sdev);
+ put_device(&starget->dev);
+ }
+ }
out:
if (tgtdev)
mpi3mr_tgtdev_put(tgtdev);
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
index 240f67a8e2e3..232af978d737 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -1428,9 +1428,15 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
}
port = sas_port_alloc_num(mr_sas_node->parent_dev);
+ if (!port) {
+ ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+ __FILE__, __LINE__, __func__);
+ goto out_fail;
+ }
if ((sas_port_add(port))) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
+ sas_port_free(port);
goto out_fail;
}
@@ -1501,6 +1507,8 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
list_for_each_entry_safe(mr_sas_phy, next, &mr_sas_port->phy_list,
port_siblings)
list_del(&mr_sas_phy->port_siblings);
+ if (tgtdev)
+ mpi3mr_tgtdev_put(tgtdev);
kfree(mr_sas_port);
return NULL;
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index fed7aeffec58..1af25a22611a 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -3238,7 +3238,10 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
* corresponding to high iops queues.
*/
if (ioc->high_iops_queues) {
- mask = cpumask_of_node(dev_to_node(&ioc->pdev->dev));
+ int node = dev_to_node(&ioc->pdev->dev);
+
+ mask = (node == NUMA_NO_NODE) ?
+ cpu_online_mask : cpumask_of_node(node);
for (index = 0; index < ioc->high_iops_queues;
index++) {
irq = pci_irq_vector(ioc->pdev, index);
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index e93ea76b565e..54b35893261a 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -1029,8 +1029,8 @@ static u32 pm8001_request_msix(struct pm8001_hba_info *pm8001_ha)
&(pm8001_ha->irq_vector[i]));
if (rc) {
for (j = 0; j < i; j++) {
- free_irq(pci_irq_vector(pm8001_ha->pdev, i),
- &(pm8001_ha->irq_vector[i]));
+ free_irq(pci_irq_vector(pm8001_ha->pdev, j),
+ &pm8001_ha->irq_vector[j]);
}
pci_free_irq_vectors(pm8001_ha->pdev);
break;
diff --git a/drivers/scsi/scsi_bsg.c b/drivers/scsi/scsi_bsg.c
index e80dec53174e..5eec248a77a6 100644
--- a/drivers/scsi/scsi_bsg.c
+++ b/drivers/scsi/scsi_bsg.c
@@ -18,6 +18,7 @@ struct scsi_bsg_uring_cmd_pdu {
struct bio *bio; /* mapped user buffer, unmap in task work */
struct request *req; /* block request, freed in task work */
u64 response_addr; /* user space response buffer address */
+ u32 max_response_len; /* user response buffer size */
};
static_assert(sizeof(struct scsi_bsg_uring_cmd_pdu) <= sizeof_field(struct io_uring_cmd, pdu));
@@ -45,8 +46,8 @@ static void scsi_bsg_uring_task_cb(struct io_tw_req tw_req, io_tw_token_t tw)
if (scsi_status_is_check_condition(scmd->result)) {
driver_status = DRIVER_SENSE;
if (pdu->response_addr)
- sense_len_wr = min_t(u8, scmd->sense_len,
- SCSI_SENSE_BUFFERSIZE);
+ sense_len_wr = min_t(unsigned int, pdu->max_response_len,
+ scmd->sense_len);
}
if (sense_len_wr) {
@@ -76,12 +77,10 @@ static enum rq_end_io_ret scsi_bsg_uring_cmd_done(struct request *req,
static int scsi_bsg_map_user_buffer(struct request *req,
struct io_uring_cmd *ioucmd,
- unsigned int issue_flags, gfp_t gfp_mask)
+ unsigned int issue_flags, gfp_t gfp_mask,
+ bool is_write, u64 buf_addr,
+ unsigned long buf_len)
{
- const struct bsg_uring_cmd *cmd = io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd);
- bool is_write = cmd->dout_xfer_len > 0;
- u64 buf_addr = is_write ? cmd->dout_xferp : cmd->din_xferp;
- unsigned long buf_len = is_write ? cmd->dout_xfer_len : cmd->din_xfer_len;
struct iov_iter iter;
int ret;
@@ -104,21 +103,28 @@ static int scsi_bsg_uring_cmd(struct request_queue *q, struct io_uring_cmd *iouc
unsigned int issue_flags, bool open_for_write)
{
struct scsi_bsg_uring_cmd_pdu *pdu = scsi_bsg_uring_cmd_pdu(ioucmd);
- const struct bsg_uring_cmd *cmd = io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd);
+ const struct bsg_uring_cmd *cmd =
+ io_uring_sqe128_cmd(ioucmd->sqe, struct bsg_uring_cmd);
struct scsi_cmnd *scmd;
struct request *req;
blk_mq_req_flags_t blk_flags = 0;
gfp_t gfp_mask = GFP_KERNEL;
+ u64 request = READ_ONCE(cmd->request);
+ u32 request_len = READ_ONCE(cmd->request_len);
+ u64 dout_xferp = READ_ONCE(cmd->dout_xferp);
+ u32 dout_xfer_len = READ_ONCE(cmd->dout_xfer_len);
+ u64 din_xferp = READ_ONCE(cmd->din_xferp);
+ u32 din_xfer_len = READ_ONCE(cmd->din_xfer_len);
int ret;
if (cmd->protocol != BSG_PROTOCOL_SCSI ||
cmd->subprotocol != BSG_SUB_PROTOCOL_SCSI_CMD)
return -EINVAL;
- if (!cmd->request || cmd->request_len == 0)
+ if (!request || request_len == 0)
return -EINVAL;
- if (cmd->dout_xfer_len && cmd->din_xfer_len) {
+ if (dout_xfer_len && din_xfer_len) {
pr_warn_once("BIDI support in bsg has been removed.\n");
return -EOPNOTSUPP;
}
@@ -131,20 +137,20 @@ static int scsi_bsg_uring_cmd(struct request_queue *q, struct io_uring_cmd *iouc
gfp_mask = GFP_NOWAIT;
}
- req = scsi_alloc_request(q, cmd->dout_xfer_len ?
+ req = scsi_alloc_request(q, dout_xfer_len ?
REQ_OP_DRV_OUT : REQ_OP_DRV_IN, blk_flags);
if (IS_ERR(req))
return PTR_ERR(req);
scmd = blk_mq_rq_to_pdu(req);
- if (cmd->request_len > sizeof(scmd->cmnd)) {
+ if (request_len > sizeof(scmd->cmnd)) {
ret = -EINVAL;
goto out_free_req;
}
- scmd->cmd_len = cmd->request_len;
+ scmd->cmd_len = request_len;
scmd->allowed = SG_DEFAULT_RETRIES;
- if (copy_from_user(scmd->cmnd, uptr64(cmd->request), cmd->request_len)) {
+ if (copy_from_user(scmd->cmnd, uptr64(request), request_len)) {
ret = -EFAULT;
goto out_free_req;
}
@@ -155,11 +161,16 @@ static int scsi_bsg_uring_cmd(struct request_queue *q, struct io_uring_cmd *iouc
}
pdu->response_addr = cmd->response;
- scmd->sense_len = cmd->max_response_len ?
- min(cmd->max_response_len, SCSI_SENSE_BUFFERSIZE) : SCSI_SENSE_BUFFERSIZE;
+ pdu->max_response_len = cmd->max_response_len;
- if (cmd->dout_xfer_len || cmd->din_xfer_len) {
- ret = scsi_bsg_map_user_buffer(req, ioucmd, issue_flags, gfp_mask);
+ if (dout_xfer_len || din_xfer_len) {
+ bool is_write = dout_xfer_len > 0;
+ u64 buf_addr = is_write ? dout_xferp : din_xferp;
+ unsigned long buf_len = is_write ? dout_xfer_len : din_xfer_len;
+
+ ret = scsi_bsg_map_user_buffer(req, ioucmd, issue_flags,
+ gfp_mask, is_write, buf_addr,
+ buf_len);
if (ret)
goto out_free_req;
pdu->bio = req->bio;
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 62ada3a52210..124ff269b8e7 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1533,8 +1533,10 @@ __iscsit_check_dataout_hdr(struct iscsit_conn *conn, void *buf,
*/
if (se_cmd->transport_state & CMD_T_ABORTED) {
if (hdr->flags & ISCSI_FLAG_CMD_FINAL &&
- --cmd->outstanding_r2ts < 1)
+ --cmd->outstanding_r2ts < 1) {
iscsit_stop_dataout_timer(cmd);
+ target_complete_cmd(se_cmd, SAM_STAT_TASK_ABORTED);
+ }
return iscsit_dump_data_payload(conn, payload_length, 1);
}
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index aafc94bcb635..c282b6a70296 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -47,7 +47,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsit_conn *conn)
login->conn = conn;
login->first_request = 1;
- login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
+ login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS + 1, GFP_KERNEL);
if (!login->req_buf) {
pr_err("Unable to allocate memory for response buffer.\n");
goto out_login;
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 62396212a0a7..b31c04b5461e 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -715,6 +715,7 @@ static void ufs_qcom_link_startup_post_change(struct ufs_hba *hba)
static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status)
{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
int err = 0;
switch (status) {
@@ -737,6 +738,14 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
*/
err = ufshcd_disable_host_tx_lcc(hba);
+ /*
+ * Restore HS/LS link startup mode set by bootloader
+ * after UFS reset clears REG_UFS_DEBUG_SPARE_CFG.
+ */
+ if (host->hw_ver.major > 0x6 ||
+ (host->hw_ver.major == 0x6 && host->hw_ver.minor >= 0x2))
+ ufshcd_writel(hba, host->boot_spare_cfg,
+ REG_UFS_DEBUG_SPARE_CFG);
break;
case POST_CHANGE:
ufs_qcom_link_startup_post_change(hba);
@@ -1325,7 +1334,7 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host)
{
struct ufs_host_params *host_params = &host->host_params;
- u32 val, dev_major;
+ u32 dev_major;
/*
* Default to powering up the PHY to the max gear possible, which is
@@ -1344,8 +1353,8 @@ static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host)
*/
host->phy_gear = UFS_HS_G2;
} else if (host->hw_ver.major >= 0x5) {
- val = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG);
- dev_major = FIELD_GET(UFS_DEV_VER_MAJOR_MASK, val);
+ host->boot_spare_cfg = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG);
+ dev_major = FIELD_GET(UFS_DEV_VER_MAJOR_MASK, host->boot_spare_cfg);
/*
* Since the UFS device version is populated, let's remove the
@@ -2282,7 +2291,7 @@ static void ufs_qcom_config_scaling_param(struct ufs_hba *hba,
p->polling_ms = 60;
p->timer = DEVFREQ_TIMER_DELAYED;
d->upthreshold = 70;
- d->downdifferential = 5;
+ d->downdifferential = 65;
hba->clk_scaling.suspend_on_no_request = true;
}
diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h
index e20b3ca50577..a5ad5ce44a19 100644
--- a/drivers/ufs/host/ufs-qcom.h
+++ b/drivers/ufs/host/ufs-qcom.h
@@ -361,6 +361,7 @@ struct ufs_qcom_host {
bool esi_enabled;
u32 saved_tx_eq_g1_setting;
+ u32 boot_spare_cfg;
};
struct ufs_qcom_drvdata {
diff --git a/drivers/ufs/host/ufshcd-pci.c b/drivers/ufs/host/ufshcd-pci.c
index f2433879b0eb..21bb11c724be 100644
--- a/drivers/ufs/host/ufshcd-pci.c
+++ b/drivers/ufs/host/ufshcd-pci.c
@@ -181,6 +181,25 @@ static int ufs_intel_lkf_pwr_change_notify(struct ufs_hba *hba,
return err;
}
+static int ufs_intel_nvl_pwr_change_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status stage,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ int adapt_val;
+
+ if (stage != PRE_CHANGE || hba->ufs_version < ufshci_version(4, 0))
+ return 0;
+
+ if (dev_req_params->pwr_tx == FAST_MODE || dev_req_params->pwr_tx == FASTAUTO_MODE)
+ adapt_val = PA_INITIAL_ADAPT;
+ else
+ adapt_val = PA_NO_ADAPT;
+
+ ufshcd_dme_configure_adapt(hba, dev_req_params->gear_tx, adapt_val);
+
+ return 0;
+}
+
static int ufs_intel_lkf_apply_dev_quirks(struct ufs_hba *hba)
{
u32 granularity, peer_granularity;
@@ -441,6 +460,43 @@ static int ufs_intel_mtl_init(struct ufs_hba *hba)
return ufs_intel_common_init(hba);
}
+static int ufs_intel_mcq_config_resource(struct ufs_hba *hba)
+{
+ hba->mcq_base = hba->mmio_base + ufshcd_mcq_queue_cfg_addr(hba);
+
+ return 0;
+}
+
+/*
+ * This Intel UFS4.0 controller maps MCQ doorbell and interrupt-status
+ * registers into the same PCI BAR as the legacy HCI space, at this
+ * fixed offset/stride.
+ */
+#define UFS_INTEL_SQDAO0 0x2800
+#define UFS_INTEL_SQISAO0 0x2814
+#define UFS_INTEL_CQDAO0 0x281C
+#define UFS_INTEL_CQISAO0 0x2824
+#define UFS_INTEL_MCQ_STRIDE 0x30
+
+static int ufs_intel_op_runtime_config(struct ufs_hba *hba)
+{
+ struct ufshcd_mcq_opr_info_t *opr;
+ int i;
+
+ hba->mcq_opr[OPR_SQD].offset = UFS_INTEL_SQDAO0;
+ hba->mcq_opr[OPR_SQIS].offset = UFS_INTEL_SQISAO0;
+ hba->mcq_opr[OPR_CQD].offset = UFS_INTEL_CQDAO0;
+ hba->mcq_opr[OPR_CQIS].offset = UFS_INTEL_CQISAO0;
+
+ for (i = 0; i < OPR_MAX; i++) {
+ opr = &hba->mcq_opr[i];
+ opr->stride = UFS_INTEL_MCQ_STRIDE;
+ opr->base = hba->mmio_base + opr->offset;
+ }
+
+ return 0;
+}
+
static int ufs_qemu_get_hba_mac(struct ufs_hba *hba)
{
return MAX_SUPP_MAC;
@@ -527,6 +583,9 @@ static struct ufs_hba_variant_ops ufs_intel_mtl_hba_vops = {
.exit = ufs_intel_common_exit,
.hce_enable_notify = ufs_intel_hce_enable_notify,
.link_startup_notify = ufs_intel_link_startup_notify,
+ .pwr_change_notify = ufs_intel_nvl_pwr_change_notify,
+ .mcq_config_resource = ufs_intel_mcq_config_resource,
+ .op_runtime_config = ufs_intel_op_runtime_config,
.resume = ufs_intel_resume,
.device_reset = ufs_intel_device_reset,
};