* [PATCH v3 1/4] scsi: st: Restore changed drive settings after reset also for MTLOAD and MTRETEN
2026-09-29 17:18 [PATCH v3 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD Laurence Oberman
@ 2026-09-29 17:18 ` Laurence Oberman
2026-09-29 17:33 ` sashiko-bot
2026-09-29 17:18 ` [PATCH v3 2/4] scsi: st: Record the tape position after a successful MTLOAD Laurence Oberman
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Laurence Oberman @ 2026-09-29 17:18 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.
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>
---
drivers/scsi/st.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index f1c3c4946637..0a4263bef9cb 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -3586,6 +3586,23 @@ static long st_common_ioctl(struct scsi_tape *STp, struct st_modedef *STm,
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,9 @@ 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));
+ if (!retval)
+ st_restore_changed_settings(STp, restore_density,
+ restore_blksize);
goto out;
}
@@ -3837,6 +3869,19 @@ 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)
+ st_restore_changed_settings(STp, restore_density,
+ restore_blksize);
+ }
goto out;
}
if (!STm->defined) {
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v3 1/4] scsi: st: Restore changed drive settings after reset also for MTLOAD and MTRETEN
2026-09-29 17:18 ` [PATCH v3 1/4] scsi: st: Restore changed drive settings after reset also for MTLOAD and MTRETEN Laurence Oberman
@ 2026-09-29 17:33 ` sashiko-bot
2026-09-29 17:45 ` Laurence Oberman
0 siblings, 1 reply; 9+ messages in thread
From: sashiko-bot @ 2026-09-29 17:33 UTC (permalink / raw)
To: Laurence Oberman; +Cc: linux-scsi
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] scsi: st: MTLOAD in immediate mode attempts premature settings restore
--
commit 17d984b3de3a58216a78afa696892ddd4aea0bbd
Author: Laurence Oberman <loberman@redhat.com>
scsi: st: Restore changed drive settings after reset also for MTLOAD and MTRETEN
A device reset returns the drive's density and block size to their defaults.
This patch attempts to re-apply values changed by the user when recovering
with MTLOAD or MTRETEN.
> diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
> index f1c3c49466379..0a4263bef9cbb 100644
> --- a/drivers/scsi/st.c
> +++ b/drivers/scsi/st.c
[ ... ]
> @@ -3819,6 +3848,9 @@ 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));
> + if (!retval)
> + st_restore_changed_settings(STp, restore_density,
> + restore_blksize);
[Severity: High]
Does this code attempt a premature settings restore if MTLOAD is called
in immediate mode?
If a user application issues MTLOAD with O_NONBLOCK and STp->immediate
set to recover after a drive reset, do_load_unload() will issue the load
command and return immediately. This unconditional call to
st_restore_changed_settings() would then cause MODE SELECT commands to
fail because the drive is still asynchronously loading.
Later, when the drive is accessed, check_tape() detects the new session
and clears the changed flags, causing the drive to silently revert to
its default density and block size. Subsequent writes might then produce
incorrectly formatted tapes without errors.
For MTRETEN, this patch correctly checks for !STp->immediate before restoring
the settings:
> goto out;
> }
[ ... ]
> @@ -3837,6 +3869,19 @@ 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)) {
Should MTLOAD also verify !STp->immediate before calling
st_restore_changed_settings() in st_ioctl()? Note that follow-up patches
in this series do not correct this omission.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260929171813.844733-1-loberman@redhat.com?part=1
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v3 1/4] scsi: st: Restore changed drive settings after reset also for MTLOAD and MTRETEN
2026-09-29 17:33 ` sashiko-bot
@ 2026-09-29 17:45 ` Laurence Oberman
0 siblings, 0 replies; 9+ messages in thread
From: Laurence Oberman @ 2026-09-29 17:45 UTC (permalink / raw)
To: sashiko-reviews; +Cc: linux-scsi
On Tue, 2026-09-29 at 17:33 +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential
> issue(s) to consider:
> - [High] scsi: st: MTLOAD in immediate mode attempts premature
> settings restore
> --
>
> commit 17d984b3de3a58216a78afa696892ddd4aea0bbd
> Author: Laurence Oberman <loberman@redhat.com>
>
> scsi: st: Restore changed drive settings after reset also for MTLOAD
> and MTRETEN
>
> A device reset returns the drive's density and block size to their
> defaults.
> This patch attempts to re-apply values changed by the user when
> recovering
> with MTLOAD or MTRETEN.
>
> > diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
> > index f1c3c49466379..0a4263bef9cbb 100644
> > --- a/drivers/scsi/st.c
> > +++ b/drivers/scsi/st.c
> [ ... ]
> > @@ -3819,6 +3848,9 @@ 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));
> > + if (!retval)
> > + st_restore_changed_settings(STp,
> > restore_density,
> > +
> > restore_blksize);
>
> [Severity: High]
> Does this code attempt a premature settings restore if MTLOAD is
> called
> in immediate mode?
>
> If a user application issues MTLOAD with O_NONBLOCK and STp-
> >immediate
> set to recover after a drive reset, do_load_unload() will issue the
> load
> command and return immediately. This unconditional call to
> st_restore_changed_settings() would then cause MODE SELECT commands
> to
> fail because the drive is still asynchronously loading.
>
> Later, when the drive is accessed, check_tape() detects the new
> session
> and clears the changed flags, causing the drive to silently revert to
> its default density and block size. Subsequent writes might then
> produce
> incorrectly formatted tapes without errors.
>
> For MTRETEN, this patch correctly checks for !STp->immediate before
> restoring
> the settings:
>
> > goto out;
> > }
> [ ... ]
> > @@ -3837,6 +3869,19 @@ 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)) {
>
> Should MTLOAD also verify !STp->immediate before calling
> st_restore_changed_settings() in st_ioctl()? Note that follow-up
> patches
> in this series do not correct this omission.
>
>
Hello Sashiko,
This only affects MTLOAD in immediate mode with an O_NONBLOCK open;
with a blocking open check_tape() waits for the drive and the restore
works. In the non-blocking case the MODE SELECTs fail and the settings
stay at the drive defaults, which is the current behaviour without the
patch, so it is not a regression. I can add a "STp->ready == ST_READY"
check before the restore in a follow-up and leave v3 as is.
Thanks
Laurence
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 2/4] scsi: st: Record the tape position after a successful MTLOAD
2026-09-29 17:18 [PATCH v3 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD Laurence Oberman
2026-09-29 17:18 ` [PATCH v3 1/4] scsi: st: Restore changed drive settings after reset also for MTLOAD and MTRETEN Laurence Oberman
@ 2026-09-29 17:18 ` Laurence Oberman
2026-09-29 17:41 ` sashiko-bot
2026-09-29 17:18 ` [PATCH v3 3/4] scsi: st: Restore the drive buffering mode after reset Laurence Oberman
2026-09-29 17:18 ` [PATCH v3 4/4] scsi: st: Relock the door after a reset Laurence Oberman
3 siblings, 1 reply; 9+ messages in thread
From: Laurence Oberman @ 2026-09-29 17:18 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, set the partition to 0, the position to BOT and
reset the EOF state, as the new-session path in check_tape() and MTREW
do. Otherwise the driver may still record the previous partition, so
that a later MTSETPART to that partition is not performed, and a read
after loading at EOD fails with EIO.
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>
---
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 | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 0a4263bef9cb..e5b2e2d4872d 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -2686,6 +2686,22 @@ 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, position and EOF state
+ * would be left as before the load. Set them as a new
+ * session and MTREW do.
+ */
+ if (retval == CHKRES_READY) {
+ STp->partition = STp->new_partition = 0;
+ STps = &(STp->ps[0]);
+ STps->drv_file = STps->drv_block = 0;
+ STps->eof = ST_NOEOF;
+ STps->at_sm = 0;
+ STps->last_block_valid = 0;
+ }
if (retval > 0)
retval = 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v3 2/4] scsi: st: Record the tape position after a successful MTLOAD
2026-09-29 17:18 ` [PATCH v3 2/4] scsi: st: Record the tape position after a successful MTLOAD Laurence Oberman
@ 2026-09-29 17:41 ` sashiko-bot
2026-09-29 18:16 ` Laurence Oberman
0 siblings, 1 reply; 9+ messages in thread
From: sashiko-bot @ 2026-09-29 17:41 UTC (permalink / raw)
To: Laurence Oberman; +Cc: linux-scsi
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] scsi: st: data corruption via rogue filemarks after MTLOAD
--
commit fa623b9485fe23a48925ee926b259a954fdd216e
Author: Laurence Oberman <loberman@redhat.com>
scsi: st: Record the tape position after a successful MTLOAD
This commit records the tape partition, position, and EOF state after a
successful MTLOAD, similar to how check_tape() does for a new session.
This fixes an issue where the driver would incorrectly report file/block
as -1 because drives didn't report a new-medium unit attention when
already loaded.
> diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
> index 0a4263bef9cbb..e5b2e2d4872d3 100644
> --- a/drivers/scsi/st.c
> +++ b/drivers/scsi/st.c
> @@ -2686,6 +2686,22 @@ 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, position and EOF state
> + * would be left as before the load. Set them as a new
> + * session and MTREW do.
> + */
> + if (retval == CHKRES_READY) {
> + STp->partition = STp->new_partition = 0;
> + STps = &(STp->ps[0]);
> + STps->drv_file = STps->drv_block = 0;
> + STps->eof = ST_NOEOF;
> + STps->at_sm = 0;
> + STps->last_block_valid = 0;
[Severity: High]
Does this code risk data corruption by omitting a reset of the rw state?
If a user writes data to partition 0 (setting ps[0].rw = ST_WRITING), issues
MTSETPART 1, and then switches to partition 1, ps[0].rw remains ST_WRITING.
If the user then issues MTLOAD, the ioctl clears the rw state for the current
partition (ps[1]), but do_load_unload() then forces STp->partition = 0 without
clearing ps[0].rw.
Upon closing the device, st_flush() would see ps[0].rw == ST_WRITING and
unconditionally execute WRITE_FILEMARKS at the beginning of the tape (BOT),
overwriting and destroying previously recorded data.
Should STps->rw = ST_IDLE; be added to this block to prevent rogue filemark
writes at BOT?
> + }
> if (retval > 0)
> retval = 0;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260929171813.844733-1-loberman@redhat.com?part=2
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v3 2/4] scsi: st: Record the tape position after a successful MTLOAD
2026-09-29 17:41 ` sashiko-bot
@ 2026-09-29 18:16 ` Laurence Oberman
0 siblings, 0 replies; 9+ messages in thread
From: Laurence Oberman @ 2026-09-29 18:16 UTC (permalink / raw)
To: sashiko-reviews; +Cc: linux-scsi
On Tue, 2026-09-29 at 17:41 +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential
> issue(s) to consider:
> - [High] scsi: st: data corruption via rogue filemarks after MTLOAD
> --
>
> commit fa623b9485fe23a48925ee926b259a954fdd216e
> Author: Laurence Oberman <loberman@redhat.com>
>
> scsi: st: Record the tape position after a successful MTLOAD
>
> This commit records the tape partition, position, and EOF state after
> a
> successful MTLOAD, similar to how check_tape() does for a new
> session.
> This fixes an issue where the driver would incorrectly report
> file/block
> as -1 because drives didn't report a new-medium unit attention when
> already loaded.
>
> > diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
> > index 0a4263bef9cbb..e5b2e2d4872d3 100644
> > --- a/drivers/scsi/st.c
> > +++ b/drivers/scsi/st.c
> > @@ -2686,6 +2686,22 @@ 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, position
> > and EOF state
> > + * would be left as before the load. Set
> > them as a new
> > + * session and MTREW do.
> > + */
> > + if (retval == CHKRES_READY) {
> > + STp->partition = STp-
> > >new_partition = 0;
> > + STps = &(STp->ps[0]);
> > + STps->drv_file = STps->drv_block =
> > 0;
> > + STps->eof = ST_NOEOF;
> > + STps->at_sm = 0;
> > + STps->last_block_valid = 0;
>
> [Severity: High]
> Does this code risk data corruption by omitting a reset of the rw
> state?
>
> If a user writes data to partition 0 (setting ps[0].rw = ST_WRITING),
> issues
> MTSETPART 1, and then switches to partition 1, ps[0].rw remains
> ST_WRITING.
>
> If the user then issues MTLOAD, the ioctl clears the rw state for the
> current
> partition (ps[1]), but do_load_unload() then forces STp->partition =
> 0 without
> clearing ps[0].rw.
>
> Upon closing the device, st_flush() would see ps[0].rw == ST_WRITING
> and
> unconditionally execute WRITE_FILEMARKS at the beginning of the tape
> (BOT),
> overwriting and destroying previously recorded data.
>
> Should STps->rw = ST_IDLE; be added to this block to prevent rogue
> filemark
> writes at BOT?
>
> > + }
> > if (retval > 0)
> > retval = 0;
> > }
Thanks, this will need to be fixed.
Correct, thanks. After MTSETPART, the previous partition's rw state is
not reset, and with v3 st moves to partition 0 after the load, so a
stale ST_WRITING there makes st_flush() write a filemark at BOT. v4
will reset the state of all partitions after the load, as check_tape()
does for a new session.
Please wait for V4 to fix both Sashiko reviews
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 3/4] scsi: st: Restore the drive buffering mode after reset
2026-09-29 17:18 [PATCH v3 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD Laurence Oberman
2026-09-29 17:18 ` [PATCH v3 1/4] scsi: st: Restore changed drive settings after reset also for MTLOAD and MTRETEN Laurence Oberman
2026-09-29 17:18 ` [PATCH v3 2/4] scsi: st: Record the tape position after a successful MTLOAD Laurence Oberman
@ 2026-09-29 17:18 ` Laurence Oberman
2026-09-29 17:18 ` [PATCH v3 4/4] scsi: st: Relock the door after a reset Laurence Oberman
3 siblings, 0 replies; 9+ messages in thread
From: Laurence Oberman @ 2026-09-29 17:18 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>
---
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 e5b2e2d4872d..efb8c6792c2c 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -2955,9 +2955,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 */
@@ -3603,16 +3605,19 @@ static long st_common_ioctl(struct scsi_tape *STp, struct st_modedef *STm,
}
/*
- * 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))
@@ -3627,7 +3632,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;
@@ -3770,6 +3775,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)
@@ -3781,6 +3789,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)
@@ -3865,7 +3875,8 @@ 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));
if (!retval)
- st_restore_changed_settings(STp, restore_density,
+ st_restore_changed_settings(STp, restore_drv_buffer,
+ restore_density,
restore_blksize);
goto out;
}
@@ -3886,7 +3897,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
@@ -3895,7 +3907,8 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
* overrides the restored settings.
*/
if (check_tape(STp, file) >= 0)
- st_restore_changed_settings(STp, restore_density,
+ st_restore_changed_settings(STp, restore_drv_buffer,
+ restore_density,
restore_blksize);
}
goto out;
@@ -4503,7 +4516,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 0d7c4b8c2c8a..c580024880c3 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.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v3 4/4] scsi: st: Relock the door after a reset
2026-09-29 17:18 [PATCH v3 0/4] scsi: st: Restore drive settings and state after reset and MTLOAD Laurence Oberman
` (2 preceding siblings ...)
2026-09-29 17:18 ` [PATCH v3 3/4] scsi: st: Restore the drive buffering mode after reset Laurence Oberman
@ 2026-09-29 17:18 ` Laurence Oberman
3 siblings, 0 replies; 9+ messages in thread
From: Laurence Oberman @ 2026-09-29 17:18 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>
---
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 efb8c6792c2c..dacd05092e0a 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.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread