summaryrefslogtreecommitdiff
path: root/drivers/scsi
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-18 09:06:02 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-18 09:06:02 -1000
commitf909e534f5e34feb2ea2701d54df63e21aa506fc (patch)
tree168f9e0c5ce0a46d0f28a8695539f124863081e7 /drivers/scsi
parent8486d357129126e27fb5d4e02622566bafc77035 (diff)
parentec6b083915e8146e147314a5f4f1285d07b57bfc (diff)
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI fixes from James Bottomley: "All fixes in drivers (or the tape ULD) and one core fix to bsg (the block ioctl equivalent of sg_io). The biggest is the race in auth updates fix in iscsi configfs, but the next biggest one is in bsg but the generic pieces of that are mostly threading reply_len" * tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi: bsg: Pass reply_len to bsg_setup_queue() to fit UFS ARPMB replies scsi: libsas: Fix SMP IO deadlock during HA resume scsi: libiscsi: Validate the task named by a management response scsi: libiscsi: Validate the ITT reflected in a Reject PDU scsi: libiscsi: Reject a negative task index from parse_pdu_itt scsi: target: iscsi: Fix race in discovery auth updates scsi: target: Disable interrupts while holding delayed_cmd_lock scsi: st: Fix use-after-free race between st_remove() and st_open() scsi: st: Save the visited block for the partition the drive is in scsi: xen/scsifront: Check for a NULL shadow entry on a backend response
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/libiscsi.c14
-rw-r--r--drivers/scsi/libsas/sas_expander.c14
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_app.c2
-rw-r--r--drivers/scsi/scsi_transport_fc.c6
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c2
-rw-r--r--drivers/scsi/scsi_transport_sas.c6
-rw-r--r--drivers/scsi/st.c18
-rw-r--r--drivers/scsi/xen-scsifront.c1
8 files changed, 43 insertions, 20 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 5cbc51899de0..5bfdb30b9088 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1142,13 +1142,15 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
spin_unlock(&conn->session->frwd_lock);
spin_lock(&conn->session->back_lock);
} else {
- struct iscsi_task *task;
+ struct iscsi_task *task = NULL;
/*
* Our nop as ping got dropped. We know the target
* and transport are ok so just clean up
*/
- task = iscsi_itt_to_task(conn, rejected_pdu.itt);
- if (!task) {
+ if (!iscsi_verify_itt(conn, rejected_pdu.itt))
+ task = iscsi_itt_to_task(conn, rejected_pdu.itt);
+ if (!task || task->state == ISCSI_TASK_FREE ||
+ task->sc) {
iscsi_conn_printk(KERN_ERR, conn,
"Invalid pdu reject. Could "
"not lookup rejected task.\n");
@@ -1191,7 +1193,7 @@ struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
session->tt->parse_pdu_itt(conn, itt, &i, NULL);
else
i = get_itt(itt);
- if (i >= session->cmds_max)
+ if (i < 0 || i >= session->cmds_max)
return NULL;
return session->cmds[i];
@@ -1284,7 +1286,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
case ISCSI_OP_SCSI_TMFUNC_RSP:
case ISCSI_OP_NOOP_IN:
task = iscsi_itt_to_task(conn, hdr->itt);
- if (!task)
+ if (!task || task->state == ISCSI_TASK_FREE || task->sc)
return ISCSI_ERR_BAD_ITT;
break;
default:
@@ -1384,7 +1386,7 @@ int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
return ISCSI_ERR_BAD_ITT;
}
- if (i >= session->cmds_max) {
+ if (i < 0 || i >= session->cmds_max) {
iscsi_conn_printk(KERN_ERR, conn,
"received invalid itt index %u (max cmds "
"%u.\n", i, session->cmds_max);
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 811c9eb4fef1..26c2099c28b9 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -62,7 +62,11 @@ static int smp_execute_task_sg(struct domain_device *dev,
to_sas_internal(dev->port->ha->shost->transportt);
struct sas_ha_struct *ha = dev->port->ha;
- pm_runtime_get_sync(ha->dev);
+ /*
+ * Non-blocking: a sync resume here would deadlock against
+ * sas_drain_work() during HA resume.
+ */
+ pm_runtime_get_noresume(ha->dev);
mutex_lock(&dev->ex_dev.cmd_mutex);
for (retry = 0; retry < 3; retry++) {
if (test_bit(SAS_DEV_GONE, &dev->state)) {
@@ -135,7 +139,7 @@ static int smp_execute_task_sg(struct domain_device *dev,
}
}
mutex_unlock(&dev->ex_dev.cmd_mutex);
- pm_runtime_put_sync(ha->dev);
+ pm_runtime_put(ha->dev);
BUG_ON(retry == 3 && task != NULL);
sas_free_task(task);
@@ -2222,6 +2226,11 @@ void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
goto out;
}
+ /* The host may have autosuspended, resume it here. */
+ ret = pm_runtime_resume_and_get(dev->port->ha->dev);
+ if (ret)
+ goto out;
+
ret = smp_execute_task_sg(dev, job->request_payload.sg_list,
job->reply_payload.sg_list);
if (ret >= 0) {
@@ -2229,6 +2238,7 @@ void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
rcvlen = job->reply_payload.payload_len - ret;
ret = 0;
}
+ pm_runtime_put(dev->port->ha->dev);
out:
bsg_job_done(job, ret, rcvlen);
diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c
index 1353a8ff9c85..094490713d69 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_app.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_app.c
@@ -3053,7 +3053,7 @@ void mpi3mr_bsg_init(struct mpi3mr_ioc *mrioc)
}
q = bsg_setup_queue(bsg_dev, dev_name(bsg_dev), &lim,
- mpi3mr_bsg_request, NULL, 0);
+ mpi3mr_bsg_request, NULL, 0, SCSI_SENSE_BUFFERSIZE);
if (IS_ERR(q)) {
ioc_err(mrioc, "%s: bsg registration failed\n",
dev_name(bsg_dev));
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 173ed6373f04..b66365a382c7 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -4345,7 +4345,8 @@ fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host)
scsi_init_limits(shost, &lim);
lim.max_segments = min_not_zero(lim.max_segments, i->f->max_bsg_segments);
q = bsg_setup_queue(dev, bsg_name, &lim, fc_bsg_dispatch,
- fc_bsg_job_timeout, i->f->dd_bsg_size);
+ fc_bsg_job_timeout, i->f->dd_bsg_size,
+ SCSI_SENSE_BUFFERSIZE);
if (IS_ERR(q)) {
dev_err(dev,
"fc_host%d: bsg interface failed to initialize - setup queue\n",
@@ -4378,7 +4379,8 @@ fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport)
scsi_init_limits(shost, &lim);
lim.max_segments = min_not_zero(lim.max_segments, i->f->max_bsg_segments);
q = bsg_setup_queue(dev, dev_name(dev), &lim, fc_bsg_dispatch_prep,
- fc_bsg_job_timeout, i->f->dd_bsg_size);
+ fc_bsg_job_timeout, i->f->dd_bsg_size,
+ SCSI_SENSE_BUFFERSIZE);
if (IS_ERR(q)) {
dev_err(dev, "failed to setup bsg queue\n");
return PTR_ERR(q);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 8aa76f813bcd..b50ff8a1d0a9 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1545,7 +1545,7 @@ iscsi_bsg_host_add(struct Scsi_Host *shost, struct iscsi_cls_host *ihost)
snprintf(bsg_name, sizeof(bsg_name), "iscsi_host%d", shost->host_no);
scsi_init_limits(shost, &lim);
q = bsg_setup_queue(dev, bsg_name, &lim, iscsi_bsg_host_dispatch, NULL,
- 0);
+ 0, SCSI_SENSE_BUFFERSIZE);
if (IS_ERR(q)) {
shost_printk(KERN_ERR, shost, "bsg interface failed to "
"initialize - no request queue\n");
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index d689b9ed08a6..a825966f60e5 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -199,7 +199,8 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
if (rphy) {
q = bsg_setup_queue(&rphy->dev, dev_name(&rphy->dev), NULL,
- sas_smp_dispatch, NULL, 0);
+ sas_smp_dispatch, NULL, 0,
+ SCSI_SENSE_BUFFERSIZE);
if (IS_ERR(q))
return PTR_ERR(q);
rphy->q = q;
@@ -208,7 +209,8 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
snprintf(name, sizeof(name), "sas_host%d", shost->host_no);
q = bsg_setup_queue(&shost->shost_gendev, name, NULL,
- sas_smp_dispatch, NULL, 0);
+ sas_smp_dispatch, NULL, 0,
+ SCSI_SENSE_BUFFERSIZE);
if (IS_ERR(q))
return PTR_ERR(q);
to_sas_host_attrs(shost)->q = q;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index f1c3c4946637..a757646c8dc6 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -3217,14 +3217,20 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition
partition >= ST_NBR_PARTITIONS)
return (-EINVAL);
if (partition != STp->partition) {
- if (get_location(STp, &blk, &p, 1))
+ /*
+ * Save the location for the partition the drive reports,
+ * not for STp->partition: after a reset STp->partition may
+ * not match the partition the drive is in.
+ */
+ if (get_location(STp, &blk, &p, 1) ||
+ p < 0 || p >= ST_NBR_PARTITIONS)
STps->last_block_valid = 0;
else {
- STps->last_block_valid = 1;
- STps->last_block_visited = blk;
+ STp->ps[p].last_block_valid = 1;
+ STp->ps[p].last_block_visited = blk;
DEBC_printk(STp, "Visited block %d for "
"partition %d saved.\n",
- blk, STp->partition);
+ blk, p);
}
}
@@ -4509,11 +4515,11 @@ static void st_remove(struct scsi_device *SDp)
remove_cdevs(tpnt);
mutex_lock(&st_ref_mutex);
- kref_put(&tpnt->kref, scsi_tape_release);
- mutex_unlock(&st_ref_mutex);
spin_lock(&st_index_lock);
idr_remove(&st_index_idr, index);
spin_unlock(&st_index_lock);
+ kref_put(&tpnt->kref, scsi_tape_release);
+ mutex_unlock(&st_ref_mutex);
}
/**
diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c
index 989bcaee42ca..aa44a233eac8 100644
--- a/drivers/scsi/xen-scsifront.c
+++ b/drivers/scsi/xen-scsifront.c
@@ -367,6 +367,7 @@ static void scsifront_do_response(struct vscsifrnt_info *info,
struct vscsifrnt_shadow *shadow;
if (ring_rsp->rqid >= VSCSIIF_MAX_REQS ||
+ !info->shadow[ring_rsp->rqid] ||
!info->shadow[ring_rsp->rqid]->inflight) {
scsifront_set_error(info, "illegal rqid returned by backend!");
return;