return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Transfer data from ATA device.\r
+\r
+ This function performs one ATA pass through transaction to transfer data from/to\r
+ ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru\r
+ interface of ATA pass through.\r
+\r
+ @param[in] DeviceData A pointer to PEI_AHCI_ATA_DEVICE_DATA structure.\r
+ @param[in,out] Buffer The pointer to the current transaction buffer.\r
+ @param[in] StartLba The starting logical block address to be accessed.\r
+ @param[in] TransferLength The block number or sector count of the transfer.\r
+ @param[in] IsWrite Indicates whether it is a write operation.\r
+\r
+ @retval EFI_SUCCESS The data transfer is complete successfully.\r
+ @return others Some error occurs when transferring data.\r
+\r
+**/\r
+EFI_STATUS\r
+TransferAtaDevice (\r
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,\r
+ IN OUT VOID *Buffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINT32 TransferLength,\r
+ IN BOOLEAN IsWrite\r
+ )\r
+{\r
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;\r
+ EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThru;\r
+ EFI_ATA_COMMAND_BLOCK Acb;\r
+ EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+ Private = DeviceData->Private;\r
+ AtaPassThru = &Private->AtaPassThruPpi;\r
+\r
+ //\r
+ // Ensure Lba48Bit and IsWrite are valid boolean values\r
+ //\r
+ ASSERT ((UINTN) DeviceData->Lba48Bit < 2);\r
+ ASSERT ((UINTN) IsWrite < 2);\r
+ if (((UINTN) DeviceData->Lba48Bit >= 2) ||\r
+ ((UINTN) IsWrite >= 2)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Prepare for ATA command block.\r
+ //\r
+ ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+ Acb.AtaCommand = mAtaCommands[DeviceData->Lba48Bit][IsWrite];\r
+ Acb.AtaSectorNumber = (UINT8) StartLba;\r
+ Acb.AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8);\r
+ Acb.AtaCylinderHigh = (UINT8) RShiftU64 (StartLba, 16);\r
+ Acb.AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 |\r
+ (DeviceData->PortMultiplier == 0xFFFF ?\r
+ 0 : (DeviceData->PortMultiplier << 4)));\r
+ Acb.AtaSectorCount = (UINT8) TransferLength;\r
+ if (DeviceData->Lba48Bit) {\r
+ Acb.AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24);\r
+ Acb.AtaCylinderLowExp = (UINT8) RShiftU64 (StartLba, 32);\r
+ Acb.AtaCylinderHighExp = (UINT8) RShiftU64 (StartLba, 40);\r
+ Acb.AtaSectorCountExp = (UINT8) (TransferLength >> 8);\r
+ } else {\r
+ Acb.AtaDeviceHead = (UINT8) (Acb.AtaDeviceHead | RShiftU64 (StartLba, 24));\r
+ }\r
+\r
+ //\r
+ // Prepare for ATA pass through packet.\r
+ //\r
+ ZeroMem (&Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
+ if (IsWrite) {\r
+ Packet.OutDataBuffer = Buffer;\r
+ Packet.OutTransferLength = TransferLength;\r
+ } else {\r
+ Packet.InDataBuffer = Buffer;\r
+ Packet.InTransferLength = TransferLength;\r
+ }\r
+ Packet.Asb = NULL;\r
+ Packet.Acb = &Acb;\r
+ Packet.Protocol = mAtaPassThruCmdProtocols[IsWrite];\r
+ Packet.Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;\r
+ //\r
+ // |------------------------|-----------------|\r
+ // | ATA PIO Transfer Mode | Transfer Rate |\r
+ // |------------------------|-----------------|\r
+ // | PIO Mode 0 | 3.3Mbytes/sec |\r
+ // |------------------------|-----------------|\r
+ // | PIO Mode 1 | 5.2Mbytes/sec |\r
+ // |------------------------|-----------------|\r
+ // | PIO Mode 2 | 8.3Mbytes/sec |\r
+ // |------------------------|-----------------|\r
+ // | PIO Mode 3 | 11.1Mbytes/sec |\r
+ // |------------------------|-----------------|\r
+ // | PIO Mode 4 | 16.6Mbytes/sec |\r
+ // |------------------------|-----------------|\r
+ //\r
+ // As AtaBus is used to manage ATA devices, we have to use the lowest transfer\r
+ // rate to calculate the possible maximum timeout value for each read/write\r
+ // operation. The timout value is rounded up to nearest integar and here an\r
+ // additional 30s is added to follow ATA spec in which it mentioned that the\r
+ // device may take up to 30s to respond commands in the Standby/Idle mode.\r
+ //\r
+ // Calculate the maximum timeout value for PIO read/write operation.\r
+ //\r
+ Packet.Timeout = TIMER_PERIOD_SECONDS (\r
+ DivU64x32 (\r
+ MultU64x32 (TransferLength, DeviceData->Media.BlockSize),\r
+ 3300000\r
+ ) + 31\r
+ );\r
+\r
+ return AtaPassThru->PassThru (\r
+ AtaPassThru,\r
+ DeviceData->Port,\r
+ DeviceData->PortMultiplier,\r
+ &Packet\r
+ );\r
+}\r
+\r
/**\r
Trust transfer data from/to ATA device.\r
\r
NULL\r
};\r
\r
+EFI_PEI_PPI_DESCRIPTOR mAhciBlkIoPpiListTemplate = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEfiPeiVirtualBlockIoPpiGuid,\r
+ NULL\r
+};\r
+\r
+EFI_PEI_PPI_DESCRIPTOR mAhciBlkIo2PpiListTemplate = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEfiPeiVirtualBlockIo2PpiGuid,\r
+ NULL\r
+};\r
+\r
EFI_PEI_PPI_DESCRIPTOR mAhciStorageSecurityPpiListTemplate = {\r
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
&gEdkiiPeiStorageSecurityCommandPpiGuid,\r
Private->AtaPassThruPpiList.Ppi = &Private->AtaPassThruPpi;\r
PeiServicesInstallPpi (&Private->AtaPassThruPpiList);\r
\r
+ Private->BlkIoPpi.GetNumberOfBlockDevices = AhciBlockIoGetDeviceNo;\r
+ Private->BlkIoPpi.GetBlockDeviceMediaInfo = AhciBlockIoGetMediaInfo;\r
+ Private->BlkIoPpi.ReadBlocks = AhciBlockIoReadBlocks;\r
+ CopyMem (\r
+ &Private->BlkIoPpiList,\r
+ &mAhciBlkIoPpiListTemplate,\r
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
+ );\r
+ Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;\r
+ PeiServicesInstallPpi (&Private->BlkIoPpiList);\r
+\r
+ Private->BlkIo2Ppi.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;\r
+ Private->BlkIo2Ppi.GetNumberOfBlockDevices = AhciBlockIoGetDeviceNo2;\r
+ Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = AhciBlockIoGetMediaInfo2;\r
+ Private->BlkIo2Ppi.ReadBlocks = AhciBlockIoReadBlocks2;\r
+ CopyMem (\r
+ &Private->BlkIo2PpiList,\r
+ &mAhciBlkIo2PpiListTemplate,\r
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
+ );\r
+ Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;\r
+ PeiServicesInstallPpi (&Private->BlkIo2PpiList);\r
+\r
if (Private->TrustComputingDevices != 0) {\r
DEBUG ((\r
DEBUG_INFO,\r
#include <Ppi/IoMmu.h>\r
#include <Ppi/EndOfPeiPhase.h>\r
#include <Ppi/AtaPassThru.h>\r
+#include <Ppi/BlockIo.h>\r
#include <Ppi/BlockIo2.h>\r
#include <Ppi/StorageSecurityCommand.h>\r
\r
typedef struct _PEI_AHCI_CONTROLLER_PRIVATE_DATA PEI_AHCI_CONTROLLER_PRIVATE_DATA;\r
\r
#include "AhciPeiPassThru.h"\r
+#include "AhciPeiBlockIo.h"\r
#include "AhciPeiStorageSecurity.h"\r
\r
//\r
\r
EFI_ATA_PASS_THRU_MODE AtaPassThruMode;\r
EDKII_PEI_ATA_PASS_THRU_PPI AtaPassThruPpi;\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;\r
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;\r
EDKII_PEI_STORAGE_SECURITY_CMD_PPI StorageSecurityPpi;\r
EFI_PEI_PPI_DESCRIPTOR AtaPassThruPpiList;\r
EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;\r
IN OUT PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private\r
);\r
\r
+/**\r
+ Transfer data from ATA device.\r
+\r
+ This function performs one ATA pass through transaction to transfer data from/to\r
+ ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru\r
+ interface of ATA pass through.\r
+\r
+ @param[in] DeviceData A pointer to PEI_AHCI_ATA_DEVICE_DATA structure.\r
+ @param[in,out] Buffer The pointer to the current transaction buffer.\r
+ @param[in] StartLba The starting logical block address to be accessed.\r
+ @param[in] TransferLength The block number or sector count of the transfer.\r
+ @param[in] IsWrite Indicates whether it is a write operation.\r
+\r
+ @retval EFI_SUCCESS The data transfer is complete successfully.\r
+ @return others Some error occurs when transferring data.\r
+\r
+**/\r
+EFI_STATUS\r
+TransferAtaDevice (\r
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,\r
+ IN OUT VOID *Buffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINT32 TransferLength,\r
+ IN BOOLEAN IsWrite\r
+ );\r
+\r
/**\r
Trust transfer data from/to ATA device.\r
\r
[Sources]\r
AhciPei.c\r
AhciPei.h\r
+ AhciPeiBlockIo.c\r
+ AhciPeiBlockIo.h\r
AhciPeiPassThru.c\r
AhciPeiPassThru.h\r
AhciPeiS3.c\r
gEdkiiIoMmuPpiGuid ## CONSUMES\r
gEfiEndOfPeiSignalPpiGuid ## CONSUMES\r
gEdkiiPeiAtaPassThruPpiGuid ## SOMETIMES_PRODUCES\r
+ gEfiPeiVirtualBlockIoPpiGuid ## SOMETIMES_PRODUCES\r
+ gEfiPeiVirtualBlockIo2PpiGuid ## SOMETIMES_PRODUCES\r
gEdkiiPeiStorageSecurityCommandPpiGuid ## SOMETIMES_PRODUCES\r
\r
[Guids]\r
--- /dev/null
+/** @file\r
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI\r
+ mode at PEI phase.\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "AhciPei.h"\r
+\r
+/**\r
+ Traverse the attached ATA devices list to find out the device with given index.\r
+\r
+ @param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA\r
+ instance.\r
+ @param[in] DeviceIndex The device index.\r
+\r
+ @retval The pointer to the PEI_AHCI_ATA_DEVICE_DATA structure of the device\r
+ info to access.\r
+\r
+**/\r
+PEI_AHCI_ATA_DEVICE_DATA *\r
+SearchDeviceByIndex (\r
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN UINTN DeviceIndex\r
+ )\r
+{\r
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;\r
+ LIST_ENTRY *Node;\r
+\r
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->ActiveDevices)) {\r
+ return NULL;\r
+ }\r
+\r
+ Node = GetFirstNode (&Private->DeviceList);\r
+ while (!IsNull (&Private->DeviceList, Node)) {\r
+ DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);\r
+\r
+ if (DeviceData->DeviceIndex == DeviceIndex) {\r
+ return DeviceData;\r
+ }\r
+\r
+ Node = GetNextNode (&Private->DeviceList, Node);\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Read a number of blocks from ATA device.\r
+\r
+ This function performs ATA pass through transactions to read data from ATA device.\r
+ It may separate the read request into several ATA pass through transactions.\r
+\r
+ @param[in] DeviceData The pointer to the PEI_AHCI_ATA_DEVICE_DATA\r
+ data structure.\r
+ @param[in,out] Buffer The pointer to the current transaction buffer.\r
+ @param[in] StartLba The starting logical block address to be accessed.\r
+ @param[in] NumberOfBlocks The block number or sector count of the transfer.\r
+\r
+ @retval EFI_SUCCESS The data transfer is complete successfully.\r
+ @return Others Some error occurs when transferring data.\r
+\r
+**/\r
+EFI_STATUS\r
+AccessAtaDevice (\r
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,\r
+ IN OUT UINT8 *Buffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN MaxTransferBlockNumber;\r
+ UINTN TransferBlockNumber;\r
+ UINTN BlockSize;\r
+\r
+ //\r
+ // Ensure Lba48Bit is a valid boolean value\r
+ //\r
+ ASSERT ((UINTN) DeviceData->Lba48Bit < 2);\r
+ if ((UINTN) DeviceData->Lba48Bit >= 2) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ MaxTransferBlockNumber = mMaxTransferBlockNumber[DeviceData->Lba48Bit];\r
+ BlockSize = DeviceData->Media.BlockSize;\r
+\r
+ do {\r
+ if (NumberOfBlocks > MaxTransferBlockNumber) {\r
+ TransferBlockNumber = MaxTransferBlockNumber;\r
+ NumberOfBlocks -= MaxTransferBlockNumber;\r
+ } else {\r
+ TransferBlockNumber = NumberOfBlocks;\r
+ NumberOfBlocks = 0;\r
+ }\r
+ DEBUG ((\r
+ DEBUG_BLKIO, "%a: Blocking AccessAtaDevice, TransferBlockNumber = %x; StartLba = %x\n",\r
+ __FUNCTION__, TransferBlockNumber, StartLba\r
+ ));\r
+\r
+ Status = TransferAtaDevice (\r
+ DeviceData,\r
+ Buffer,\r
+ StartLba,\r
+ (UINT32) TransferBlockNumber,\r
+ FALSE // Read\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ StartLba += TransferBlockNumber;\r
+ Buffer += TransferBlockNumber * BlockSize;\r
+ } while (NumberOfBlocks > 0);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read specified bytes from Lba from the device.\r
+\r
+ @param[in] DeviceData The pointer to the PEI_AHCI_ATA_DEVICE_DATA data structure.\r
+ @param[out] Buffer The Buffer used to store the Data read from the device.\r
+ @param[in] StartLba The start block number.\r
+ @param[in] BufferSize Total bytes to be read.\r
+\r
+ @retval EFI_SUCCESS Data are read from the device.\r
+ @retval Others Fail to read all the data.\r
+\r
+**/\r
+EFI_STATUS\r
+AhciRead (\r
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,\r
+ OUT VOID *Buffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN BufferSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+\r
+ //\r
+ // Check parameters.\r
+ //\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ BlockSize = DeviceData->Media.BlockSize;\r
+ if ((BufferSize % BlockSize) != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (StartLba > DeviceData->Media.LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+ if (NumberOfBlocks - 1 > DeviceData->Media.LastBlock - StartLba) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Invoke low level AtaDevice Access Routine.\r
+ //\r
+ Status = AccessAtaDevice (DeviceData, Buffer, StartLba, NumberOfBlocks);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one\r
+ specific block driver detects. If no device is detected, then the function\r
+ will return zero.\r
+\r
+ @param[in] PeiServices General-purpose services that are available\r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI\r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciBlockIoGetDeviceNo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ )\r
+{\r
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;\r
+\r
+ if (This == NULL || NumberBlockDevices == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);\r
+ *NumberBlockDevices = Private->ActiveDevices;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media\r
+ information. If the media changes, calling this function will update the media\r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, the PPIs that\r
+ want to talk to a single device must specify the\r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to\r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media.\r
+ The caller is responsible for the ownership of this\r
+ data structure.\r
+\r
+ @par Note:\r
+ The MediaInfo structure describes an enumeration of possible block device\r
+ types. This enumeration exists because no device paths are actually passed\r
+ across interfaces that describe the type or class of hardware that is publishing\r
+ the block I/O interface. This enumeration will allow for policy decisions\r
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+ by a given device type, they should be reported in ascending order; this\r
+ order also applies to nested partitions, such as legacy MBR, where the\r
+ outermost partitions would have precedence in the reporting order. The\r
+ same logic applies to systems such as IDE that have precedence relationships\r
+ like "Master/Slave" or "Primary/Secondary". The master device should be\r
+ reported first, the slave second.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device\r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciBlockIoGetMediaInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo\r
+ )\r
+{\r
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;\r
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;\r
+\r
+ if (This == NULL || MediaInfo == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);\r
+ DeviceData = SearchDeviceByIndex (Private, DeviceIndex);\r
+ if (DeviceData == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ MediaInfo->DeviceType = (EFI_PEI_BLOCK_DEVICE_TYPE) EDKII_PEI_BLOCK_DEVICE_TYPE_ATA_HARD_DISK;\r
+ MediaInfo->MediaPresent = TRUE;\r
+ MediaInfo->LastBlock = (UINTN) DeviceData->Media.LastBlock;\r
+ MediaInfo->BlockSize = DeviceData->Media.BlockSize;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to\r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, PPIs that\r
+ want to talk to a single device must specify the device\r
+ index that was assigned during the enumeration process.\r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciBlockIoReadBlocks (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;\r
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);\r
+ DeviceData = SearchDeviceByIndex (Private, DeviceIndex);\r
+ if (DeviceData == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ return AhciRead (DeviceData, Buffer, StartLBA, BufferSize);\r
+}\r
+\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one\r
+ specific block driver detects. If no device is detected, then the function\r
+ will return zero.\r
+\r
+ @param[in] PeiServices General-purpose services that are available\r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI\r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciBlockIoGetDeviceNo2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ )\r
+{\r
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;\r
+\r
+ if (This == NULL || NumberBlockDevices == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);\r
+ *NumberBlockDevices = Private->ActiveDevices;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media\r
+ information. If the media changes, calling this function will update the media\r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, the PPIs that\r
+ want to talk to a single device must specify the\r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to\r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media.\r
+ The caller is responsible for the ownership of this\r
+ data structure.\r
+\r
+ @par Note:\r
+ The MediaInfo structure describes an enumeration of possible block device\r
+ types. This enumeration exists because no device paths are actually passed\r
+ across interfaces that describe the type or class of hardware that is publishing\r
+ the block I/O interface. This enumeration will allow for policy decisions\r
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+ by a given device type, they should be reported in ascending order; this\r
+ order also applies to nested partitions, such as legacy MBR, where the\r
+ outermost partitions would have precedence in the reporting order. The\r
+ same logic applies to systems such as IDE that have precedence relationships\r
+ like "Master/Slave" or "Primary/Secondary". The master device should be\r
+ reported first, the slave second.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device\r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciBlockIoGetMediaInfo2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo\r
+ )\r
+{\r
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;\r
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;\r
+\r
+ if (This == NULL || MediaInfo == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);\r
+ DeviceData = SearchDeviceByIndex (Private, DeviceIndex);\r
+ if (DeviceData == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ CopyMem (\r
+ MediaInfo,\r
+ &DeviceData->Media,\r
+ sizeof (EFI_PEI_BLOCK_IO2_MEDIA)\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to\r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, PPIs that\r
+ want to talk to a single device must specify the device\r
+ index that was assigned during the enumeration process.\r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciBlockIoReadBlocks2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);\r
+ return AhciBlockIoReadBlocks (\r
+ PeiServices,\r
+ &Private->BlkIoPpi,\r
+ DeviceIndex,\r
+ StartLBA,\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+}\r
--- /dev/null
+/** @file\r
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI\r
+ mode at PEI phase.\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef _AHCI_PEI_BLOCKIO_H_\r
+#define _AHCI_PEI_BLOCKIO_H_\r
+\r
+//\r
+// ATA hard disk device for EFI_PEI_BLOCK_DEVICE_TYPE\r
+//\r
+#define EDKII_PEI_BLOCK_DEVICE_TYPE_ATA_HARD_DISK 8\r
+\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one\r
+ specific block driver detects. If no device is detected, then the function\r
+ will return zero.\r
+\r
+ @param[in] PeiServices General-purpose services that are available\r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI\r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciBlockIoGetDeviceNo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ );\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media\r
+ information. If the media changes, calling this function will update the media\r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, the PPIs that\r
+ want to talk to a single device must specify the\r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to\r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media.\r
+ The caller is responsible for the ownership of this\r
+ data structure.\r
+\r
+ @par Note:\r
+ The MediaInfo structure describes an enumeration of possible block device\r
+ types. This enumeration exists because no device paths are actually passed\r
+ across interfaces that describe the type or class of hardware that is publishing\r
+ the block I/O interface. This enumeration will allow for policy decisions\r
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+ by a given device type, they should be reported in ascending order; this\r
+ order also applies to nested partitions, such as legacy MBR, where the\r
+ outermost partitions would have precedence in the reporting order. The\r
+ same logic applies to systems such as IDE that have precedence relationships\r
+ like "Master/Slave" or "Primary/Secondary". The master device should be\r
+ reported first, the slave second.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device\r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciBlockIoGetMediaInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo\r
+ );\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to\r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, PPIs that\r
+ want to talk to a single device must specify the device\r
+ index that was assigned during the enumeration process.\r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciBlockIoReadBlocks (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+ This function is used for getting the count of block I/O devices that one\r
+ specific block driver detects. If no device is detected, then the function\r
+ will return zero.\r
+\r
+ @param[in] PeiServices General-purpose services that are available\r
+ to every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI\r
+ instance.\r
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.\r
+\r
+ @retval EFI_SUCCESS The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciBlockIoGetDeviceNo2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ OUT UINTN *NumberBlockDevices\r
+ );\r
+\r
+/**\r
+ Gets a block device's media information.\r
+\r
+ This function will provide the caller with the specified block device's media\r
+ information. If the media changes, calling this function will update the media\r
+ information accordingly.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every\r
+ PEIM\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, the PPIs that\r
+ want to talk to a single device must specify the\r
+ device index that was assigned during the enumeration\r
+ process. This index is a number from one to\r
+ NumberBlockDevices.\r
+ @param[out] MediaInfo The media information of the specified block media.\r
+ The caller is responsible for the ownership of this\r
+ data structure.\r
+\r
+ @par Note:\r
+ The MediaInfo structure describes an enumeration of possible block device\r
+ types. This enumeration exists because no device paths are actually passed\r
+ across interfaces that describe the type or class of hardware that is publishing\r
+ the block I/O interface. This enumeration will allow for policy decisions\r
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+ by a given device type, they should be reported in ascending order; this\r
+ order also applies to nested partitions, such as legacy MBR, where the\r
+ outermost partitions would have precedence in the reporting order. The\r
+ same logic applies to systems such as IDE that have precedence relationships\r
+ like "Master/Slave" or "Primary/Secondary". The master device should be\r
+ reported first, the slave second.\r
+\r
+ @retval EFI_SUCCESS Media information about the specified block device\r
+ was obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciBlockIoGetMediaInfo2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo\r
+ );\r
+\r
+/**\r
+ Reads the requested number of blocks from the specified block device.\r
+\r
+ The function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned. If there is no media in the device,\r
+ the function returns EFI_NO_MEDIA.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to\r
+ every PEIM.\r
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+ @param[in] DeviceIndex Specifies the block device to which the function wants\r
+ to talk. Because the driver that implements Block I/O\r
+ PPIs will manage multiple block devices, PPIs that\r
+ want to talk to a single device must specify the device\r
+ index that was assigned during the enumeration process.\r
+ This index is a number from one to NumberBlockDevices.\r
+ @param[in] StartLBA The starting logical block address (LBA) to read from\r
+ on the device\r
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be\r
+ a multiple of the intrinsic block size of the device.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for the ownership of the\r
+ buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not properly aligned.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciBlockIoReadBlocks2 (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+ IN UINTN DeviceIndex,\r
+ IN EFI_PEI_LBA StartLBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+#endif\r