diff mbox series

[2/3] scsi: st: clear was_reset when CHKRES_NEW_SESSION

Message ID 20241031010032.117296-3-jmeneghi@redhat.com
State New
Headers show
Series scsi: st: improve pos_unknown handling after reset | expand

Commit Message

John Meneghini Oct. 31, 2024, 1 a.m. UTC
Be sure to clear was_reset when ever we clear pos_unknown. If we don't
then the code in st_chk_result() will turn on pos_unknown again.

        STp->pos_unknown |= STp->device->was_reset;

This results in confusion as future commands fail unexpectedly.

Signed-off-by: John Meneghini <jmeneghi@redhat.com>
---
 drivers/scsi/st.c | 1 +
 1 file changed, 1 insertion(+)

Comments

Kai Mäkisara Nov. 3, 2024, 6:32 p.m. UTC | #1
> On 31. Oct 2024, at 3.00, John Meneghini <jmeneghi@redhat.com> wrote:
> 
> Be sure to clear was_reset when ever we clear pos_unknown. If we don't
> then the code in st_chk_result() will turn on pos_unknown again.
> 
>        STp->pos_unknown |= STp->device->was_reset;
> 
> This results in confusion as future commands fail unexpectedly.

This brings in my mind (again) the question: is the hack using was_reset set
by scsi_error to detect device reset necessary any more? It was introduced
as a temporary method somewhere between 1.3.20 and 1.3.30 (in 1995)
when the POR (power on/reset) UAs (Unit Attention) were not passed to st.
The worst problem with this hack is clearing was_reset. St should not clear
something set by error handling (layering violation).

Your earlier patch added code to st to set pos_unknown when a POR UA
was found. So, is this now alone enough to catch the resets?

I now did some experiments with scsi_debug and in those experiments
reset initiated using sg_reset did result in st getting POR UA.
But this was just a simple and somewhat artificial test.
John Meneghini Nov. 7, 2024, 4:05 p.m. UTC | #2
On 11/3/24 13:32, "Kai Mäkisara (Kolumbus)" wrote:
>> On 31. Oct 2024, at 3.00, John Meneghini <jmeneghi@redhat.com> wrote:
>>
>> Be sure to clear was_reset when ever we clear pos_unknown. If we don't
>> then the code in st_chk_result() will turn on pos_unknown again.
>>
>>         STp->pos_unknown |= STp->device->was_reset;
>>
>> This results in confusion as future commands fail unexpectedly.
> 
> This brings in my mind (again) the question: is the hack using was_reset set
> by scsi_error to detect device reset necessary any more? It was introduced
> as a temporary method somewhere between 1.3.20 and 1.3.30 (in 1995)
> when the POR (power on/reset) UAs (Unit Attention) were not passed to st.
> The worst problem with this hack is clearing was_reset. St should not clear
> something set by error handling (layering violation).

OK. I wasn't aware of the history here... but I agree we want to get rid of the layering violation.

> Your earlier patch added code to st to set pos_unknown when a POR UA
> was found. So, is this now alone enough to catch the resets?

As long at the tape device actually sends a UA, no I don't think we need the was_reset code anymore.
We should remove the device->was_reset code from st.c.

> I now did some experiments with scsi_debug and in those experiments
> reset initiated using sg_reset did result in st getting POR UA.
> But this was just a simple and somewhat artificial test.

Yes, I've noticed that not all of the different emulators out there like MHVTL and scsi_debug
will reliably send a POR UA following sg_reset. Especially scsi_debug. The tape emulation in
scsi_debug is inadequate when it comes to resets AFAIAC.

I'll see if I can develop some further tests for MHVLT, but scsi_debug isn't worth the
trouble (for me) and I've told our QE group here at Red Hat to stop testing the st driver
with scsi_debug.  Doing this has led to too many false positives and passing tests. That's
why I finally purchased a tape drive and started testing this myself.

