]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg/AtaAtapiPassThru: Restart failed packets
authorAlbecki, Mateusz <mateusz.albecki@intel.com>
Thu, 5 Nov 2020 12:48:46 +0000 (20:48 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Wed, 11 Nov 2020 02:27:59 +0000 (02:27 +0000)
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 transfers, the
command will be retried until the timeout value timeout specified by the
requester is 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@intel.com>
Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h

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