* [PATCH v4 1/4] scsi: st: Restore changed drive settings after reset also for MTLOAD and MTRETEN
2026-09-29 19:28 [PATCH v4 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD Laurence Oberman
@ 2026-09-29 19:28 ` Laurence Oberman
2026-09-29 19:28 ` [PATCH v4 2/4] scsi: st: Record the tape position after a successful MTLOAD Laurence Oberman
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Laurence Oberman @ 2026-09-29 19:28 UTC (permalink / raw)
To: linux-scsi
Cc: Martin K . Petersen, James E . J . Bottomley, Kai Makisara,
John Meneghini, emilne, bgurney
A device reset returns the drive's density and block size to their
defaults. Commit 7081dc75df79 ("scsi: st: Restore some drive settings
after reset") re-applies values changed by the user when the position is
recovered with MTREW, MTSEEK or MTEOM. MTLOAD and MTRETEN are also
allowed to clear the reset condition and also leave the same medium at
BOT, but they restore nothing.
Because check_tape() reads the drive's block size with MODE SENSE on
every open, the driver silently switches to the drive default after the
reset. An application that set fixed-block mode with MTSETBLK and
recovers with MTLOAD or MTRETEN keeps writing, but variable-length
blocks, without any error.
Restore the changed density and block size for MTLOAD and MTRETEN as
well. Both operations may make the drive report a new medium, and the
new session started by check_tape() clears the "changed" flags and
applies the mode defaults. So save the values before the operation, let
check_tape() run first (do_load_unload() already calls it for MTLOAD;
call it after MTRETEN), and then re-apply them. Retry the restore once
in case a unit attention is still pending. Only restore when the drive is
ready after the operation: with an immediate-mode load and O_NONBLOCK,
check_tape() does not wait and the drive may still be loading.
In immediate mode (MT_ST_NOWAIT) MTRETEN may return before the
retension has finished; do not wait for it there.
MTOFFL is not changed: the medium is unloaded and a different one may be
loaded next, for which the mode defaults apply.
Reproduced with scsi_debug (which reports a new medium after MTRETEN and
MTLOAD) and with IBM LTO drives on FC (which do not).
Fixes: 7081dc75df79 ("scsi: st: Restore some drive settings after reset")
Assisted-by: Claude sashiko
Signed-off-by: Laurence Oberman <loberman@redhat.com>
---
v4: restore after MTLOAD and MTRETEN only when the drive is ready
(Sashiko).
v2, v3: no changes.
drivers/scsi/st.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index f1c3c49..6e5e6f6 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -3586,6 +3586,23 @@ out:
return retval;
}
+/*
+ * Re-apply a density and block size that were changed by the user before a
+ * device reset (a negative value means "not changed"). A unit attention
+ * still pending after the operation (e.g. new medium after a load) fails the
+ * first MODE SELECT, so retry each once. As in the other post-reset restore
+ * path, errors are ignored and one setting failing does not prevent
+ * restoring the other.
+ */
+static void st_restore_changed_settings(struct scsi_tape *STp, int density,
+ int blksize)
+{
+ if (density >= 0 && st_int_ioctl(STp, MTSETDENSITY, density))
+ st_int_ioctl(STp, MTSETDENSITY, density);
+ if (blksize >= 0 && st_int_ioctl(STp, MTSETBLK, blksize))
+ st_int_ioctl(STp, MTSETBLK, blksize);
+}
+
/* The ioctl command */
static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
{
@@ -3594,6 +3611,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
int retval = 0;
unsigned int blk;
bool cmd_mtiocget;
+ int restore_density = -1, restore_blksize = -1;
struct scsi_tape *STp = file->private_data;
struct st_modedef *STm;
struct st_partstat *STps;
@@ -3740,6 +3758,17 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
st_int_ioctl(STp, MTSETDENSITY, STp->changed_density);
if (STp->blksize_changed)
st_int_ioctl(STp, MTSETBLK, STp->changed_blksize);
+ } else if (mtc.mt_op == MTLOAD || mtc.mt_op == MTRETEN) {
+ /*
+ * The same medium ends up at BOT, so the settings
+ * apply as with MTREW. The operation may start a
+ * new session, which clears the "changed" flags:
+ * save the values and restore them afterwards.
+ */
+ if (STp->density_changed)
+ restore_density = STp->changed_density;
+ if (STp->blksize_changed)
+ restore_blksize = STp->changed_blksize;
}
}
@@ -3819,6 +3848,14 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
if (mtc.mt_op == MTLOAD) {
retval = do_load_unload(STp, file, max(1, mtc.mt_count));
+ /*
+ * Restore only if the drive is ready: after an
+ * immediate-mode load with O_NONBLOCK, check_tape()
+ * does not wait and the drive may still be loading.
+ */
+ if (!retval && STp->ready == ST_READY)
+ st_restore_changed_settings(STp, restore_density,
+ restore_blksize);
goto out;
}
@@ -3837,6 +3874,20 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
retval = st_compression(STp, (mtc.mt_count & 1));
else
retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count);
+ if (!retval && mtc.mt_op == MTRETEN && !STp->immediate &&
+ (restore_density >= 0 || restore_blksize >= 0)) {
+ /*
+ * Retension reloads the medium and the drive may
+ * report a new medium. Let check_tape() start the new
+ * session (applying the mode defaults) now, as for
+ * MTLOAD; otherwise it happens at the next open and
+ * overrides the restored settings.
+ */
+ if (check_tape(STp, file) >= 0 &&
+ STp->ready == ST_READY)
+ st_restore_changed_settings(STp, restore_density,
+ restore_blksize);
+ }
goto out;
}
if (!STm->defined) {
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v4 2/4] scsi: st: Record the tape position after a successful MTLOAD
2026-09-29 19:28 [PATCH v4 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD Laurence Oberman
2026-09-29 19:28 ` [PATCH v4 1/4] scsi: st: Restore changed drive settings after reset also for MTLOAD and MTRETEN Laurence Oberman
@ 2026-09-29 19:28 ` Laurence Oberman
2026-09-29 19:28 ` [PATCH v4 3/4] scsi: st: Restore the drive buffering mode after reset Laurence Oberman
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Laurence Oberman @ 2026-09-29 19:28 UTC (permalink / raw)
To: linux-scsi
Cc: Martin K . Petersen, James E . J . Bottomley, Kai Makisara,
John Meneghini, emilne, bgurney
Commit 0b120edb37dc ("scsi: st: Add MTIOCGET and MTLOAD to ioctls allowed
after device reset") allows MTLOAD to clear the reset condition because
the tape location is known after MTLOAD. But the driver does not record
it: reset_state() sets the file and block numbers to -1, and
do_load_unload() leaves them there. check_tape() sets them to 0 only for
a new session, which requires a new-medium unit attention. Drives that
do not report one when the medium was already loaded (seen with IBM LTO
drives) keep reporting file/block -1 in MTIOCGET and no BOT, although the
tape is at the beginning.
After a successful load, reset the partition and the state of all
partitions, as the new-session path in check_tape() does: partition 0,
position at BOT, EOF state cleared and no pending write. Otherwise the
driver may still record the previous partition, so that a later MTSETPART
to that partition is not performed; a read after loading at EOD fails
with EIO; and a partition left in the ST_WRITING state by a partition
switch in read() or write() makes st_flush() write a filemark at the
beginning of partition 0 when the device is closed.
Fixes: 0b120edb37dc ("scsi: st: Add MTIOCGET and MTLOAD to ioctls allowed after device reset")
Suggested-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
Assisted-by: Claude sashiko
Signed-off-by: Laurence Oberman <loberman@redhat.com>
---
v4: reset the state of all partitions after the load, as a new session
does; a stale ST_WRITING state made st_flush() write a filemark at
BOT of partition 0 (Sashiko). Reproduced on an IBM LTO-5: write in
partition 0, MTSETPART 1, read(), MTLOAD, close.
v3: set the partition to 0 for all partitions, not only when the current
partition is 0 (Kai Mäkisara).
v2: also reset the EOF state after the load, as MTREW does (Sashiko).
drivers/scsi/st.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 6e5e6f6..aa4d2ce 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -2686,6 +2686,30 @@ static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_cod
else {
STp->rew_at_close = STp->autorew_dev;
retval = check_tape(STp, filp);
+ /*
+ * LOAD leaves the medium at the beginning of partition
+ * 0. check_tape() records that only for a new session;
+ * without a new-medium unit attention (the medium was
+ * already loaded) the partition and the partition state
+ * would be left as before the load. Reset them as a
+ * new session does, for all partitions: a stale
+ * ST_WRITING state would make st_flush() write a
+ * filemark at the beginning of partition 0.
+ */
+ if (retval == CHKRES_READY) {
+ int i;
+
+ STp->partition = STp->new_partition = 0;
+ for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+ STps = &(STp->ps[i]);
+ STps->rw = ST_IDLE;
+ STps->eof = ST_NOEOF;
+ STps->at_sm = 0;
+ STps->last_block_valid = 0;
+ STps->drv_block = 0;
+ STps->drv_file = 0;
+ }
+ }
if (retval > 0)
retval = 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v4 3/4] scsi: st: Restore the drive buffering mode after reset
2026-09-29 19:28 [PATCH v4 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD Laurence Oberman
2026-09-29 19:28 ` [PATCH v4 1/4] scsi: st: Restore changed drive settings after reset also for MTLOAD and MTRETEN Laurence Oberman
2026-09-29 19:28 ` [PATCH v4 2/4] scsi: st: Record the tape position after a successful MTLOAD Laurence Oberman
@ 2026-09-29 19:28 ` Laurence Oberman
2026-09-29 19:28 ` [PATCH v4 4/4] scsi: st: Relock the door after a reset Laurence Oberman
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Laurence Oberman @ 2026-09-29 19:28 UTC (permalink / raw)
To: linux-scsi
Cc: Martin K . Petersen, James E . J . Bottomley, Kai Makisara,
John Meneghini, emilne, bgurney
A device reset also returns the drive's buffered mode to its default.
check_tape() reads the buffered mode with MODE SENSE on every open, so
st follows the drive and a mode set by the user with MTSETDRVBUFFER is
lost without any indication. The value is also written back by every
later MODE SELECT, including the one that restores a changed block size.
Unlike density and block size, the buffered mode has no "changed" state
that could be used to restore it. Record the value set with
MTSETDRVBUFFER and restore it after a reset together with density and
block size: when MTREW, MTSEEK or MTEOM clear the reset condition, and
after MTLOAD and MTRETEN. It is restored first, so that the MODE SELECTs
for density and block size carry the right value.
The buffered mode is a drive setting, not a property of the medium, so
it is not cleared when a new session starts.
Suggested-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
Assisted-by: Claude sashiko
Signed-off-by: Laurence Oberman <loberman@redhat.com>
---
v4: no changes.
v3: new patch (Kai Mäkisara).
drivers/scsi/st.c | 43 ++++++++++++++++++++++++++++---------------
drivers/scsi/st.h | 2 ++
2 files changed, 30 insertions(+), 15 deletions(-)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index aa4d2ce..f548197 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -2963,9 +2963,11 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
direction = DMA_TO_DEVICE;
memset((STp->buffer)->b_data, 0, 12);
- if (cmd_in == MTSETDRVBUFFER)
+ if (cmd_in == MTSETDRVBUFFER) {
(STp->buffer)->b_data[2] = (arg & 7) << 4;
- else
+ STp->drv_buffer_changed = 1; /* At least we tried ;-) */
+ STp->changed_drv_buffer = arg & 7;
+ } else
(STp->buffer)->b_data[2] =
STp->drv_buffer << 4;
(STp->buffer)->b_data[3] = 8; /* block descriptor length */
@@ -3611,16 +3613,19 @@ out:
}
/*
- * Re-apply a density and block size that were changed by the user before a
- * device reset (a negative value means "not changed"). A unit attention
- * still pending after the operation (e.g. new medium after a load) fails the
- * first MODE SELECT, so retry each once. As in the other post-reset restore
- * path, errors are ignored and one setting failing does not prevent
- * restoring the other.
+ * Re-apply a drive buffering mode, density and block size that were changed
+ * by the user before a device reset (a negative value means "not changed").
+ * The buffering mode goes first: the other MODE SELECTs send the current
+ * STp->drv_buffer. A unit attention still pending after the operation
+ * (e.g. new medium after a load) fails the first MODE SELECT, so retry each
+ * once. As in the other post-reset restore path, errors are ignored and one
+ * setting failing does not prevent restoring the others.
*/
-static void st_restore_changed_settings(struct scsi_tape *STp, int density,
- int blksize)
+static void st_restore_changed_settings(struct scsi_tape *STp, int drv_buffer,
+ int density, int blksize)
{
+ if (drv_buffer >= 0 && st_int_ioctl(STp, MTSETDRVBUFFER, drv_buffer))
+ st_int_ioctl(STp, MTSETDRVBUFFER, drv_buffer);
if (density >= 0 && st_int_ioctl(STp, MTSETDENSITY, density))
st_int_ioctl(STp, MTSETDENSITY, density);
if (blksize >= 0 && st_int_ioctl(STp, MTSETBLK, blksize))
@@ -3635,7 +3640,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
int retval = 0;
unsigned int blk;
bool cmd_mtiocget;
- int restore_density = -1, restore_blksize = -1;
+ int restore_drv_buffer = -1, restore_density = -1, restore_blksize = -1;
struct scsi_tape *STp = file->private_data;
struct st_modedef *STm;
struct st_partstat *STps;
@@ -3778,6 +3783,9 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
STp->partition = 0;
switch_partition(STp);
}
+ if (STp->drv_buffer_changed)
+ st_int_ioctl(STp, MTSETDRVBUFFER,
+ STp->changed_drv_buffer);
if (STp->density_changed)
st_int_ioctl(STp, MTSETDENSITY, STp->changed_density);
if (STp->blksize_changed)
@@ -3789,6 +3797,8 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
* new session, which clears the "changed" flags:
* save the values and restore them afterwards.
*/
+ if (STp->drv_buffer_changed)
+ restore_drv_buffer = STp->changed_drv_buffer;
if (STp->density_changed)
restore_density = STp->changed_density;
if (STp->blksize_changed)
@@ -3878,7 +3888,8 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
* does not wait and the drive may still be loading.
*/
if (!retval && STp->ready == ST_READY)
- st_restore_changed_settings(STp, restore_density,
+ st_restore_changed_settings(STp, restore_drv_buffer,
+ restore_density,
restore_blksize);
goto out;
}
@@ -3899,7 +3910,8 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
else
retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count);
if (!retval && mtc.mt_op == MTRETEN && !STp->immediate &&
- (restore_density >= 0 || restore_blksize >= 0)) {
+ (restore_drv_buffer >= 0 || restore_density >= 0 ||
+ restore_blksize >= 0)) {
/*
* Retension reloads the medium and the drive may
* report a new medium. Let check_tape() start the new
@@ -3909,7 +3921,8 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
*/
if (check_tape(STp, file) >= 0 &&
STp->ready == ST_READY)
- st_restore_changed_settings(STp, restore_density,
+ st_restore_changed_settings(STp, restore_drv_buffer,
+ restore_density,
restore_blksize);
}
goto out;
@@ -4517,7 +4530,7 @@ static int st_probe(struct scsi_device *SDp)
tpnt->modes[0].defined = 1;
tpnt->density_changed = tpnt->compression_changed =
- tpnt->blksize_changed = 0;
+ tpnt->blksize_changed = tpnt->drv_buffer_changed = 0;
mutex_init(&tpnt->lock);
idr_preload(GFP_KERNEL);
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 0d7c4b8..c580024 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -162,10 +162,12 @@ struct scsi_tape {
unsigned char in_use;
unsigned char blksize_changed;
unsigned char density_changed;
+ unsigned char drv_buffer_changed;
unsigned char compression_changed;
unsigned char drv_buffer;
unsigned char density;
unsigned char changed_density;
+ unsigned char changed_drv_buffer;
unsigned char door_locked;
unsigned char autorew_dev; /* auto-rewind device */
unsigned char rew_at_close; /* rewind necessary at close */
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v4 4/4] scsi: st: Relock the door after a reset
2026-09-29 19:28 [PATCH v4 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD Laurence Oberman
` (2 preceding siblings ...)
2026-09-29 19:28 ` [PATCH v4 3/4] scsi: st: Restore the drive buffering mode after reset Laurence Oberman
@ 2026-09-29 19:28 ` Laurence Oberman
2026-09-30 15:58 ` [PATCH v4 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD "Kai Mäkisara (Kolumbus)"
2026-10-03 14:36 ` Martin K. Petersen (Oracle)
5 siblings, 0 replies; 7+ messages in thread
From: Laurence Oberman @ 2026-09-29 19:28 UTC (permalink / raw)
To: linux-scsi
Cc: Martin K . Petersen, James E . J . Bottomley, Kai Makisara,
John Meneghini, emilne, bgurney
With auto-lock enabled, st locks the door at the first read or write and
records ST_LOCKED_AUTO. A device reset clears the drive's medium removal
prevention, but st keeps its state, so it never locks the door again and
the medium can be removed from the drive while it is in use.
Set the lock state to ST_UNLOCKED when a reset is recognized. The door
is then locked again at the next read or write.
Suggested-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
Assisted-by: Claude sashiko
Signed-off-by: Laurence Oberman <loberman@redhat.com>
---
v4: no changes.
v3: new patch (Kai Mäkisara).
drivers/scsi/st.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index f548197..e089d3a 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -368,6 +368,8 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
if (ctr != STp->por_ctr) {
STp->por_ctr = ctr;
STp->pos_unknown = 1; /* ASC => power on / reset */
+ /* The reset allowed medium removal; relock at next access */
+ STp->door_locked = ST_UNLOCKED;
st_printk(KERN_WARNING, STp, "Power on/reset recognized.");
}
@@ -426,6 +428,7 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
if (cmdstatp->have_sense && scode == UNIT_ATTENTION &&
cmdstatp->sense_hdr.asc == 0x29 && !STp->pos_unknown) {
STp->pos_unknown = 1; /* ASC => power on / reset */
+ STp->door_locked = ST_UNLOCKED;
st_printk(KERN_WARNING, STp, "Power on/reset recognized.");
}
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v4 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD
2026-09-29 19:28 [PATCH v4 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD Laurence Oberman
` (3 preceding siblings ...)
2026-09-29 19:28 ` [PATCH v4 4/4] scsi: st: Relock the door after a reset Laurence Oberman
@ 2026-09-30 15:58 ` "Kai Mäkisara (Kolumbus)"
2026-10-03 14:36 ` Martin K. Petersen (Oracle)
5 siblings, 0 replies; 7+ messages in thread
From: "Kai Mäkisara (Kolumbus)" @ 2026-09-30 15:58 UTC (permalink / raw)
To: Laurence Oberman
Cc: linux-scsi, Martin K . Petersen, James E . J . Bottomley,
John Meneghini, emilne, bgurney
> On 29. Sep 2026, at 22.28, Laurence Oberman <loberman@redhat.com> wrote:
>
> After a device reset st blocks tape access until one of MTREW, MTOFFL,
> MTLOAD, MTRETEN, MTERASE, MTSEEK or MTEOM clears the reset condition.
> Testing the reset handling on scsi_debug and on IBM LTO drives found that
> several settings and parts of the driver state do not survive the reset
> or an MTLOAD.
...
Looks good. For the whole series:
Reviewed-by: Kai Mäkisara <kai.makisara@kolumbus.fi <mailto:kai.makisara@kolumbus.fi>>
Thanks,
Kai
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH v4 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD
2026-09-29 19:28 [PATCH v4 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD Laurence Oberman
` (4 preceding siblings ...)
2026-09-30 15:58 ` [PATCH v4 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD "Kai Mäkisara (Kolumbus)"
@ 2026-10-03 14:36 ` Martin K. Petersen (Oracle)
5 siblings, 0 replies; 7+ messages in thread
From: Martin K. Petersen (Oracle) @ 2026-10-03 14:36 UTC (permalink / raw)
To: Laurence Oberman
Cc: linux-scsi, Martin K . Petersen, James E . J . Bottomley,
Kai Makisara, John Meneghini, emilne, bgurney
Laurence,
> After a device reset st blocks tape access until one of MTREW, MTOFFL,
> MTLOAD, MTRETEN, MTERASE, MTSEEK or MTEOM clears the reset condition.
> Testing the reset handling on scsi_debug and on IBM LTO drives found that
> several settings and parts of the driver state do not survive the reset
> or an MTLOAD.
Applied to 7.4/scsi-staging, thanks!
--
Martin K. Petersen
^ permalink raw reply [flat|nested] 7+ messages in thread