diff mbox series

[2/3] scsi: libsas: Add return_fis_on_success to sas_ata_task

Message ID 20230817214137.462044-2-ipylypiv@google.com
State Superseded
Headers show
Series [1/3] ata: libata: Introduce ata_qc_has_cdl() | expand

Commit Message

Igor Pylypiv Aug. 17, 2023, 9:41 p.m. UTC
For Command Duration Limits policy 0xD (command completes without
an error) libata needs FIS in order to detect the ATA_SENSE bit and
read the Sense Data for Successful NCQ Commands log (0Fh).

Set return_fis_on_success for commands that have a CDL descriptor
since any CDL descriptor can be configured with policy 0xD.

Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
---
 drivers/scsi/libsas/sas_ata.c | 3 +++
 include/scsi/libsas.h         | 1 +
 2 files changed, 4 insertions(+)

Comments

Damien Le Moal Aug. 17, 2023, 11:12 p.m. UTC | #1
On 2023/08/18 6:41, Igor Pylypiv wrote:
> For Command Duration Limits policy 0xD (command completes without
> an error) libata needs FIS in order to detect the ATA_SENSE bit and
> read the Sense Data for Successful NCQ Commands log (0Fh).
> 
> Set return_fis_on_success for commands that have a CDL descriptor
> since any CDL descriptor can be configured with policy 0xD.
> 
> Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
> ---
>  drivers/scsi/libsas/sas_ata.c | 3 +++
>  include/scsi/libsas.h         | 1 +
>  2 files changed, 4 insertions(+)
> 
> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
> index 77714a495cbb..da67c4f671b2 100644
> --- a/drivers/scsi/libsas/sas_ata.c
> +++ b/drivers/scsi/libsas/sas_ata.c
> @@ -207,6 +207,9 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
>  	task->ata_task.use_ncq = ata_is_ncq(qc->tf.protocol);
>  	task->ata_task.dma_xfer = ata_is_dma(qc->tf.protocol);
>  
> +	/* CDL policy 0xD requires FIS for successful (no error) completions */
> +	task->ata_task.return_fis_on_success = ata_qc_has_cdl(qc);
Niklas Cassel Aug. 17, 2023, 11:36 p.m. UTC | #2
On Thu, Aug 17, 2023 at 02:41:36PM -0700, Igor Pylypiv wrote:

Hello Igor,

> For Command Duration Limits policy 0xD (command completes without
> an error) libata needs FIS in order to detect the ATA_SENSE bit and
> read the Sense Data for Successful NCQ Commands log (0Fh).
> 
> Set return_fis_on_success for commands that have a CDL descriptor
> since any CDL descriptor can be configured with policy 0xD.
> 
> Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
> ---
>  drivers/scsi/libsas/sas_ata.c | 3 +++
>  include/scsi/libsas.h         | 1 +
>  2 files changed, 4 insertions(+)
> 
> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
> index 77714a495cbb..da67c4f671b2 100644
> --- a/drivers/scsi/libsas/sas_ata.c
> +++ b/drivers/scsi/libsas/sas_ata.c
> @@ -207,6 +207,9 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
>  	task->ata_task.use_ncq = ata_is_ncq(qc->tf.protocol);
>  	task->ata_task.dma_xfer = ata_is_dma(qc->tf.protocol);
>  
> +	/* CDL policy 0xD requires FIS for successful (no error) completions */
> +	task->ata_task.return_fis_on_success = ata_qc_has_cdl(qc);

In ata_qc_complete(), for a successful command, we call fill_result_tf()
if (qc->flags & ATA_QCFLAG_RESULT_TF):
https://github.com/torvalds/linux/blob/v6.5-rc6/drivers/ata/libata-core.c#L4926

My point is, I think that you should set
task->ata_task.return_fis_on_success = ata_qc_wants_result(qc);

where ata_qc_wants_result()
returns true if ATA_QCFLAG_RESULT_TF is set.

(ata_set_tf_cdl() will set both ATA_QCFLAG_HAS_CDL and ATA_QCFLAG_RESULT_TF).

That way, e.g. an internal command (i.e. a command issued by
ata_exec_internal_sg()), which always has ATA_QCFLAG_RESULT_TF set,
will always gets an up to date tf status and tf error value back,
because the SAS HBA will send a FIS back.

If we don't do this, then libsas will instead fill in the tf status and
tf error from the last command that returned a FIS (which might be out
of date).


> +
>  	if (qc->scsicmd)
>  		ASSIGN_SAS_TASK(qc->scsicmd, task);
>  
> diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
> index 159823e0afbf..9e2c69c13dd3 100644
> --- a/include/scsi/libsas.h
> +++ b/include/scsi/libsas.h
> @@ -550,6 +550,7 @@ struct sas_ata_task {
>  	u8     use_ncq:1;
>  	u8     set_affil_pol:1;
>  	u8     stp_affil_pol:1;
> +	u8     return_fis_on_success:1;
>  
>  	u8     device_control_reg_update:1;
>  
> -- 
> 2.42.0.rc1.204.g551eb34607-goog
> 

Considering that libsas return value is defined like this:
https://github.com/torvalds/linux/blob/v6.5-rc6/include/scsi/libsas.h#L507

Basically, if you returned a FIS in resp->ending_fis, you should return
SAS_PROTO_RESPONSE. If you didn't return a FIS for your command, then
you return SAS_SAM_STAT_GOOD (or if it is an error, a SAS_ error code
that is not SAS_PROTO_RESPONSE, as you didn't return a FIS).

Since you have implemented this only for pm80xx, how about adding something
like this to sas_ata_task_done:

diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 77714a495cbb..e1c56c2c00a5 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -114,6 +114,15 @@ static void sas_ata_task_done(struct sas_task *task)
                }
        }
 
+       /*
+        * If a FIS was requested for a good command, and the lldd returned
+        * SAS_SAM_STAT_GOOD instead of SAS_PROTO_RESPONSE, then the lldd
+        * has not implemented support for sas_ata_task.return_fis_on_success
+        * Warn about this once. If we don't return FIS on success, then we
+        * won't be able to return an up to date TF.status and TF.error.
+        */
+       WARN_ON_ONCE(ata_qc_wants_result(qc) && stat->stat == SAS_SAM_STAT_GOOD);
+
        if (stat->stat == SAS_PROTO_RESPONSE ||
            stat->stat == SAS_SAM_STAT_GOOD ||
            (stat->stat == SAS_SAM_STAT_CHECK_CONDITION &&




Kind regards,
Niklas
Niklas Cassel Aug. 17, 2023, 11:50 p.m. UTC | #3
On Fri, Aug 18, 2023 at 08:12:02AM +0900, Damien Le Moal wrote:
> On 2023/08/18 6:41, Igor Pylypiv wrote:
> > For Command Duration Limits policy 0xD (command completes without
> > an error) libata needs FIS in order to detect the ATA_SENSE bit and
> > read the Sense Data for Successful NCQ Commands log (0Fh).
> > 
> > Set return_fis_on_success for commands that have a CDL descriptor
> > since any CDL descriptor can be configured with policy 0xD.
> > 
> > Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
> > ---
> >  drivers/scsi/libsas/sas_ata.c | 3 +++
> >  include/scsi/libsas.h         | 1 +
> >  2 files changed, 4 insertions(+)
> > 
> > diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
> > index 77714a495cbb..da67c4f671b2 100644
> > --- a/drivers/scsi/libsas/sas_ata.c
> > +++ b/drivers/scsi/libsas/sas_ata.c
> > @@ -207,6 +207,9 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
> >  	task->ata_task.use_ncq = ata_is_ncq(qc->tf.protocol);
> >  	task->ata_task.dma_xfer = ata_is_dma(qc->tf.protocol);
> >  
> > +	/* CDL policy 0xD requires FIS for successful (no error) completions */
> > +	task->ata_task.return_fis_on_success = ata_qc_has_cdl(qc);
> 
> From the comments on patch 1, this should be:
> 
> 	if (qc->flags & ATA_QCFLAG_HAS_CDL)
> 		task->ata_task.return_sdb_fis_on_success = 1;
> 
> Note the renaming to "return_sdb_fis_on_success" to be clear about the FIS type.

I'm not sure if I agree with this comment.

According to the pm80xx programmers manual,
setting the RETFIS bit enables the HBA to return a FIS for a successful
command:

PIO Read: Nothing is returned
PIO Write: Device To Host FIS received from the device.
DMA Read: Device To Host FIS received from the device.
DMA Write: Device To Host FIS received from the device.
FPDMA Read: Set Device Bit FIS received from the device.
FPDMA Write: Set Device Bit FIS received from the device.
Non-Data: Device To Host FIS received from the device.

So the FIS you get back can also be e.g. a D2H FIS, if you send
e.g. a DMA read command.

If the RETFIS bit is not set, and the command was successful,
no FIS will be returned.

So if you really want to rename this bit, then we would also need to
change the logic in pm80xx to be something like:
if (ata_is_ncq() && task->ata_task.return_sdb_fis_on_success)
	set_RETFIS_bit;

Doesn't it make more sense for this generic libsas flag to keep its
current name, i.e. it means that we enable FIS reception for successful
commands, regardless of FIS type?


Kind regards,
Niklas
Damien Le Moal Aug. 18, 2023, 12:06 a.m. UTC | #4
On 2023/08/18 8:50, Niklas Cassel wrote:
> On Fri, Aug 18, 2023 at 08:12:02AM +0900, Damien Le Moal wrote:
>> On 2023/08/18 6:41, Igor Pylypiv wrote:
>>> For Command Duration Limits policy 0xD (command completes without
>>> an error) libata needs FIS in order to detect the ATA_SENSE bit and
>>> read the Sense Data for Successful NCQ Commands log (0Fh).
>>>
>>> Set return_fis_on_success for commands that have a CDL descriptor
>>> since any CDL descriptor can be configured with policy 0xD.
>>>
>>> Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
>>> ---
>>>  drivers/scsi/libsas/sas_ata.c | 3 +++
>>>  include/scsi/libsas.h         | 1 +
>>>  2 files changed, 4 insertions(+)
>>>
>>> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
>>> index 77714a495cbb..da67c4f671b2 100644
>>> --- a/drivers/scsi/libsas/sas_ata.c
>>> +++ b/drivers/scsi/libsas/sas_ata.c
>>> @@ -207,6 +207,9 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
>>>  	task->ata_task.use_ncq = ata_is_ncq(qc->tf.protocol);
>>>  	task->ata_task.dma_xfer = ata_is_dma(qc->tf.protocol);
>>>  
>>> +	/* CDL policy 0xD requires FIS for successful (no error) completions */
>>> +	task->ata_task.return_fis_on_success = ata_qc_has_cdl(qc);
>>
>> From the comments on patch 1, this should be:
>>
>> 	if (qc->flags & ATA_QCFLAG_HAS_CDL)
>> 		task->ata_task.return_sdb_fis_on_success = 1;
>>
>> Note the renaming to "return_sdb_fis_on_success" to be clear about the FIS type.
> 
> I'm not sure if I agree with this comment.
> 
> According to the pm80xx programmers manual,
> setting the RETFIS bit enables the HBA to return a FIS for a successful
> command:
> 
> PIO Read: Nothing is returned
> PIO Write: Device To Host FIS received from the device.
> DMA Read: Device To Host FIS received from the device.
> DMA Write: Device To Host FIS received from the device.
> FPDMA Read: Set Device Bit FIS received from the device.
> FPDMA Write: Set Device Bit FIS received from the device.
> Non-Data: Device To Host FIS received from the device.
> 
> So the FIS you get back can also be e.g. a D2H FIS, if you send
> e.g. a DMA read command.

Right. Forgot about non NCQ commands :)
So no need for renaming to sdb_fis. Apologies for the noise.

> 
> If the RETFIS bit is not set, and the command was successful,
> no FIS will be returned.
> 
> So if you really want to rename this bit, then we would also need to
> change the logic in pm80xx to be something like:
> if (ata_is_ncq() && task->ata_task.return_sdb_fis_on_success)
> 	set_RETFIS_bit;
> 
> Doesn't it make more sense for this generic libsas flag to keep its
> current name, i.e. it means that we enable FIS reception for successful
> commands, regardless of FIS type?

Yes.

> 
> 
> Kind regards,
> Niklas
Damien Le Moal Aug. 18, 2023, 12:08 a.m. UTC | #5
On 2023/08/18 8:36, Niklas Cassel wrote:
> On Thu, Aug 17, 2023 at 02:41:36PM -0700, Igor Pylypiv wrote:
> 
> Hello Igor,
> 
>> For Command Duration Limits policy 0xD (command completes without
>> an error) libata needs FIS in order to detect the ATA_SENSE bit and
>> read the Sense Data for Successful NCQ Commands log (0Fh).
>>
>> Set return_fis_on_success for commands that have a CDL descriptor
>> since any CDL descriptor can be configured with policy 0xD.
>>
>> Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
>> ---
>>  drivers/scsi/libsas/sas_ata.c | 3 +++
>>  include/scsi/libsas.h         | 1 +
>>  2 files changed, 4 insertions(+)
>>
>> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
>> index 77714a495cbb..da67c4f671b2 100644
>> --- a/drivers/scsi/libsas/sas_ata.c
>> +++ b/drivers/scsi/libsas/sas_ata.c
>> @@ -207,6 +207,9 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
>>  	task->ata_task.use_ncq = ata_is_ncq(qc->tf.protocol);
>>  	task->ata_task.dma_xfer = ata_is_dma(qc->tf.protocol);
>>  
>> +	/* CDL policy 0xD requires FIS for successful (no error) completions */
>> +	task->ata_task.return_fis_on_success = ata_qc_has_cdl(qc);
> 
> In ata_qc_complete(), for a successful command, we call fill_result_tf()
> if (qc->flags & ATA_QCFLAG_RESULT_TF):
> https://github.com/torvalds/linux/blob/v6.5-rc6/drivers/ata/libata-core.c#L4926
> 
> My point is, I think that you should set
> task->ata_task.return_fis_on_success = ata_qc_wants_result(qc);
> 
> where ata_qc_wants_result()
> returns true if ATA_QCFLAG_RESULT_TF is set.

I do not think we need that helper. Testing the flag directly would be fine.
If you really insist on introducing the helper, then at least go through libata
and replace all direct tests of that flag with the helper. But I do not think it
is worth the churn.

> 
> (ata_set_tf_cdl() will set both ATA_QCFLAG_HAS_CDL and ATA_QCFLAG_RESULT_TF).
> 
> That way, e.g. an internal command (i.e. a command issued by
> ata_exec_internal_sg()), which always has ATA_QCFLAG_RESULT_TF set,
> will always gets an up to date tf status and tf error value back,
> because the SAS HBA will send a FIS back.
> 
> If we don't do this, then libsas will instead fill in the tf status and
> tf error from the last command that returned a FIS (which might be out
> of date).
> 
> 
>> +
>>  	if (qc->scsicmd)
>>  		ASSIGN_SAS_TASK(qc->scsicmd, task);
>>  
>> diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
>> index 159823e0afbf..9e2c69c13dd3 100644
>> --- a/include/scsi/libsas.h
>> +++ b/include/scsi/libsas.h
>> @@ -550,6 +550,7 @@ struct sas_ata_task {
>>  	u8     use_ncq:1;
>>  	u8     set_affil_pol:1;
>>  	u8     stp_affil_pol:1;
>> +	u8     return_fis_on_success:1;
>>  
>>  	u8     device_control_reg_update:1;
>>  
>> -- 
>> 2.42.0.rc1.204.g551eb34607-goog
>>
> 
> Considering that libsas return value is defined like this:
> https://github.com/torvalds/linux/blob/v6.5-rc6/include/scsi/libsas.h#L507
> 
> Basically, if you returned a FIS in resp->ending_fis, you should return
> SAS_PROTO_RESPONSE. If you didn't return a FIS for your command, then
> you return SAS_SAM_STAT_GOOD (or if it is an error, a SAS_ error code
> that is not SAS_PROTO_RESPONSE, as you didn't return a FIS).
> 
> Since you have implemented this only for pm80xx, how about adding something
> like this to sas_ata_task_done:
> 
> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
> index 77714a495cbb..e1c56c2c00a5 100644
> --- a/drivers/scsi/libsas/sas_ata.c
> +++ b/drivers/scsi/libsas/sas_ata.c
> @@ -114,6 +114,15 @@ static void sas_ata_task_done(struct sas_task *task)
>                 }
>         }
>  
> +       /*
> +        * If a FIS was requested for a good command, and the lldd returned
> +        * SAS_SAM_STAT_GOOD instead of SAS_PROTO_RESPONSE, then the lldd
> +        * has not implemented support for sas_ata_task.return_fis_on_success
> +        * Warn about this once. If we don't return FIS on success, then we
> +        * won't be able to return an up to date TF.status and TF.error.
> +        */
> +       WARN_ON_ONCE(ata_qc_wants_result(qc) && stat->stat == SAS_SAM_STAT_GOOD);
> +
>         if (stat->stat == SAS_PROTO_RESPONSE ||
>             stat->stat == SAS_SAM_STAT_GOOD ||
>             (stat->stat == SAS_SAM_STAT_CHECK_CONDITION &&
> 
> 
> 
> 
> Kind regards,
> Niklas
Damien Le Moal Aug. 18, 2023, 12:09 a.m. UTC | #6
On 2023/08/18 8:36, Niklas Cassel wrote:
> On Thu, Aug 17, 2023 at 02:41:36PM -0700, Igor Pylypiv wrote:
> 
> Hello Igor,
> 
>> For Command Duration Limits policy 0xD (command completes without
>> an error) libata needs FIS in order to detect the ATA_SENSE bit and
>> read the Sense Data for Successful NCQ Commands log (0Fh).
>>
>> Set return_fis_on_success for commands that have a CDL descriptor
>> since any CDL descriptor can be configured with policy 0xD.
>>
>> Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
>> ---
>>  drivers/scsi/libsas/sas_ata.c | 3 +++
>>  include/scsi/libsas.h         | 1 +
>>  2 files changed, 4 insertions(+)
>>
>> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
>> index 77714a495cbb..da67c4f671b2 100644
>> --- a/drivers/scsi/libsas/sas_ata.c
>> +++ b/drivers/scsi/libsas/sas_ata.c
>> @@ -207,6 +207,9 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
>>  	task->ata_task.use_ncq = ata_is_ncq(qc->tf.protocol);
>>  	task->ata_task.dma_xfer = ata_is_dma(qc->tf.protocol);
>>  
>> +	/* CDL policy 0xD requires FIS for successful (no error) completions */
>> +	task->ata_task.return_fis_on_success = ata_qc_has_cdl(qc);
> 
> In ata_qc_complete(), for a successful command, we call fill_result_tf()
> if (qc->flags & ATA_QCFLAG_RESULT_TF):
> https://github.com/torvalds/linux/blob/v6.5-rc6/drivers/ata/libata-core.c#L4926
> 
> My point is, I think that you should set
> task->ata_task.return_fis_on_success = ata_qc_wants_result(qc);
> 
> where ata_qc_wants_result()
> returns true if ATA_QCFLAG_RESULT_TF is set.
> 
> (ata_set_tf_cdl() will set both ATA_QCFLAG_HAS_CDL and ATA_QCFLAG_RESULT_TF).
> 
> That way, e.g. an internal command (i.e. a command issued by
> ata_exec_internal_sg()), which always has ATA_QCFLAG_RESULT_TF set,
> will always gets an up to date tf status and tf error value back,
> because the SAS HBA will send a FIS back.

+1

> 
> If we don't do this, then libsas will instead fill in the tf status and
> tf error from the last command that returned a FIS (which might be out
> of date).
Niklas Cassel Aug. 18, 2023, 12:37 a.m. UTC | #7
On Fri, Aug 18, 2023 at 09:08:26AM +0900, Damien Le Moal wrote:
> On 2023/08/18 8:36, Niklas Cassel wrote:
> > On Thu, Aug 17, 2023 at 02:41:36PM -0700, Igor Pylypiv wrote:
> > 
> > Hello Igor,
> > 
> >> For Command Duration Limits policy 0xD (command completes without
> >> an error) libata needs FIS in order to detect the ATA_SENSE bit and
> >> read the Sense Data for Successful NCQ Commands log (0Fh).
> >>
> >> Set return_fis_on_success for commands that have a CDL descriptor
> >> since any CDL descriptor can be configured with policy 0xD.
> >>
> >> Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
> >> ---
> >>  drivers/scsi/libsas/sas_ata.c | 3 +++
> >>  include/scsi/libsas.h         | 1 +
> >>  2 files changed, 4 insertions(+)
> >>
> >> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
> >> index 77714a495cbb..da67c4f671b2 100644
> >> --- a/drivers/scsi/libsas/sas_ata.c
> >> +++ b/drivers/scsi/libsas/sas_ata.c
> >> @@ -207,6 +207,9 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
> >>  	task->ata_task.use_ncq = ata_is_ncq(qc->tf.protocol);
> >>  	task->ata_task.dma_xfer = ata_is_dma(qc->tf.protocol);
> >>  
> >> +	/* CDL policy 0xD requires FIS for successful (no error) completions */
> >> +	task->ata_task.return_fis_on_success = ata_qc_has_cdl(qc);
> > 
> > In ata_qc_complete(), for a successful command, we call fill_result_tf()
> > if (qc->flags & ATA_QCFLAG_RESULT_TF):
> > https://github.com/torvalds/linux/blob/v6.5-rc6/drivers/ata/libata-core.c#L4926
> > 
> > My point is, I think that you should set
> > task->ata_task.return_fis_on_success = ata_qc_wants_result(qc);
> > 
> > where ata_qc_wants_result()
> > returns true if ATA_QCFLAG_RESULT_TF is set.
> 
> I do not think we need that helper. Testing the flag directly would be fine.
> If you really insist on introducing the helper, then at least go through libata
> and replace all direct tests of that flag with the helper. But I do not think it
> is worth the churn.

I agree that there is no need for a helper.


Kind regards,
Niklas
Niklas Cassel Aug. 18, 2023, 1:08 a.m. UTC | #8
On Fri, Aug 18, 2023 at 01:36:39AM +0200, Niklas Cassel wrote:
> On Thu, Aug 17, 2023 at 02:41:36PM -0700, Igor Pylypiv wrote:

(snip)

> Considering that libsas return value is defined like this:
> https://github.com/torvalds/linux/blob/v6.5-rc6/include/scsi/libsas.h#L507
> 
> Basically, if you returned a FIS in resp->ending_fis, you should return
> SAS_PROTO_RESPONSE. If you didn't return a FIS for your command, then
> you return SAS_SAM_STAT_GOOD (or if it is an error, a SAS_ error code
> that is not SAS_PROTO_RESPONSE, as you didn't return a FIS).
> 
> Since you have implemented this only for pm80xx, how about adding something
> like this to sas_ata_task_done:
> 
> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
> index 77714a495cbb..e1c56c2c00a5 100644
> --- a/drivers/scsi/libsas/sas_ata.c
> +++ b/drivers/scsi/libsas/sas_ata.c
> @@ -114,6 +114,15 @@ static void sas_ata_task_done(struct sas_task *task)
>                 }
>         }
>  
> +       /*
> +        * If a FIS was requested for a good command, and the lldd returned
> +        * SAS_SAM_STAT_GOOD instead of SAS_PROTO_RESPONSE, then the lldd
> +        * has not implemented support for sas_ata_task.return_fis_on_success
> +        * Warn about this once. If we don't return FIS on success, then we
> +        * won't be able to return an up to date TF.status and TF.error.
> +        */
> +       WARN_ON_ONCE(ata_qc_wants_result(qc) && stat->stat == SAS_SAM_STAT_GOOD);
> +
>         if (stat->stat == SAS_PROTO_RESPONSE ||
>             stat->stat == SAS_SAM_STAT_GOOD ||
>             (stat->stat == SAS_SAM_STAT_CHECK_CONDITION &&
> 

Note that some drivers, e.g. aic94xx, already seem to:
always copy to ending_fis, and sets SAS_PROTO_RESPONSE,
both for successful and error commands. So it would already work.

Other drivers like isci, hisi, and mvsas seem to always copy
to ending_fis, but incorrectly sets status to SAS_PROTO_RESPONSE
only when there was an error.
They should probably also set status to SAS_PROTO_RESPONSE in the
success case, since they did copy the FIS also in the success case.


Kind regards,
Niklas
Igor Pylypiv Aug. 18, 2023, 10 p.m. UTC | #9
On Thu, Aug 17, 2023 at 11:36:43PM +0000, Niklas Cassel wrote:
> On Thu, Aug 17, 2023 at 02:41:36PM -0700, Igor Pylypiv wrote:
> 
> Hello Igor,
> 
> > For Command Duration Limits policy 0xD (command completes without
> > an error) libata needs FIS in order to detect the ATA_SENSE bit and
> > read the Sense Data for Successful NCQ Commands log (0Fh).
> > 
> > Set return_fis_on_success for commands that have a CDL descriptor
> > since any CDL descriptor can be configured with policy 0xD.
> > 
> > Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
> > ---
> >  drivers/scsi/libsas/sas_ata.c | 3 +++
> >  include/scsi/libsas.h         | 1 +
> >  2 files changed, 4 insertions(+)
> > 
> > diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
> > index 77714a495cbb..da67c4f671b2 100644
> > --- a/drivers/scsi/libsas/sas_ata.c
> > +++ b/drivers/scsi/libsas/sas_ata.c
> > @@ -207,6 +207,9 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
> >  	task->ata_task.use_ncq = ata_is_ncq(qc->tf.protocol);
> >  	task->ata_task.dma_xfer = ata_is_dma(qc->tf.protocol);
> >  
> > +	/* CDL policy 0xD requires FIS for successful (no error) completions */
> > +	task->ata_task.return_fis_on_success = ata_qc_has_cdl(qc);
> 
> In ata_qc_complete(), for a successful command, we call fill_result_tf()
> if (qc->flags & ATA_QCFLAG_RESULT_TF):
> https://github.com/torvalds/linux/blob/v6.5-rc6/drivers/ata/libata-core.c#L4926
> 
> My point is, I think that you should set
> task->ata_task.return_fis_on_success = ata_qc_wants_result(qc);
> 
> where ata_qc_wants_result()
> returns true if ATA_QCFLAG_RESULT_TF is set.
> 
> (ata_set_tf_cdl() will set both ATA_QCFLAG_HAS_CDL and ATA_QCFLAG_RESULT_TF).
> 
> That way, e.g. an internal command (i.e. a command issued by
> ata_exec_internal_sg()), which always has ATA_QCFLAG_RESULT_TF set,
> will always gets an up to date tf status and tf error value back,
> because the SAS HBA will send a FIS back.
> 
> If we don't do this, then libsas will instead fill in the tf status and
> tf error from the last command that returned a FIS (which might be out
> of date).

Hi Niklas,

Thanks for the suggestion! I'll update the check to ATA_QCFLAG_RESULT_TF in v2.

> 
> 
> > +
> >  	if (qc->scsicmd)
> >  		ASSIGN_SAS_TASK(qc->scsicmd, task);
> >  
> > diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
> > index 159823e0afbf..9e2c69c13dd3 100644
> > --- a/include/scsi/libsas.h
> > +++ b/include/scsi/libsas.h
> > @@ -550,6 +550,7 @@ struct sas_ata_task {
> >  	u8     use_ncq:1;
> >  	u8     set_affil_pol:1;
> >  	u8     stp_affil_pol:1;
> > +	u8     return_fis_on_success:1;
> >  
> >  	u8     device_control_reg_update:1;
> >  
> > -- 
> > 2.42.0.rc1.204.g551eb34607-goog
> > 
> 
> Considering that libsas return value is defined like this:
> https://github.com/torvalds/linux/blob/v6.5-rc6/include/scsi/libsas.h#L507
> 
> Basically, if you returned a FIS in resp->ending_fis, you should return
> SAS_PROTO_RESPONSE. If you didn't return a FIS for your command, then
> you return SAS_SAM_STAT_GOOD (or if it is an error, a SAS_ error code
> that is not SAS_PROTO_RESPONSE, as you didn't return a FIS).
> 
> Since you have implemented this only for pm80xx, how about adding something
> like this to sas_ata_task_done:
> 
> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
> index 77714a495cbb..e1c56c2c00a5 100644
> --- a/drivers/scsi/libsas/sas_ata.c
> +++ b/drivers/scsi/libsas/sas_ata.c
> @@ -114,6 +114,15 @@ static void sas_ata_task_done(struct sas_task *task)
>                 }
>         }
>  
> +       /*
> +        * If a FIS was requested for a good command, and the lldd returned
> +        * SAS_SAM_STAT_GOOD instead of SAS_PROTO_RESPONSE, then the lldd
> +        * has not implemented support for sas_ata_task.return_fis_on_success
> +        * Warn about this once. If we don't return FIS on success, then we
> +        * won't be able to return an up to date TF.status and TF.error.
> +        */
> +       WARN_ON_ONCE(ata_qc_wants_result(qc) && stat->stat == SAS_SAM_STAT_GOOD);

I'm a bit hesitant about adding this warning. pm80xx manual states that FIS
is not getting returned for PIO Read commands. ata_dev_read_id() sends
ATA_CMD_ID_ATA (0xEC) PIO command during bus probe resulting in this warning
getting triggered every time. Checking for !PIO doesn't seem to be the right
thing to do. I'll hold off from adding the warning.

> +
>         if (stat->stat == SAS_PROTO_RESPONSE ||
>             stat->stat == SAS_SAM_STAT_GOOD ||
>             (stat->stat == SAS_SAM_STAT_CHECK_CONDITION &&
> 

Thanks,
Igor
diff mbox series

Patch

diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 77714a495cbb..da67c4f671b2 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -207,6 +207,9 @@  static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
 	task->ata_task.use_ncq = ata_is_ncq(qc->tf.protocol);
 	task->ata_task.dma_xfer = ata_is_dma(qc->tf.protocol);
 
+	/* CDL policy 0xD requires FIS for successful (no error) completions */
+	task->ata_task.return_fis_on_success = ata_qc_has_cdl(qc);
+
 	if (qc->scsicmd)
 		ASSIGN_SAS_TASK(qc->scsicmd, task);
 
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 159823e0afbf..9e2c69c13dd3 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -550,6 +550,7 @@  struct sas_ata_task {
 	u8     use_ncq:1;
 	u8     set_affil_pol:1;
 	u8     stp_affil_pol:1;
+	u8     return_fis_on_success:1;
 
 	u8     device_control_reg_update:1;