diff mbox series

[14/42] scsi: add scsi_result_is_good()

Message ID 20210421174749.11221-15-hare@suse.de
State New
Headers show
Series SCSI result cleanup, part 2 | expand

Commit Message

Hannes Reinecke April 21, 2021, 5:47 p.m. UTC
Add helper to check if the status is 'GOOD', ie if none of the
status bytes are set.

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 include/scsi/scsi_cmnd.h | 4 ++++
 1 file changed, 4 insertions(+)

Comments

Hannes Reinecke April 22, 2021, 6:34 a.m. UTC | #1
On 4/21/21 11:10 PM, Bart Van Assche wrote:
> On 4/21/21 10:47 AM, Hannes Reinecke wrote:
>> +static inline bool scsi_result_is_good(struct scsi_cmnd *cmd)
>> +{
>> +    return (cmd->result == 0);
>> +}
> 
> Do we really need an inline function to compare an integer with zero? 
> How about open-coding this comparison in the callers of this function?
> 
My approach is to avoid direct access to the 'result' field, as the 
definition of which is about to change.

But as this is not part of _this_ patchset I'll drop this patch for the 
next round.

Cheers,

Hannes
Hannes Reinecke April 22, 2021, 8:42 a.m. UTC | #2
On 4/21/21 11:58 PM, Douglas Gilbert wrote:
> On 2021-04-21 5:10 p.m., Bart Van Assche wrote:
>> On 4/21/21 10:47 AM, Hannes Reinecke wrote:
>>> +static inline bool scsi_result_is_good(struct scsi_cmnd *cmd)
>>> +{
>>> +    return (cmd->result == 0);
>>> +}
>>
>> Do we really need an inline function to compare an integer with zero? 
>> How about open-coding this comparison in the callers of this function?
>>
> 
> Please don't open code it. Please fix it!
> Spot the difference:
> 
> static inline int scsi_status_is_good(int status)
> {
>          /*
>           * FIXME: bit0 is listed as reserved in SCSI-2, but is
>           * significant in SCSI-3.  For now, we follow the SCSI-2
>           * behaviour and ignore reserved bits.
>           */
>          status &= 0xfe;
>          return ((status == SAM_STAT_GOOD) ||
>                  (status == SAM_STAT_CONDITION_MET) ||
> /*   >>>                   ^^^^^^^^^^^^^^^^^^^^^^                
> <<<        */
>                  /* Next two "intermediate" statuses are obsolete in 
> SAM-4 */
>                  (status == SAM_STAT_INTERMEDIATE) ||
>                  (status == SAM_STAT_INTERMEDIATE_CONDITION_MET) ||
>                  /* FIXME: this is obsolete in SAM-3 */
>                  (status == SAM_STAT_COMMAND_TERMINATED));
> }
> 
> In sg3_utils' library I ignore the last three SAM_STATs. Not sure if 
> ignoring
> bit 0 is still required.
> 
> Without considering SAM_STAT_CONDITION_MET a good status, someone will be
> scratching their head wondering why so many PRE-FETCH commands fail.
> 
> That command can be used when a sequence of READs to consecutive LBAs is
> followed by a different (i.e. non-consecutive) READ. That last READ could
> be preceded by PRE-FETCH(new_LBA, IMMED). Assuming there is processing
> of the data from the consecutive LBAs to be done, when the time comes
> for READ(new_LBA) the probability of its data being in the disk's cache is
> increased.
> 
That would be a change in behaviour.
Current code doesn't check for CONDITION_MET, so this change shouldn't 
do it, neither. Idea was that this patchset shouldn't change the current 
behaviour.

While your argument might be valid, it definitely is a different story 
and would need to be address with a different patchset.

Cheers,

Hannes
Bart Van Assche April 22, 2021, 4:52 p.m. UTC | #3
On 4/22/21 8:56 AM, Douglas Gilbert wrote:
> In driver manuals Seagate often list the PRE-FETCH command as optional. As
> in: pay us some extra money and we will put it in. That suggests to me some
> big OEM likes PRE-FETCH. Where I found it supported in WDC manuals, they
> didn't support the IMMED bit which sort of defeats the purpose of it IMO.

Since the sd driver does not submit the PRE-FETCH command, how about
moving support for CONDITION MET into the sg code and treating CONDITION
MET as an error inside the sd, sr and st drivers? I think that would
allow to simplify scsi_status_is_good(). The current definition of that
function is as follows:

static inline int scsi_status_is_good(int status)
{
	/*
	 * FIXME: bit0 is listed as reserved in SCSI-2, but is
	 * significant in SCSI-3.  For now, we follow the SCSI-2
	 * behaviour and ignore reserved bits.
	 */
	status &= 0xfe;
	return ((status == SAM_STAT_GOOD) ||
		(status == SAM_STAT_CONDITION_MET) ||
		/* Next two "intermediate" statuses are obsolete in*/
		/* SAM-4 */
		(status == SAM_STAT_INTERMEDIATE) ||
		(status == SAM_STAT_INTERMEDIATE_CONDITION_MET) ||
		/* FIXME: this is obsolete in SAM-3 */
		(status == SAM_STAT_COMMAND_TERMINATED));
}

Thanks,

Bart.
Douglas Gilbert April 22, 2021, 5:33 p.m. UTC | #4
On 2021-04-22 12:52 p.m., Bart Van Assche wrote:
> On 4/22/21 8:56 AM, Douglas Gilbert wrote:
>> In driver manuals Seagate often list the PRE-FETCH command as optional. As
>> in: pay us some extra money and we will put it in. That suggests to me some
>> big OEM likes PRE-FETCH. Where I found it supported in WDC manuals, they
>> didn't support the IMMED bit which sort of defeats the purpose of it IMO.
> 
> Since the sd driver does not submit the PRE-FETCH command, how about
> moving support for CONDITION MET into the sg code and treating CONDITION
> MET as an error inside the sd, sr and st drivers? I think that would
> allow to simplify scsi_status_is_good(). The current definition of that
> function is as follows:
> 
> static inline int scsi_status_is_good(int status)
> {
> 	/*
> 	 * FIXME: bit0 is listed as reserved in SCSI-2, but is
> 	 * significant in SCSI-3.  For now, we follow the SCSI-2
> 	 * behaviour and ignore reserved bits.
> 	 */
> 	status &= 0xfe;
> 	return ((status == SAM_STAT_GOOD) ||
> 		(status == SAM_STAT_CONDITION_MET) ||
> 		/* Next two "intermediate" statuses are obsolete in*/
> 		/* SAM-4 */
> 		(status == SAM_STAT_INTERMEDIATE) ||
> 		(status == SAM_STAT_INTERMEDIATE_CONDITION_MET) ||
> 		/* FIXME: this is obsolete in SAM-3 */
> 		(status == SAM_STAT_COMMAND_TERMINATED));
> }

The whole stack needs to treat SAM_STAT_CONDITION_MET as a non-error.
However the complex multi-layer return values are represented,
reducing them to a comparison with zero, spread all over the
stack just seems bad software engineering. IMO a predicate function
(i.e. returning bool) is needed.

I would argue that in the right circumstances, the sd driver should
indeed by using PRE-FETCH. It would need help from the upper layers.
It is essentially "read-ahead" in the case where the next LBA
does not follow the last read LBA. A smarter read-ahead ...

Doug Gilbert
Hannes Reinecke April 26, 2021, 8:45 a.m. UTC | #5
On 4/22/21 7:33 PM, Douglas Gilbert wrote:
> On 2021-04-22 12:52 p.m., Bart Van Assche wrote:

>> On 4/22/21 8:56 AM, Douglas Gilbert wrote:

>>> In driver manuals Seagate often list the PRE-FETCH command as

>>> optional. As

>>> in: pay us some extra money and we will put it in. That suggests to

>>> me some

>>> big OEM likes PRE-FETCH. Where I found it supported in WDC manuals, they

>>> didn't support the IMMED bit which sort of defeats the purpose of it

>>> IMO.

>>

>> Since the sd driver does not submit the PRE-FETCH command, how about

>> moving support for CONDITION MET into the sg code and treating CONDITION

>> MET as an error inside the sd, sr and st drivers? I think that would

>> allow to simplify scsi_status_is_good(). The current definition of that

>> function is as follows:

>>

>> static inline int scsi_status_is_good(int status)

>> {

>>     /*

>>      * FIXME: bit0 is listed as reserved in SCSI-2, but is

>>      * significant in SCSI-3.  For now, we follow the SCSI-2

>>      * behaviour and ignore reserved bits.

>>      */

>>     status &= 0xfe;

>>     return ((status == SAM_STAT_GOOD) ||

>>         (status == SAM_STAT_CONDITION_MET) ||

>>         /* Next two "intermediate" statuses are obsolete in*/

>>         /* SAM-4 */

>>         (status == SAM_STAT_INTERMEDIATE) ||

>>         (status == SAM_STAT_INTERMEDIATE_CONDITION_MET) ||

>>         /* FIXME: this is obsolete in SAM-3 */

>>         (status == SAM_STAT_COMMAND_TERMINATED));

>> }

> 

> The whole stack needs to treat SAM_STAT_CONDITION_MET as a non-error.

> However the complex multi-layer return values are represented,

> reducing them to a comparison with zero, spread all over the

> stack just seems bad software engineering. IMO a predicate function

> (i.e. returning bool) is needed.

> 

> I would argue that in the right circumstances, the sd driver should

> indeed by using PRE-FETCH. It would need help from the upper layers.

> It is essentially "read-ahead" in the case where the next LBA

> does not follow the last read LBA. A smarter read-ahead ...

> 

Might, but again not something we should attempt in this patchset.

Using PRE-FETCH might be worthwhile for larger I/O, which we could
easily prepend with a PRE-FETCH command for the entire range.
But then error handling for PRE-FETCH is decidedly tricky, and we might
end up incurring quite some regressions just because we didn't get the
error handling right in the first go.

Worth a shot, but please in another patchset.

The other use-case for using PRE-FETCH after cryptographic erase
definitely is required, but as that's triggered by userspace I would
expect userspace to do it properly, too.

The only valid use-case I see would be for issuing PRE-FETCH after
UNMAP, but that would need to be plugged into the 'discard' machinery,
which is already fragile as hell; I'd rather not attempt that one.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		        Kernel Storage Architect
hare@suse.de			               +49 911 74053 688
SUSE Software Solutions Germany GmbH, 90409 Nürnberg
GF: F. Imendörffer, HRB 36809 (AG Nürnberg)
diff mbox series

Patch

diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 0ac18a7d8ac6..7089617911e1 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -336,6 +336,10 @@  static inline unsigned char get_host_byte(struct scsi_cmnd *cmd)
 	return (cmd->result >> 16) & 0xff;
 }
 
+static inline bool scsi_result_is_good(struct scsi_cmnd *cmd)
+{
+	return (cmd->result == 0);
+}
 
 static inline unsigned scsi_transfer_length(struct scsi_cmnd *scmd)
 {