If you want to remove the device->was_reset from the st driver I can help by running
the patch through my tests with the tape device.
Kai Mäkisara Nov. 14, 2024, 4:51 p.m. UTC | #3
> On 7. Nov 2024, at 18.05, John Meneghini <jmeneghi@redhat.com> wrote:
> 
> On 11/3/24 13:32, "Kai Mäkisara (Kolumbus)" wrote:
>>> On 31. Oct 2024, at 3.00, John Meneghini <jmeneghi@redhat.com> wrote:
>>> 
>>> Be sure to clear was_reset when ever we clear pos_unknown. If we don't
>>> then the code in st_chk_result() will turn on pos_unknown again.
>>> 
>>>        STp->pos_unknown |= STp->device->was_reset;
>>> 
>>> This results in confusion as future commands fail unexpectedly.
>> This brings in my mind (again) the question: is the hack using was_reset set
>> by scsi_error to detect device reset necessary any more? It was introduced
>> as a temporary method somewhere between 1.3.20 and 1.3.30 (in 1995)
>> when the POR (power on/reset) UAs (Unit Attention) were not passed to st.
>> The worst problem with this hack is clearing was_reset. St should not clear
>> something set by error handling (layering violation).
> 
> OK. I wasn't aware of the history here... but I agree we want to get rid of the layering violation.
> 
I have read code and done experiments. I think I now know how the POR UAs were lost
in 1990s. And why that does not happen now.

In 1.3.30, scsi.c handled resets. When resetting, it set the device->expecting_cc_ua flag.
If UA was received when expecting_cc_ua was set, the command was retried if
retries were allowed. St allowed five retries for TEST UNIT READY and so the POR UA
was left in the midlevel. (If expecting_cc_ua was zero, UA:s were returned to the upper
level.)

Now, st does allow zero retries. In addition to this, the requests use either REQ_OP_DRV_IN
or REQ_OP_DRV_OUT and these requests are not retried. So, now POR UAs reach
st (as the experiments have indicated).

>> Your earlier patch added code to st to set pos_unknown when a POR UA
>> was found. So, is this now alone enough to catch the resets?
> 
> As long at the tape device actually sends a UA, no I don't think we need the was_reset code anymore.
> We should remove the device->was_reset code from st.c.
> 
Using device->was_reset has the advantage that it does not depend on the
drives sending UA. However, I think that a probability of a working drive
not sending UA after reset is minimal.

>> I now did some experiments with scsi_debug and in those experiments
>> reset initiated using sg_reset did result in st getting POR UA.
>> But this was just a simple and somewhat artificial test.
> 
> Yes, I've noticed that not all of the different emulators out there like MHVTL and scsi_debug
> will reliably send a POR UA following sg_reset. Especially scsi_debug. The tape emulation in
> scsi_debug is inadequate when it comes to resets AFAIAC.
> 
> I'll see if I can develop some further tests for MHVLT, but scsi_debug isn't worth the
> trouble (for me) and I've told our QE group here at Red Hat to stop testing the st driver
> with scsi_debug.  Doing this has led to too many false positives and passing tests. That's
> why I finally purchased a tape drive and started testing this myself.

I have a more positive view about scsi_debug. Its tape support is minimal, but it can be
useful if you consider what it does support and what it doesn't support.

A real drive is better, of course.

> If you want to remove the device->was_reset from the st driver I can help by running
> the patch through my tests with the tape device.

I will send patches tomorrow. The patches will also include a fix to another problem:
some parameters should be restored after reset in case of some operations like rewind:
the partition, density and block size should be restored to the values set before reset.

Thanks for your testing (so far and in future).

Kai
John Meneghini Nov. 15, 2024, 3:34 p.m. UTC | #4
On 11/14/24 11:51, "Kai Mäkisara (Kolumbus)" wrote:>
>> On 7. Nov 2024, at 18.05, John Meneghini <jmeneghi@redhat.com> wrote:
>>
>> On 11/3/24 13:32, "Kai Mäkisara (Kolumbus)" wrote:
>>>> On 31. Oct 2024, at 3.00, John Meneghini <jmeneghi@redhat.com> wrote:
>>>>
>>>> Be sure to clear was_reset when ever we clear pos_unknown. If we don't
>>>> then the code in st_chk_result() will turn on pos_unknown again.
>>>>
>>>>         STp->pos_unknown |= STp->device->was_reset;
>>>>
>>>> This results in confusion as future commands fail unexpectedly.
>>> This brings in my mind (again) the question: is the hack using was_reset set
>>> by scsi_error to detect device reset necessary any more? It was introduced
>>> as a temporary method somewhere between 1.3.20 and 1.3.30 (in 1995)
>>> when the POR (power on/reset) UAs (Unit Attention) were not passed to st.
>>> The worst problem with this hack is clearing was_reset. St should not clear
>>> something set by error handling (layering violation).
>>
>> OK. I wasn't aware of the history here... but I agree we want to get rid of the layering violation.
>>
> I have read code and done experiments. I think I now know how the POR UAs were lost
> in 1990s. And why that does not happen now.
> 
> In 1.3.30, scsi.c handled resets. When resetting, it set the device->expecting_cc_ua flag.
> If UA was received when expecting_cc_ua was set, the command was retried if
> retries were allowed. St allowed five retries for TEST UNIT READY and so the POR UA
> was left in the midlevel. (If expecting_cc_ua was zero, UA:s were returned to the upper
> level.)

> Now, st does allow zero retries. In addition to this, the requests use either REQ_OP_DRV_IN
> or REQ_OP_DRV_OUT and these requests are not retried. So, now POR UAs reach
> st (as the experiments have indicated).

Yes, the only time I've see the POR UA not get passed to the st driver is with scsi_debug, when
the driver first loads.

[tape_tests]# modprobe -r scsi_debug
[tape_tests]# modprobe scsi_debug  ptype=1  max_luns=1 dev_size_mb=10000
[Fri Nov 15 09:28:51 2024] scsi_debug:sdebug_driver_probe: scsi_debug: trim poll_queues to 0. poll_q/nr_hw = (0/1)
[Fri Nov 15 09:28:51 2024] scsi host8: scsi_debug: version 0191 [20210520]
                              dev_size_mb=10000, opts=0x0, submit_queues=1, statistics=0
[Fri Nov 15 09:28:51 2024] scsi 8:0:0:0: Sequential-Access Linux    scsi_debug       0191 PQ: 0 ANSI: 7
[Fri Nov 15 09:28:51 2024] scsi 8:0:0:0: Power-on or device reset occurred
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The sg driver is clearing the UA here.

[Fri Nov 15 09:28:51 2024] st 8:0:0:0: Attached scsi tape st1
[Fri Nov 15 09:28:51 2024] st 8:0:0:0: st1: try direct i/o: yes (alignment 4 B)
[Fri Nov 15 09:28:51 2024] st 8:0:0:0: Attached scsi generic sg3 type 1

[tape_tests]# mt -f /dev/nst1 status
[Fri Nov 15 09:28:55 2024] st 8:0:0:0: [st1] check_tape: 1064: pos_unknown 0 was_reset 0 ready 0
[Fri Nov 15 09:28:55 2024] st 8:0:0:0: [st1] Error: 402, cmd: 5 0 0 0 0 0
[Fri Nov 15 09:28:55 2024] st 8:0:0:0: [st1] Sense Key : Illegal Request [current]
[Fri Nov 15 09:28:55 2024] st 8:0:0:0: [st1] Add. Sense: Invalid command operation code
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There should be a UA right here.

I have no idea whey the scsi_debug driver doesn't support READ BLOCK LIMITS.

[Fri Nov 15 09:28:55 2024] st 8:0:0:0: [st1] st_chk_result: 421: pos_unknown 0 was_reset 0 ready 0, result 1026
[Fri Nov 15 09:28:55 2024] st 8:0:0:0: [st1] Can't read block limits.
SCSI 2 tape drive:
File number=-1, block number=-1, partition=0.
Tape block size 0 bytes. Density code 0x0 (default).
Soft error count since last status=0
General status bits on (1010000):
  ONLINE IM_REP_EN

Another problem with using scsi_debug is:

[tape_tests]# sg_reset --target /dev/sg3

This does nothing.  I have to use the /dev/st device to reset.  This is not true if you have a real tape device.

