[edk2-devel] [PATCHv3 3/4] MdeModulePkg/AtaAtapiPassThru: Restart failed packets

Wu, Hao A hao.a.wu at intel.com
Fri Nov 6 03:14:23 UTC 2020


> -----Original Message-----
> From: Albecki, Mateusz <mateusz.albecki at intel.com>
> Sent: Thursday, November 5, 2020 8:49 PM
> To: devel at edk2.groups.io
> Cc: Albecki, Mateusz <mateusz.albecki at intel.com>; Ni, Ray
> <ray.ni at intel.com>; Wu, Hao A <hao.a.wu at intel.com>
> Subject: [PATCHv3 3/4] MdeModulePkg/AtaAtapiPassThru: Restart failed
> packets
> 
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3026
> 
> This commit adds code to restart the ATA packets that failed due to the CRC
> error or other link condition. For sync transfers the code will try to get the
> command working for up to 5 times. For async traansfers, the command wil
> be retried until the timeout value timeout specified by the requester is


Reviewed-by: Hao A Wu <hao.a.wu at intel.com>

Best Regards,
Hao Wu


> reached. For sync case the count of 5 retries has been chosen arbitrarily and
> if needed can be increased or decreased.
> 
> Signed-off-by: Mateusz Albecki <mateusz.albecki at intel.com>
> 
> Cc: Ray Ni <ray.ni at intel.com>
> Cc: Hao A Wu <hao.a.wu at intel.com>
> ---
>  .../Bus/Ata/AtaAtapiPassThru/AhciMode.c       | 305 +++++++++++-------
>  .../Bus/Ata/AtaAtapiPassThru/AhciMode.h       |   2 +
>  2 files changed, 182 insertions(+), 125 deletions(-)
> 
> diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
> b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
> index 0b7141c4f1..47275a851a 100644
> --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
> +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
> @@ -897,6 +897,7 @@ AhciPioTransfer (
>    EFI_AHCI_COMMAND_FIS          CFis;
>    EFI_AHCI_COMMAND_LIST         CmdList;
>    UINT32                        PrdCount;
> +  UINT32                        Retry;
> 
>    if (Read) {
>      Flag = EfiPciIoOperationBusMasterWrite; @@ -931,49 +932,56 @@
> AhciPioTransfer (
>    CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
>    CmdList.AhciCmdW   = Read ? 0 : 1;
> 
> -  AhciBuildCommand (
> -    PciIo,
> -    AhciRegisters,
> -    Port,
> -    PortMultiplier,
> -    &CFis,
> -    &CmdList,
> -    AtapiCommand,
> -    AtapiCommandLength,
> -    0,
> -    (VOID *)(UINTN)PhyAddr,
> -    DataCount
> -    );
> +  for (Retry = 0; Retry < AHCI_COMMAND_RETRIES; Retry++) {
> +    AhciBuildCommand (
> +      PciIo,
> +      AhciRegisters,
> +      Port,
> +      PortMultiplier,
> +      &CFis,
> +      &CmdList,
> +      AtapiCommand,
> +      AtapiCommandLength,
> +      0,
> +      (VOID *)(UINTN)PhyAddr,
> +      DataCount
> +      );
> 
> -  Status = AhciStartCommand (
> -             PciIo,
> -             Port,
> -             0,
> -             Timeout
> -             );
> -  if (EFI_ERROR (Status)) {
> -    goto Exit;
> -  }
> +    Status = AhciStartCommand (
> +              PciIo,
> +              Port,
> +              0,
> +              Timeout
> +              );
> +    if (EFI_ERROR (Status)) {
> +      break;
> +    }
> 
> -  if (Read && (AtapiCommand == 0)) {
> -    Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisPioSetup);
> -    if (Status == EFI_SUCCESS) {
> -      PrdCount = *(volatile UINT32 *) (&(AhciRegisters-
> >AhciCmdList[0].AhciCmdPrdbc));
> -      if (PrdCount == DataCount) {
> -        Status = EFI_SUCCESS;
> -      } else {
> -        Status = EFI_DEVICE_ERROR;
> +    if (Read && (AtapiCommand == 0)) {
> +      Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisPioSetup);
> +      if (Status == EFI_SUCCESS) {
> +        PrdCount = *(volatile UINT32 *) (&(AhciRegisters-
> >AhciCmdList[0].AhciCmdPrdbc));
> +        if (PrdCount == DataCount) {
> +          Status = EFI_SUCCESS;
> +        } else {
> +          Status = EFI_DEVICE_ERROR;
> +        }
>        }
> +    } else {
> +      Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout,
> + SataFisD2H);
>      }
> -  } else {
> -    Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H);
> -  }
> 
> -  if (Status == EFI_DEVICE_ERROR) {
> -    AhciRecoverPortError (PciIo, Port);
> +    if (Status == EFI_DEVICE_ERROR) {
> +      DEBUG ((DEBUG_ERROR, "PIO command failed at retry %d\n", Retry));
> +      Status = AhciRecoverPortError (PciIo, Port);
> +      if (EFI_ERROR (Status)) {
> +        break;
> +      }
> +    } else {
> +      break;
> +    }
>    }
> 
> -Exit:
>    AhciStopCommand (
>      PciIo,
>      Port,
> @@ -992,7 +1000,6 @@ Exit:
>      );
> 
>    AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);
> -
>    return Status;
>  }
> 
> @@ -1046,9 +1053,9 @@ AhciDmaTransfer (
>    EFI_PCI_IO_PROTOCOL_OPERATION Flag;
>    EFI_AHCI_COMMAND_FIS          CFis;
>    EFI_AHCI_COMMAND_LIST         CmdList;
> -
>    EFI_PCI_IO_PROTOCOL           *PciIo;
>    EFI_TPL                       OldTpl;
> +  UINT32                        Retry;
> 
>    Map   = NULL;
>    PciIo = Instance->PciIo;
> @@ -1058,36 +1065,16 @@ AhciDmaTransfer (
>    }
> 
>    //
> -  // Before starting the Blocking BlockIO operation, push to finish all non-
> blocking
> -  // BlockIO tasks.
> -  // Delay 100us to simulate the blocking time out checking.
> +  // DMA buffer allocation. Needs to be done only once for both sync
> + and async  // DMA transfers irrespective of number of retries.
>    //
> -  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> -  while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList)))
> {
> -    AsyncNonBlockingTransferRoutine (NULL, Instance);
> -    //
> -    // Stall for 100us.
> -    //
> -    MicroSecondDelay (100);
> -  }
> -  gBS->RestoreTPL (OldTpl);
> -
> -  if ((Task == NULL) || ((Task != NULL) && (!Task->IsStart))) {
> -    //
> -    // Mark the Task to indicate that it has been started.
> -    //
> -    if (Task != NULL) {
> -      Task->IsStart      = TRUE;
> -    }
> +  if ((Task == NULL) || ((Task != NULL) && (Task->Map == NULL))) {
>      if (Read) {
>        Flag = EfiPciIoOperationBusMasterWrite;
>      } else {
>        Flag = EfiPciIoOperationBusMasterRead;
>      }
> 
> -    //
> -    // Construct command list and command table with pci bus address.
> -    //
>      MapLength = DataCount;
>      Status = PciIo->Map (
>                        PciIo,
> @@ -1101,63 +1088,123 @@ AhciDmaTransfer (
>      if (EFI_ERROR (Status) || (DataCount != MapLength)) {
>        return EFI_BAD_BUFFER_SIZE;
>      }
> -
>      if (Task != NULL) {
>        Task->Map = Map;
>      }
> -    //
> -    // Package read needed
> -    //
> +  }
> +
> +  if (Task == NULL || (Task != NULL && !Task->IsStart)) {
>      AhciBuildCommandFis (&CFis, AtaCommandBlock);
> 
>      ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
> 
>      CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
>      CmdList.AhciCmdW   = Read ? 0 : 1;
> +  }
> 
> -    AhciBuildCommand (
> -      PciIo,
> -      AhciRegisters,
> -      Port,
> -      PortMultiplier,
> -      &CFis,
> -      &CmdList,
> -      AtapiCommand,
> -      AtapiCommandLength,
> -      0,
> -      (VOID *)(UINTN)PhyAddr,
> -      DataCount
> -      );
> -
> -    Status = AhciStartCommand (
> -               PciIo,
> -               Port,
> -               0,
> -               Timeout
> -               );
> -    if (EFI_ERROR (Status)) {
> -      goto Exit;
> +  if (Task == NULL) {
> +    //
> +    // Before starting the Blocking BlockIO operation, push to finish all non-
> blocking
> +    // BlockIO tasks.
> +    // Delay 100us to simulate the blocking time out checking.
> +    //
> +    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
> +    while (!IsListEmpty (&Instance->NonBlockingTaskList)) {
> +      AsyncNonBlockingTransferRoutine (NULL, Instance);
> +      //
> +      // Stall for 100us.
> +      //
> +      MicroSecondDelay (100);
>      }
> -  }
> +    gBS->RestoreTPL (OldTpl);
> +    for (Retry = 0; Retry < AHCI_COMMAND_RETRIES; Retry++) {
> +      AhciBuildCommand (
> +        PciIo,
> +        AhciRegisters,
> +        Port,
> +        PortMultiplier,
> +        &CFis,
> +        &CmdList,
> +        AtapiCommand,
> +        AtapiCommandLength,
> +        0,
> +        (VOID *)(UINTN)PhyAddr,
> +        DataCount
> +        );
> 
> -  if (Task != NULL) {
> -    Status = AhciCheckFisReceived (PciIo, Port, SataFisD2H);
> -    if (Status == EFI_NOT_READY) {
> -      if (!Task->InfiniteWait && Task->RetryTimes == 0) {
> -        Status = EFI_TIMEOUT;
> +      Status = AhciStartCommand (
> +                PciIo,
> +                Port,
> +                0,
> +                Timeout
> +                );
> +      if (EFI_ERROR (Status)) {
> +        break;
> +      }
> +      Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H);
> +      if (Status == EFI_DEVICE_ERROR) {
> +        DEBUG ((DEBUG_ERROR, "DMA command failed at retry: %d\n",
> Retry));
> +        Status = AhciRecoverPortError (PciIo, Port);
> +        if (EFI_ERROR (Status)) {
> +          break;
> +        }
>        } else {
> -        Task->RetryTimes--;
> +        break;
>        }
>      }
>    } else {
> -    Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H);
> -  }
> +    if (!Task->IsStart) {
> +      AhciBuildCommand (
> +        PciIo,
> +        AhciRegisters,
> +        Port,
> +        PortMultiplier,
> +        &CFis,
> +        &CmdList,
> +        AtapiCommand,
> +        AtapiCommandLength,
> +        0,
> +        (VOID *)(UINTN)PhyAddr,
> +        DataCount
> +        );
> +
> +      Status = AhciStartCommand (
> +                PciIo,
> +                Port,
> +                0,
> +                Timeout
> +                );
> +      if (!EFI_ERROR (Status)) {
> +        Task->IsStart = TRUE;
> +      }
> +    }
> +    if (Task->IsStart) {
> +      Status = AhciCheckFisReceived (PciIo, Port, SataFisD2H);
> +      if (Status == EFI_DEVICE_ERROR) {
> +        DEBUG ((DEBUG_ERROR, "DMA command failed at retry: %d\n", Task-
> >RetryTimes));
> +        Status = AhciRecoverPortError (PciIo, Port);
> +        //
> +        // If recovery passed mark the Task as not started and change the
> status
> +        // to EFI_NOT_READY. This will make the higher level call this function
> again
> +        // and on next call the command will be re-issued due to IsStart being
> FALSE.
> +        // This also makes the next condition decrement the RetryTimes.
> +        //
> +        if (Status == EFI_SUCCESS) {
> +          Task->IsStart = FALSE;
> +          Status = EFI_NOT_READY;
> +        }
> +      }
> 
> -  if (Status == EFI_DEVICE_ERROR) {
> -    AhciRecoverPortError (PciIo, Port);
> +      if (Status == EFI_NOT_READY) {
> +        if (!Task->InfiniteWait && Task->RetryTimes == 0) {
> +          Status = EFI_TIMEOUT;
> +        } else {
> +          Task->RetryTimes--;
> +        }
> +      }
> +    }
>    }
> 
> -Exit:
>    //
>    // For Blocking mode, the command should be stopped, the Fis should be
> disabled
>    // and the PciIo should be unmapped.
> @@ -1234,6 +1281,7 @@ AhciNonDataTransfer (
>    EFI_STATUS                   Status;
>    EFI_AHCI_COMMAND_FIS         CFis;
>    EFI_AHCI_COMMAND_LIST        CmdList;
> +  UINT32                       Retry;
> 
>    //
>    // Package read needed
> @@ -1244,36 +1292,43 @@ AhciNonDataTransfer (
> 
>    CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
> 
> -  AhciBuildCommand (
> -    PciIo,
> -    AhciRegisters,
> -    Port,
> -    PortMultiplier,
> -    &CFis,
> -    &CmdList,
> -    AtapiCommand,
> -    AtapiCommandLength,
> -    0,
> -    NULL,
> -    0
> -    );
> +  for (Retry = 0; Retry < AHCI_COMMAND_RETRIES; Retry++) {
> +    AhciBuildCommand (
> +      PciIo,
> +      AhciRegisters,
> +      Port,
> +      PortMultiplier,
> +      &CFis,
> +      &CmdList,
> +      AtapiCommand,
> +      AtapiCommandLength,
> +      0,
> +      NULL,
> +      0
> +      );
> 
> -  Status = AhciStartCommand (
> -             PciIo,
> -             Port,
> -             0,
> -             Timeout
> -             );
> -  if (EFI_ERROR (Status)) {
> -    goto Exit;
> -  }
> +    Status = AhciStartCommand (
> +                PciIo,
> +                Port,
> +                0,
> +                Timeout
> +                );
> +    if (EFI_ERROR (Status)) {
> +      break;
> +    }
> 
> -  Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H);
> -  if (Status == EFI_DEVICE_ERROR) {
> -    AhciRecoverPortError (PciIo, Port);
> +    Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H);
> +    if (Status == EFI_DEVICE_ERROR) {
> +      DEBUG ((DEBUG_ERROR, "Non data transfer failed at retry %d\n",
> Retry));
> +      Status = AhciRecoverPortError (PciIo, Port);
> +      if (EFI_ERROR (Status)) {
> +        break;
> +      }
> +    } else {
> +      break;
> +    }
>    }
> 
> -Exit:
>    AhciStopCommand (
>      PciIo,
>      Port,
> diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
> b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
> index 338447a55f..ced2648970 100644
> --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
> +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
> @@ -192,6 +192,8 @@ typedef union {
>  #define   AHCI_PORT_DEVSLP_DITO_MASK           0x01FF8000
>  #define   AHCI_PORT_DEVSLP_DM_MASK             0x1E000000
> 
> +#define AHCI_COMMAND_RETRIES  5
> +
>  #pragma pack(1)
>  //
>  // Command List structure includes total 32 entries.
> --
> 2.28.0.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#67061): https://edk2.groups.io/g/devel/message/67061
Mute This Topic: https://groups.io/mt/78049846/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-






More information about the edk2-devel-archive mailing list