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
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
);\r
\r
AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
-\r
return Status;\r
}\r
\r
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
}\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
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
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
\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