[tape_tests]# sg_reset --target /dev/nst1
[Fri Nov 15 09:37:18 2024] st 8:0:0:0: [st1] check_tape: 1064: pos_unknown 0 was_reset 1 ready 0
[Fri Nov 15 09:37:18 2024] st 8:0:0:0: Power-on or device reset occurred
[Fri Nov 15 09:37:18 2024] st 8:0:0:0: [st1] Error: 2, cmd: 0 0 0 0 0 0
[Fri Nov 15 09:37:18 2024] st 8:0:0:0: [st1] Sense Key : Unit Attention [current]
[Fri Nov 15 09:37:18 2024] st 8:0:0:0: [st1] Add. Sense: Scsi bus reset occurred
[Fri Nov 15 09:37:18 2024] st 8:0:0:0: [st1] st_chk_result: 421: pos_unknown 1 was_reset 1 ready 0, result 2
^^^^^^^^^^^^^^^^^^
Now we've set pos_unkown.

>>> Your earlier patch added code to st to set pos_unknown when a POR UA
>>> was found. So, is this now alone enough to catch the resets?
>>
>> As long at the tape device actually sends a UA, no I don't think we need the was_reset code anymore.
>> We should remove the device->was_reset code from st.c. >
> Using device->was_reset has the advantage that it does not depend on the
> drives sending UA. However, I think that a probability of a working drive
> not sending UA after reset is minimal.

Agreed. There are some idiosyncrasies in the scsi_debug tape emulation. But I don't want those problems to make their way into 
the st driver. I don't think the st driver should be paying attention to was_reset, or anything else in the mid layer.

>>> I now did some experiments with scsi_debug and in those experiments
>>> reset initiated using sg_reset did result in st getting POR UA.
>>> But this was just a simple and somewhat artificial test.
>>
>> Yes, I've noticed that not all of the different emulators out there like MHVTL and scsi_debug
>> will reliably send a POR UA following sg_reset. Especially scsi_debug. The tape emulation in
>> scsi_debug is inadequate when it comes to resets AFAIAC.
>>
>> I'll see if I can develop some further tests for MHVLT, but scsi_debug isn't worth the
>> trouble (for me) and I've told our QE group here at Red Hat to stop testing the st driver
>> with scsi_debug.  Doing this has led to too many false positives and passing tests. That's
>> why I finally purchased a tape drive and started testing this myself.
> 
> I have a more positive view about scsi_debug. Its tape support is minimal, but it can be
> useful if you consider what it does support and what it doesn't support.
> 
> A real drive is better, of course.

Please try my latest version of the tape_reset_debug.sh script.

https://github.com/johnmeneghini/tape_tests/blob/master/tape_reset_debug.sh

This test uses the scsi_debug driver with ptype=1 to test these patches using "sg_reset --target /dev/nst$i".

There is also the tape_reset_debug_sg.sh script. That script runs the same tests using "sg_reset --target /dev/sg$i"

They each give me different false negative and false positive results... but that may because of something I'm doing wrong.

>> If you want to remove the device->was_reset from the st driver I can help by running
>> the patch through my tests with the tape device.
> 
> I will send patches tomorrow. The patches will also include a fix to another problem:
> some parameters should be restored after reset in case of some operations like rewind:
> the partition, density and block size should be restored to the values set before reset.

OK, I will test those as soon as they show up.

> Thanks for your testing (so far and in future).

And Thanks for your help fixing these bugs...

/John

> Kai
>
Kai Mäkisara Nov. 18, 2024, 5:10 p.m. UTC | #5
> On 15. Nov 2024, at 17.34, John Meneghini <jmeneghi@redhat.com> wrote:
> 
...
>> Now, st does allow zero retries. In addition to this, the requests use either REQ_OP_DRV_IN
>> or REQ_OP_DRV_OUT and these requests are not retried. So, now POR UAs reach
>> st (as the experiments have indicated).
> 
> Yes, the only time I've see the POR UA not get passed to the st driver is with scsi_debug, when
> the driver first loads.
> 
> [tape_tests]# modprobe -r scsi_debug
> [tape_tests]# modprobe scsi_debug  ptype=1  max_luns=1 dev_size_mb=10000
> [Fri Nov 15 09:28:51 2024] scsi_debug:sdebug_driver_probe: scsi_debug: trim poll_queues to 0. poll_q/nr_hw = (0/1)
> [Fri Nov 15 09:28:51 2024] scsi host8: scsi_debug: version 0191 [20210520]
>                             dev_size_mb=10000, opts=0x0, submit_queues=1, statistics=0
> [Fri Nov 15 09:28:51 2024] scsi 8:0:0:0: Sequential-Access Linux    scsi_debug       0191 PQ: 0 ANSI: 7
> [Fri Nov 15 09:28:51 2024] scsi 8:0:0:0: Power-on or device reset occurred
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> The sg driver is clearing the UA here.

