public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Laszlo Ersek" <lersek@redhat.com>
To: Gary Lin <glin@suse.com>, devel@edk2.groups.io
Cc: Jordan Justen <jordan.l.justen@intel.com>,
	Ard Biesheuvel <ard.biesheuvel@arm.com>
Subject: Re: [PATCH v2 11/12] OvmfPkg/LsiScsiDxe: Calculate the transferred bytes
Date: Thu, 16 Jul 2020 20:21:46 +0200	[thread overview]
Message-ID: <c41f6879-c2e5-5721-b652-69bb8fa1f18f@redhat.com> (raw)
In-Reply-To: <20200716074607.18048-12-glin@suse.com>

On 07/16/20 09:46, Gary Lin wrote:
> Calculate the transferred bytes during data phases based on the
> Cumulative SCSI Byte Count (CSBC) and update
> InTransferLength/OutTransferLength of the request packet.
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
>  OvmfPkg/Include/IndustryStandard/LsiScsi.h |  1 +
>  OvmfPkg/LsiScsiDxe/LsiScsi.c               | 50 ++++++++++++++++++++++
>  2 files changed, 51 insertions(+)
> 
> diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> index 9964bd40385c..01d75323cdbc 100644
> --- a/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> +++ b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> @@ -25,6 +25,7 @@
>  #define LSI_REG_DSP               0x2C
>  #define LSI_REG_SIST0             0x42
>  #define LSI_REG_SIST1             0x43
> +#define LSI_REG_CSBC              0xDC
>  
>  //
>  // The status bits for DMA Status (DSTAT)
> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> index d5fe1d4ab3b8..10483ed02bd7 100644
> --- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
> +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> @@ -79,6 +79,24 @@ In8 (
>                            );
>  }
>  
> +STATIC
> +EFI_STATUS
> +In32 (
> +  IN  LSI_SCSI_DEV *Dev,
> +  IN  UINT32       Addr,
> +  OUT UINT32       *Data
> +  )
> +{
> +  return Dev->PciIo->Io.Read (
> +                          Dev->PciIo,
> +                          EfiPciIoWidthUint32,
> +                          PCI_BAR_IDX0,
> +                          Addr,
> +                          1,
> +                          Data
> +                          );
> +}
> +
>  STATIC
>  EFI_STATUS
>  LsiScsiReset (
> @@ -219,6 +237,8 @@ LsiScsiProcessRequest (
>    UINT8      DStat;
>    UINT8      SIst0;
>    UINT8      SIst1;
> +  UINT32     Csbc;
> +  UINT32     CsbcBase;
>  
>    Script      = Dev->Dma->Script;
>    Cdb         = Dev->Dma->Cdb;
> @@ -232,6 +252,18 @@ LsiScsiProcessRequest (
>    SetMem (Cdb, sizeof Dev->Dma->Cdb, 0x00);
>    CopyMem (Cdb, Packet->Cdb, Packet->CdbLength);
>  
> +  //
> +  // Fetch the first Cumulative SCSI Byte Count (CSBC).
> +  //
> +  // CSBC is a cumulative counter of the actual number of bytes that has been

(1) typo: s/has been/have been/

> +  // transferred across the SCSI bus during data phases, i.e. it will not

(2) typo (I think): s/will not/will not count/

> +  // bytes sent in command, status, message in and out phases.
> +  //
> +  Status = In32 (Dev, LSI_REG_CSBC, &CsbcBase);
> +  if (EFI_ERROR (Status)) {
> +    return Status;

(3) IMO, we should not return directly, but jump to the Error label.

> +  }
> +
>    //
>    // Clean up the DMA buffer for the script.
>    //
> @@ -407,6 +439,24 @@ LsiScsiProcessRequest (
>      gBS->Stall (Dev->StallPerPollUsec);
>    }
>  
> +  //
> +  // Fetch CSBC again to calculate the transferred bytes and update
> +  // InTransferLength/OutTransferLength.
> +  //

This calculation matters for EFI_SUCCESS. But at this point we cannot
yet guarantee that we'll return EFI_SUCCESS.

(4) So I suggest postponing the CSBC re-fetch until after we're past the
last "goto Error" statement -- that is, just before "Copy Data to
InDataBuffer if necessary".

> +  // Note: The number of transferred bytes is bounded by
> +  //       "sizeof Dev->Dma->Data", so it's safe to subtract CsbcBase
> +  //       from Csbc.
> +  //

It's safe to perform the subtraction, but I think we should extend the
comment.

This register seems to be a 4-byte counter. It's not super difficult to
transfer more than 4GB even in UEFI, and so the counter might wrap around.

Luckily, when it wraps around, the subtraction will do exactly the right
thing. (And for that, it is indeed relevant that the max requestable
transfer size is smaller than (MAX_UINT32+1).)

Assume

  Csbc < CsbcBase

This means (a) the counter has wrapped, and (b) mathematically, the
difference

  Csbc - Csbcbase

is negative.

Given that we use UINT32 variables here, the resultant value (in C) will
be (per C standard):

  (MAX_UINT32 + 1) + (Csbc - Csbcbase)                               [1]

And that's perfect! Because, what does it mean that "CSBC wraps"? It
means that the mathematical meaning of the new CSBC value is:

  ((MAX_UINT32 + 1) + Csbc)

(It's just a different way to say that bit#32 is set in the mathematical
value.)

Consequently, for getting the right difference, we'd have to calculate:

  ((MAX_UINT32 + 1) + Csbc) - Csbcbase                               [2]

But that's exactly what the C language *already* gives us, in [1].


(5) So please append the following sentence to the comment:

  If the CSBC register wraps around, the correct difference is ensured
  by the standard C modular arithmetic.

(6) Furthermore, please dedicate a new variable to the difference:

  UINT32 Transferred;

  Transferred = Csbc - CsbcBase;

> +  Status = In32 (Dev, LSI_REG_CSBC, &Csbc);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }

(7) Again I think we should jump to the Error label.

> +  if (Packet->InTransferLength > 0) {
> +    Packet->InTransferLength = Csbc - CsbcBase;
> +  } else if (Packet->OutTransferLength > 0) {
> +    Packet->OutTransferLength = Csbc - CsbcBase;
> +  }
> +

(8) I'd recommend a sanity check -- it's unlikely that the device will
blatantly lie, but if it ever happens, we should not let it out.

We may only ever reduce the transfer length. Thus:

  if (Packet->InTransferLength > 0) {
    if (Transferred <= Packet->InTransferLength) {
      Packet->InTransferLength = Transferred;
    } else {
      goto Error;
    }
  } else if (Packet->OutTransferLength > 0) {
    if (Transferred <= Packet->OutTransferLength) {
      Packet->OutTransferLength = Transferred;
    } else {
      goto Error;
    }
  }

Thanks,
Laszlo

>    //
>    // Check if everything is good.
>    //   SCSI Message Code 0x00: COMMAND COMPLETE
> 


  reply	other threads:[~2020-07-16 18:21 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
2020-07-16  7:45 ` [PATCH v2 01/12] OvmfPkg/LsiScsiDxe: Create the empty driver Gary Lin
2020-07-16  7:45 ` [PATCH v2 02/12] OvmfPkg/LsiScsiDxe: Install the skeleton of driver binding Gary Lin
2020-07-16  7:45 ` [PATCH v2 03/12] OvmfPkg/LsiScsiDxe: Report the name of the driver Gary Lin
2020-07-16  7:45 ` [PATCH v2 04/12] OvmfPkg/LsiScsiDxe: Probe PCI devices and look for LsiScsi Gary Lin
2020-07-16  7:46 ` [PATCH v2 05/12] OvmfPkg/LsiScsiDxe: Install stubbed EXT_SCSI_PASS_THRU Gary Lin
2020-07-16  7:46 ` [PATCH v2 06/12] OvmfPkg/LsiScsiDxe: Report Targets and LUNs Gary Lin
2020-07-16 15:04   ` Laszlo Ersek
2020-07-16 16:19     ` Laszlo Ersek
2020-07-16  7:46 ` [PATCH v2 07/12] OvmfPkg/LsiScsiDxe: Open PciIo protocol and initialize the device Gary Lin
2020-07-16 16:07   ` Laszlo Ersek
2020-07-16  7:46 ` [PATCH v2 08/12] OvmfPkg/LsiScsiDxe: Map DMA buffer Gary Lin
2020-07-16 16:11   ` Laszlo Ersek
2020-07-16  7:46 ` [PATCH v2 09/12] OvmfPkg/LsiScsiDxe: Examine the incoming SCSI Request Packet Gary Lin
2020-07-16  7:46 ` [PATCH v2 10/12] OvmfPkg/LsiScsiDxe: Process the " Gary Lin
2020-07-16 17:37   ` Laszlo Ersek
2020-07-17  2:28     ` Gary Lin
2020-07-16  7:46 ` [PATCH v2 11/12] OvmfPkg/LsiScsiDxe: Calculate the transferred bytes Gary Lin
2020-07-16 18:21   ` Laszlo Ersek [this message]
2020-07-17  3:15     ` Gary Lin
2020-07-16  7:46 ` [PATCH v2 12/12] Maintainers.txt: Add Gary Lin as the reviewer for LsiScsi driver Gary Lin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c41f6879-c2e5-5721-b652-69bb8fa1f18f@redhat.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox