/** @file\r
Header file for AHCI mode of ATA host controller.\r
\r
- Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
IN UINT64 Timeout\r
)\r
{\r
- UINT32 Delay;\r
+ UINT64 Delay;\r
UINT8 StatusRegister;\r
+ BOOLEAN InfiniteWait;\r
\r
ASSERT (PciIo != NULL);\r
ASSERT (IdeRegisters != NULL);\r
\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ Delay = DivU64x32(Timeout, 1000) + 1;\r
do {\r
StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
\r
\r
Delay--;\r
\r
- } while (Delay > 0);\r
+ } while (InfiniteWait || (Delay > 0));\r
\r
return EFI_TIMEOUT;\r
}\r
IN UINT64 Timeout\r
)\r
{\r
- UINT32 Delay;\r
+ UINT64 Delay;\r
UINT8 AltRegister;\r
+ BOOLEAN InfiniteWait;\r
\r
ASSERT (PciIo != NULL);\r
ASSERT (IdeRegisters != NULL);\r
\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ Delay = DivU64x32(Timeout, 1000) + 1;\r
do {\r
AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
\r
\r
Delay--;\r
\r
- } while (Delay > 0);\r
+ } while (InfiniteWait || (Delay > 0));\r
\r
return EFI_TIMEOUT;\r
}\r
@param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
@param Timeout The time to complete the command, uses 100ns as a unit.\r
\r
- @retval EFI_SUCCESS DRQ bit set within the time out.\r
- @retval EFI_TIMEOUT DRQ bit not set within the time out.\r
- @retval EFI_ABORTED DRQ bit not set caused by the command abort.\r
+ @retval EFI_SUCCESS BSY bit cleared and DRQ bit set within the\r
+ timeout.\r
+\r
+ @retval EFI_TIMEOUT BSY bit not cleared within the timeout.\r
+\r
+ @retval EFI_ABORTED Polling abandoned due to command abort.\r
+\r
+ @retval EFI_DEVICE_ERROR Polling abandoned due to a non-abort error.\r
+\r
+ @retval EFI_NOT_READY BSY bit cleared within timeout, and device\r
+ reported "command complete" by clearing DRQ\r
+ bit.\r
\r
@note Read Status Register will clear interrupt status.\r
\r
IN UINT64 Timeout\r
)\r
{\r
- UINT32 Delay;\r
+ UINT64 Delay;\r
UINT8 StatusRegister;\r
UINT8 ErrorRegister;\r
+ BOOLEAN InfiniteWait;\r
\r
ASSERT (PciIo != NULL);\r
ASSERT (IdeRegisters != NULL);\r
\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ Delay = DivU64x32(Timeout, 1000) + 1;\r
do {\r
//\r
// Read Status Register will clear interrupt\r
MicroSecondDelay (100);\r
\r
Delay--;\r
- } while (Delay > 0);\r
+ } while (InfiniteWait || (Delay > 0));\r
\r
return EFI_TIMEOUT;\r
}\r
@param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
@param Timeout The time to complete the command, uses 100ns as a unit.\r
\r
- @retval EFI_SUCCESS DRQ bit set within the time out.\r
- @retval EFI_TIMEOUT DRQ bit not set within the time out.\r
- @retval EFI_ABORTED DRQ bit not set caused by the command abort.\r
+ @retval EFI_SUCCESS BSY bit cleared and DRQ bit set within the\r
+ timeout.\r
+\r
+ @retval EFI_TIMEOUT BSY bit not cleared within the timeout.\r
+\r
+ @retval EFI_ABORTED Polling abandoned due to command abort.\r
+\r
+ @retval EFI_DEVICE_ERROR Polling abandoned due to a non-abort error.\r
+\r
+ @retval EFI_NOT_READY BSY bit cleared within timeout, and device\r
+ reported "command complete" by clearing DRQ\r
+ bit.\r
+\r
@note Read Alternate Status Register will not clear interrupt status.\r
\r
**/\r
IN UINT64 Timeout\r
)\r
{\r
- UINT32 Delay;\r
+ UINT64 Delay;\r
UINT8 AltRegister;\r
UINT8 ErrorRegister;\r
+ BOOLEAN InfiniteWait;\r
\r
ASSERT (PciIo != NULL);\r
ASSERT (IdeRegisters != NULL);\r
\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ Delay = DivU64x32(Timeout, 1000) + 1;\r
\r
do {\r
//\r
MicroSecondDelay (100);\r
\r
Delay--;\r
- } while (Delay > 0);\r
-\r
- return EFI_TIMEOUT;\r
-}\r
-\r
-/**\r
- This function is used to poll for the DRDY bit set in the Status Register. DRDY\r
- bit is set when the device is ready to accept command. Most ATA commands must be\r
- sent after DRDY set except the ATAPI Packet Command.\r
-\r
- @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
- @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
- @param Timeout The time to complete the command, uses 100ns as a unit.\r
-\r
- @retval EFI_SUCCESS DRDY bit set within the time out.\r
- @retval EFI_TIMEOUT DRDY bit not set within the time out.\r
-\r
- @note Read Status Register will clear interrupt status.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-DRDYReady (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN EFI_IDE_REGISTERS *IdeRegisters,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- UINT32 Delay;\r
- UINT8 StatusRegister;\r
- UINT8 ErrorRegister;\r
-\r
- ASSERT (PciIo != NULL);\r
- ASSERT (IdeRegisters != NULL);\r
-\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
- do {\r
- StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
- //\r
- // Wait for BSY == 0, then judge if DRDY is set or ERR is set\r
- //\r
- if ((StatusRegister & ATA_STSREG_BSY) == 0) {\r
- if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
- ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
-\r
- if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
- return EFI_ABORTED;\r
- }\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- if ((StatusRegister & ATA_STSREG_DRDY) == ATA_STSREG_DRDY) {\r
- return EFI_SUCCESS;\r
- } else {\r
- return EFI_DEVICE_ERROR;\r
- }\r
- }\r
-\r
- //\r
- // Stall for 100 microseconds.\r
- //\r
- MicroSecondDelay (100);\r
-\r
- Delay--;\r
- } while (Delay > 0);\r
+ } while (InfiniteWait || (Delay > 0));\r
\r
return EFI_TIMEOUT;\r
}\r
\r
-/**\r
- This function is used to poll for the DRDY bit set in the Alternate Status Register.\r
- DRDY bit is set when the device is ready to accept command. Most ATA commands must\r
- be sent after DRDY set except the ATAPI Packet Command.\r
-\r
- @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
- @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
- @param Timeout The time to complete the command, uses 100ns as a unit.\r
\r
- @retval EFI_SUCCESS DRDY bit set within the time out.\r
- @retval EFI_TIMEOUT DRDY bit not set within the time out.\r
\r
- @note Read Alternate Status Register will clear interrupt status.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-DRDYReady2 (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN EFI_IDE_REGISTERS *IdeRegisters,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- UINT32 Delay;\r
- UINT8 AltRegister;\r
- UINT8 ErrorRegister;\r
-\r
- ASSERT (PciIo != NULL);\r
- ASSERT (IdeRegisters != NULL);\r
-\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
- do {\r
- AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
- //\r
- // Wait for BSY == 0, then judge if DRDY is set or ERR is set\r
- //\r
- if ((AltRegister & ATA_STSREG_BSY) == 0) {\r
- if ((AltRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
- ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
-\r
- if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
- return EFI_ABORTED;\r
- }\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- if ((AltRegister & ATA_STSREG_DRDY) == ATA_STSREG_DRDY) {\r
- return EFI_SUCCESS;\r
- } else {\r
- return EFI_DEVICE_ERROR;\r
- }\r
- }\r
-\r
- //\r
- // Stall for 100 microseconds.\r
- //\r
- MicroSecondDelay (100);\r
-\r
- Delay--;\r
- } while (Delay > 0);\r
-\r
- return EFI_TIMEOUT;\r
-}\r
\r
/**\r
This function is used to poll for the BSY bit clear in the Status Register. BSY\r
IN UINT64 Timeout\r
)\r
{\r
- UINT32 Delay;\r
+ UINT64 Delay;\r
UINT8 StatusRegister;\r
+ BOOLEAN InfiniteWait;\r
\r
ASSERT (PciIo != NULL);\r
ASSERT (IdeRegisters != NULL);\r
\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ Delay = DivU64x32(Timeout, 1000) + 1;\r
do {\r
StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
\r
\r
Delay--;\r
\r
- } while (Delay > 0);\r
+ } while (InfiniteWait || (Delay > 0));\r
\r
return EFI_TIMEOUT;\r
}\r
\r
-/**\r
- This function is used to poll for the BSY bit clear in the Status Register. BSY\r
- is clear when the device is not busy. Every command must be sent after device is not busy.\r
-\r
- @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
- @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
- @param Timeout The time to complete the command, uses 100ns as a unit.\r
-\r
- @retval EFI_SUCCESS BSY bit clear within the time out.\r
- @retval EFI_TIMEOUT BSY bit not clear within the time out.\r
-\r
- @note Read Status Register will clear interrupt status.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-WaitForBSYClear2 (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN EFI_IDE_REGISTERS *IdeRegisters,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- UINT32 Delay;\r
- UINT8 AltStatusRegister;\r
-\r
- ASSERT (PciIo != NULL);\r
- ASSERT (IdeRegisters != NULL);\r
-\r
- Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
- do {\r
- AltStatusRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
-\r
- if ((AltStatusRegister & ATA_STSREG_BSY) == 0x00) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // Stall for 100 microseconds.\r
- //\r
- MicroSecondDelay (100);\r
-\r
- Delay--;\r
-\r
- } while (Delay > 0);\r
-\r
- return EFI_TIMEOUT;\r
-}\r
\r
/**\r
Get IDE i/o port registers' base addresses by mode.\r
return EFI_SUCCESS;\r
}\r
\r
-/**\r
- This function is used to implement the Soft Reset on the specified device. But,\r
- the ATA Soft Reset mechanism is so strong a reset method that it will force\r
- resetting on both devices connected to the same cable.\r
-\r
- It is called by IdeBlkIoReset(), a interface function of Block\r
- I/O protocol.\r
-\r
- This function can also be used by the ATAPI device to perform reset when\r
- ATAPI Reset command is failed.\r
-\r
- @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
- @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
- @param Timeout The time to complete the command, uses 100ns as a unit.\r
-\r
- @retval EFI_SUCCESS Soft reset completes successfully.\r
- @retval EFI_DEVICE_ERROR Any step during the reset process is failed.\r
-\r
- @note The registers initial values after ATA soft reset are different\r
- to the ATA device and ATAPI device.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AtaSoftReset (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN EFI_IDE_REGISTERS *IdeRegisters,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- UINT8 DeviceControl;\r
-\r
- DeviceControl = 0;\r
- //\r
- // disable Interrupt and set SRST bit to initiate soft reset\r
- //\r
- DeviceControl = ATA_CTLREG_SRST | ATA_CTLREG_IEN_L;\r
-\r
- IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
-\r
- //\r
- // SRST should assert for at least 5 us, we use 10 us for\r
- // better compatibility\r
- //\r
- MicroSecondDelay (10);\r
-\r
- //\r
- // Enable interrupt to support UDMA, and clear SRST bit\r
- //\r
- DeviceControl = 0;\r
- IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
-\r
- //\r
- // Wait for at least 10 ms to check BSY status, we use 10 ms\r
- // for better compatibility\r
- //\r
- MicroSecondDelay (10000);\r
-\r
- //\r
- // slave device needs at most 31ms to clear BSY\r
- //\r
- if (WaitForBSYClear (PciIo, IdeRegisters, Timeout) == EFI_TIMEOUT) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
\r
/**\r
Send ATA Ext command into device with NON_DATA protocol.\r
\r
@param[in] PciIo The PCI IO protocol instance.\r
@param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
+ @param[in] Timeout The time to complete the command, uses 100ns as a unit.\r
\r
@retval EFI_DEVICE_ERROR The memory is not set.\r
@retval EFI_TIMEOUT The memory setting is time out.\r
**/\r
EFI_STATUS\r
AtaUdmStatusWait (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN EFI_IDE_REGISTERS *IdeRegisters\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_IDE_REGISTERS *IdeRegisters,\r
+ IN UINT64 Timeout\r
)\r
{\r
UINT8 RegisterValue;\r
EFI_STATUS Status;\r
UINT16 IoPortForBmis;\r
- UINT64 Timeout;\r
+ UINT64 Delay;\r
+ BOOLEAN InfiniteWait;\r
\r
- Timeout = 2000;\r
+ if (Timeout == 0) {\r
+ InfiniteWait = TRUE;\r
+ } else {\r
+ InfiniteWait = FALSE;\r
+ }\r
+\r
+ Delay = DivU64x32 (Timeout, 1000) + 1;\r
\r
- while (TRUE) {\r
+ do {\r
Status = CheckStatusRegister (PciIo, IdeRegisters);\r
if (EFI_ERROR (Status)) {\r
Status = EFI_DEVICE_ERROR;\r
break;\r
}\r
//\r
- // Stall for 1 milliseconds.\r
+ // Stall for 100 microseconds.\r
//\r
- MicroSecondDelay (1000);\r
- Timeout--;\r
- }\r
+ MicroSecondDelay (100);\r
+ Delay--;\r
+ } while (InfiniteWait || (Delay > 0));\r
\r
return Status;\r
}\r
return EFI_SUCCESS;\r
}\r
\r
- if (Task->RetryTimes == 0) {\r
+ if (!Task->InfiniteWait && (Task->RetryTimes == 0)) {\r
return EFI_TIMEOUT;\r
} else {\r
//\r
UINTN PrdTableSize;\r
EFI_PHYSICAL_ADDRESS PrdTableMapAddr;\r
VOID *PrdTableMap;\r
- EFI_ATA_DMA_PRD *PrdBaseAddr;\r
+ EFI_PHYSICAL_ADDRESS PrdTableBaseAddr;\r
EFI_ATA_DMA_PRD *TempPrdBaseAddr;\r
UINTN PrdTableNum;\r
\r
EFI_PCI_IO_PROTOCOL *PciIo;\r
EFI_TPL OldTpl;\r
\r
+ UINTN AlignmentMask;\r
+ UINTN RealPageCount;\r
+ EFI_PHYSICAL_ADDRESS BaseAddr;\r
+ EFI_PHYSICAL_ADDRESS BaseMapAddr;\r
\r
Status = EFI_SUCCESS;\r
- PrdBaseAddr = NULL;\r
PrdTableMap = NULL;\r
BufferMap = NULL;\r
PageCount = 0;\r
+ RealPageCount = 0;\r
+ BaseAddr = 0;\r
PciIo = Instance->PciIo;\r
\r
if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {\r
\r
//\r
// Allocate buffer for PRD table initialization.\r
+ // Note Ide Bus Master spec said the descriptor table must be aligned on a 4 byte\r
+ // boundary and the table cannot cross a 64K boundary in memory.\r
+ //\r
+ PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);\r
+ RealPageCount = PageCount + EFI_SIZE_TO_PAGES (SIZE_64KB);\r
+\r
//\r
- PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);\r
+ // Make sure that PageCount plus EFI_SIZE_TO_PAGES (SIZE_64KB) does not overflow.\r
+ //\r
+ ASSERT (RealPageCount > PageCount);\r
+\r
Status = PciIo->AllocateBuffer (\r
PciIo,\r
AllocateAnyPages,\r
EfiBootServicesData,\r
- PageCount,\r
- (VOID **)&PrdBaseAddr,\r
+ RealPageCount,\r
+ (VOID **)&BaseAddr,\r
0\r
);\r
if (EFI_ERROR (Status)) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- ByteCount = EFI_PAGES_TO_SIZE (PageCount);\r
+ ByteCount = EFI_PAGES_TO_SIZE (RealPageCount);\r
Status = PciIo->Map (\r
PciIo,\r
EfiPciIoOperationBusMasterCommonBuffer,\r
- PrdBaseAddr,\r
+ (VOID*)(UINTN)BaseAddr,\r
&ByteCount,\r
- &PrdTableMapAddr,\r
+ &BaseMapAddr,\r
&PrdTableMap\r
);\r
- if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (PageCount))) {\r
+ if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (RealPageCount))) {\r
//\r
// If the data length actually mapped is not equal to the requested amount,\r
// it means the DMA operation may be broken into several discontinuous smaller chunks.\r
// Can't handle this case.\r
//\r
- PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+ PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount);\r
+ ZeroMem ((VOID *) ((UINTN) BaseAddr), ByteCount);\r
+\r
+ //\r
+ // Calculate the 64K align address as PRD Table base address.\r
+ //\r
+ AlignmentMask = SIZE_64KB - 1;\r
+ PrdTableBaseAddr = ((UINTN) BaseAddr + AlignmentMask) & ~AlignmentMask;\r
+ PrdTableMapAddr = ((UINTN) BaseMapAddr + AlignmentMask) & ~AlignmentMask;\r
\r
//\r
// Map the host address of DataBuffer to DMA master address.\r
);\r
if (EFI_ERROR (Status) || (ByteCount != DataLength)) {\r
PciIo->Unmap (PciIo, PrdTableMap);\r
- PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+ PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
// Fill the PRD table with appropriate bus master address of data buffer and data length.\r
//\r
ByteRemaining = ByteCount;\r
- TempPrdBaseAddr = PrdBaseAddr;\r
+ TempPrdBaseAddr = (EFI_ATA_DMA_PRD*)(UINTN)PrdTableBaseAddr;\r
while (ByteRemaining != 0) {\r
if (ByteRemaining <= 0x10000) {\r
TempPrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);\r
\r
if (Task != NULL) {\r
- //\r
- // Max transfer number of sectors for one command is 65536(32Mbyte),\r
- // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
- // So set the variable Count to 2000, for about 2 second Timeout time.\r
- //\r
- Task->RetryTimes = 2000;\r
Task->Map = BufferMap;\r
Task->TableMap = PrdTableMap;\r
- Task->MapBaseAddress = PrdBaseAddr;\r
- Task->PageCount = PageCount;\r
+ Task->MapBaseAddress = (EFI_ATA_DMA_PRD*)(UINTN)BaseAddr;\r
+ Task->PageCount = RealPageCount;\r
Task->IsStart = TRUE;\r
}\r
\r
\r
//\r
// Check the INTERRUPT and ERROR bit of BMIS\r
- // Max transfer number of sectors for one command is 65536(32Mbyte),\r
- // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
- // So set the variable Count to 2000, for about 2 second Timeout time.\r
//\r
if (Task != NULL) {\r
Status = AtaUdmStatusCheck (PciIo, Task, IdeRegisters);\r
} else {\r
- Status = AtaUdmStatusWait (PciIo, IdeRegisters);\r
+ Status = AtaUdmStatusWait (PciIo, IdeRegisters, Timeout);\r
}\r
\r
//\r
PciIo->Unmap (PciIo, Task->Map);\r
} else {\r
PciIo->Unmap (PciIo, PrdTableMap);\r
- PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+ PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);\r
PciIo->Unmap (PciIo, BufferMap);\r
}\r
\r
IN EFI_PCI_IO_PROTOCOL *PciIo,\r
IN EFI_IDE_REGISTERS *IdeRegisters,\r
IN OUT VOID *Buffer,\r
- IN UINT64 ByteCount,\r
+ IN OUT UINT32 *ByteCount,\r
IN BOOLEAN Read,\r
IN UINT64 Timeout\r
)\r
EFI_STATUS Status;\r
UINT16 *PtrBuffer;\r
\r
+ PtrBuffer = Buffer;\r
+ RequiredWordCount = *ByteCount >> 1;\r
+\r
//\r
// No data transfer is premitted.\r
//\r
- if (ByteCount == 0) {\r
+ if (RequiredWordCount == 0) {\r
return EFI_SUCCESS;\r
}\r
\r
- PtrBuffer = Buffer;\r
- RequiredWordCount = (UINT32)RShiftU64(ByteCount, 1);\r
//\r
- // ActuralWordCount means the word count of data really transferred.\r
+ // ActualWordCount means the word count of data really transferred.\r
//\r
ActualWordCount = 0;\r
\r
//\r
Status = DRQReady2 (PciIo, IdeRegisters, Timeout);\r
if (EFI_ERROR (Status)) {\r
- return CheckStatusRegister (PciIo, IdeRegisters);\r
+ if (Status == EFI_NOT_READY) {\r
+ //\r
+ // Device provided less data than we intended to read, or wanted less\r
+ // data than we intended to write, but it may still be successful.\r
+ //\r
+ break;\r
+ } else {\r
+ return Status;\r
+ }\r
}\r
\r
//\r
return EFI_DEVICE_ERROR;\r
}\r
\r
- return Status;\r
-}\r
-\r
-/**\r
- Sumbit ATAPI request sense command.\r
-\r
- @param[in] PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
- @param[in] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to\r
- store the IDE i/o port registers' base addresses\r
- @param[in] Channel The channel number of device.\r
- @param[in] Device The device number of device.\r
- @param[in] SenseData A pointer to store sense data.\r
- @param[in] SenseDataLength The sense data length.\r
- @param[in] Timeout The timeout value to execute this cmd, uses 100ns as a unit.\r
-\r
- @retval EFI_SUCCESS Send out the ATAPI packet command successfully.\r
- @retval EFI_DEVICE_ERROR The device failed to send data.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AtaPacketRequestSense (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN EFI_IDE_REGISTERS *IdeRegisters,\r
- IN UINT8 Channel,\r
- IN UINT8 Device,\r
- IN VOID *SenseData,\r
- IN UINT8 SenseDataLength,\r
- IN UINT64 Timeout\r
- )\r
-{\r
- EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;\r
- UINT8 Cdb[12];\r
- EFI_STATUS Status;\r
-\r
- ZeroMem (&Packet, sizeof (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));\r
- ZeroMem (Cdb, 12);\r
-\r
- Cdb[0] = ATA_CMD_REQUEST_SENSE;\r
- Cdb[4] = SenseDataLength;\r
-\r
- Packet.Timeout = Timeout;\r
- Packet.Cdb = Cdb;\r
- Packet.CdbLength = 12;\r
- Packet.DataDirection = EFI_EXT_SCSI_DATA_DIRECTION_READ;\r
- Packet.InDataBuffer = SenseData;\r
- Packet.InTransferLength = SenseDataLength;\r
-\r
- Status = AtaPacketCommandExecute (PciIo, IdeRegisters, Channel, Device, &Packet);\r
-\r
+ *ByteCount = ActualWordCount << 1;\r
return Status;\r
}\r
\r
IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
)\r
{\r
- EFI_STATUS PacketCommandStatus;\r
EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
EFI_STATUS Status;\r
UINT8 Count;\r
// Read/Write the data of ATAPI Command\r
//\r
if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
- PacketCommandStatus = AtaPacketReadWrite (\r
- PciIo,\r
- IdeRegisters,\r
- Packet->InDataBuffer,\r
- Packet->InTransferLength,\r
- TRUE,\r
- Packet->Timeout\r
- );\r
+ Status = AtaPacketReadWrite (\r
+ PciIo,\r
+ IdeRegisters,\r
+ Packet->InDataBuffer,\r
+ &Packet->InTransferLength,\r
+ TRUE,\r
+ Packet->Timeout\r
+ );\r
} else {\r
- PacketCommandStatus = AtaPacketReadWrite (\r
- PciIo,\r
- IdeRegisters,\r
- Packet->OutDataBuffer,\r
- Packet->OutTransferLength,\r
- FALSE,\r
- Packet->Timeout\r
- );\r
- }\r
-\r
- if (!EFI_ERROR (PacketCommandStatus)) {\r
- return PacketCommandStatus;\r
- }\r
-\r
- //\r
- // Return SenseData if PacketCommandStatus matches\r
- // the following return codes.\r
- //\r
- if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||\r
- (PacketCommandStatus == EFI_DEVICE_ERROR) ||\r
- (PacketCommandStatus == EFI_TIMEOUT)) {\r
-\r
- //\r
- // avoid submit request sense command continuously.\r
- //\r
- if ((Packet->SenseData == NULL) || (((UINT8 *)Packet->Cdb)[0] == ATA_CMD_REQUEST_SENSE)) {\r
- return PacketCommandStatus;\r
- }\r
-\r
- AtaPacketRequestSense (\r
- PciIo,\r
- IdeRegisters,\r
- Channel,\r
- Device,\r
- Packet->SenseData,\r
- Packet->SenseDataLength,\r
- Packet->Timeout\r
- );\r
+ Status = AtaPacketReadWrite (\r
+ PciIo,\r
+ IdeRegisters,\r
+ Packet->OutDataBuffer,\r
+ &Packet->OutTransferLength,\r
+ FALSE,\r
+ Packet->Timeout\r
+ );\r
}\r
\r
- return PacketCommandStatus;\r
+ return Status;\r
}\r
\r
\r
);\r
\r
if (EFI_ERROR (Status)) {\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
+ );\r
return EFI_DEVICE_ERROR;\r
}\r
\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
+ );\r
+\r
LBAMid = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderLsb);\r
LBAHigh = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderMsb);\r
\r
// The threshold exceeded condition is not detected by the device\r
//\r
DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
-\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
+ );\r
} else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
//\r
// The threshold exceeded condition is detected by the device\r
//\r
DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
+ );\r
}\r
\r
return EFI_SUCCESS;\r
//\r
DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at [%a] channel [%a] device!\n",\r
(Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
+ );\r
} else {\r
//\r
// Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
//\r
if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLE)\r
+ );\r
+\r
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
\r
AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
PciIo = Instance->PciIo;\r
\r
for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) {\r
+ //\r
+ // Select Master or Slave device to get the return signature for ATA DEVICE DIAGNOSTIC cmd.\r
+ //\r
+ IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)((IdeDevice << 4) | 0xe0));\r
+\r
//\r
// Send ATA Device Execut Diagnostic command.\r
// This command should work no matter DRDY is ready or not\r