I enabled some SCSI debug logging (0x3001). It shows that the UA is received as response to
a 'Report supported operation codes' command. I looked at the code and it seems that scsi_add_lun()
in scsi_scan.c uses this operation. So, the UA is not cleared by any ULD.

...

> I have no idea whey the scsi_debug driver doesn't support READ BLOCK LIMITS.
> 
scsi_debug does not support any "tape-specific" commands. This includes READ BLOCK LIMITS,
WRITE FILEMARKS, REWIND, etc. Additionally the CDB definition for tapes is special for reads and
writes.

REWIND is implemented in scsi_debug, but it is buggy. MODE SENSE and MODE SELECT without
any page (i.e., interested only in block descriptor) are not allowed in scsi_debug.

St is designed to work with minimal command support. READ BLOCK LIMITS is not needed. I have
fixed REWIND and MODE SENSE/SELECT for my tests. Using fake_rw I can "read" tape, but
writing does not work because WRITE FILEMARKS is missing.

...
> Another problem with using scsi_debug is:
> 
> [tape_tests]# sg_reset --target /dev/sg3
> 
> This does nothing.  I have to use the /dev/st device to reset.  This is not true if you have a real tape device.

In my tests, resets using both /dev/nstx and /dev/sgx have been working. However, you should note that
when using /dev/nstx, the device is opened using st driver, whereas if /dev/sgx is used, it is opened
using the sg driver. Digging deeper reveals that SG_SCSI_RESET through st does not go through
sg at all. (Both end up to scsi_ioctl_reset() in scsi_error.c, but in a different way.) (And if you use,
/dev/stx, the tape is rewound.)

> [tape_tests]# sg_reset --target /dev/nst1
> [Fri Nov 15 09:37:18 2024] st 8:0:0:0: [st1] check_tape: 1064: pos_unknown 0 was_reset 1 ready 0
> [Fri Nov 15 09:37:18 2024] st 8:0:0:0: Power-on or device reset occurred
> [Fri Nov 15 09:37:18 2024] st 8:0:0:0: [st1] Error: 2, cmd: 0 0 0 0 0 0
> [Fri Nov 15 09:37:18 2024] st 8:0:0:0: [st1] Sense Key : Unit Attention [current]
> [Fri Nov 15 09:37:18 2024] st 8:0:0:0: [st1] Add. Sense: Scsi bus reset occurred
> [Fri Nov 15 09:37:18 2024] st 8:0:0:0: [st1] st_chk_result: 421: pos_unknown 1 was_reset 1 ready 0, result 2
> ^^^^^^^^^^^^^^^^^^
> Now we've set pos_unkown.

If you use /dev/sgx, you are not supposed to see any output. The next operation sent to /dev/nstx
(e.g., mt status) sets pos_unknown. In the example above, you probably have used sg_reset -target
/dev/sg1 previously and it is opening /dev/nst1 the the next sg_reset that catches the previous reset.

...
> 
> Please try my latest version of the tape_reset_debug.sh script.

I looked at the script. It tries to write to tape and that is not implemented in the scsi_debug I have
diff mbox series

Patch

diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 9c0f9779768e..e9d1cb6c8a86 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -1083,6 +1083,7 @@  static int check_tape(struct scsi_tape *STp, struct file *filp)
 
 	if (retval == CHKRES_NEW_SESSION) {
 		STp->pos_unknown = 0;
+		STp->device->was_reset = 0;
 		STp->partition = STp->new_partition = 0;
 		if (STp->can_partitions)
 			STp->nbr_partitions = 1; /* This guess will be updated later