From: "Ni, Ray" <ray.ni@intel.com>
To: "devel@edk2.groups.io" <devel@edk2.groups.io>,
"Wu, Hao A" <hao.a.wu@intel.com>
Cc: "Dong, Eric" <eric.dong@intel.com>,
"Wang, Jian J" <jian.j.wang@intel.com>
Subject: Re: [edk2-devel] [PATCH v3 2/2] MdeModulePkg/AhciPei: Add PEI BlockIO support
Date: Tue, 23 Apr 2019 18:14:57 +0000 [thread overview]
Message-ID: <734D49CCEBEEF84792F5B80ED585239D5C0FEB4D@SHSMSX104.ccr.corp.intel.com> (raw)
In-Reply-To: <20190423080630.14992-3-hao.a.wu@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
> -----Original Message-----
> From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> Wu, Hao A
> Sent: Tuesday, April 23, 2019 1:07 AM
> To: devel@edk2.groups.io
> Cc: Wu, Hao A <hao.a.wu@intel.com>; Ni, Ray <ray.ni@intel.com>; Dong,
> Eric <eric.dong@intel.com>; Wang, Jian J <jian.j.wang@intel.com>
> Subject: [edk2-devel] [PATCH v3 2/2] MdeModulePkg/AhciPei: Add PEI
> BlockIO support
>
> REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1483
>
> This commit will add the PEI BlockIO (2) PPIs support for AHCI mode ATA
> devices.
>
> More specifically, the driver will consume the ATA AHCI host controller
> PPI for ATA controllers working under AHCI code within the system. And
> then produces the below additional PPIs for each controller:
>
> EFI PEI Recovery Block IO PPI
> EFI PEI Recovery Block IO2 PPI
>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Signed-off-by: Hao Wu <hao.a.wu@intel.com>
> ---
> MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf | 4 +
> MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h | 30 ++
> MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.h | 257 ++++++++++
> MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c | 118 +++++
> MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c | 35 ++
> MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c | 516
> ++++++++++++++++++++
> 6 files changed, 960 insertions(+)
>
> diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
> b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
> index bf686a198f..912ff7a8ba 100644
> --- a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
> +++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
> @@ -26,6 +26,8 @@ [Defines]
> [Sources]
> AhciPei.c
> AhciPei.h
> + AhciPeiBlockIo.c
> + AhciPeiBlockIo.h
> AhciPeiPassThru.c
> AhciPeiPassThru.h
> AhciPeiS3.c
> @@ -54,6 +56,8 @@ [Ppis]
> gEdkiiIoMmuPpiGuid ## CONSUMES
> gEfiEndOfPeiSignalPpiGuid ## CONSUMES
> gEdkiiPeiAtaPassThruPpiGuid ## SOMETIMES_PRODUCES
> + gEfiPeiVirtualBlockIoPpiGuid ## SOMETIMES_PRODUCES
> + gEfiPeiVirtualBlockIo2PpiGuid ## SOMETIMES_PRODUCES
> gEdkiiPeiStorageSecurityCommandPpiGuid ## SOMETIMES_PRODUCES
>
> [Guids]
> diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
> b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
> index e6a9c0a333..9a34dc6e4f 100644
> --- a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
> +++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
> @@ -19,6 +19,7 @@
> #include <Ppi/IoMmu.h>
> #include <Ppi/EndOfPeiPhase.h>
> #include <Ppi/AtaPassThru.h>
> +#include <Ppi/BlockIo.h>
> #include <Ppi/BlockIo2.h>
> #include <Ppi/StorageSecurityCommand.h>
>
> @@ -35,6 +36,7 @@
> typedef struct _PEI_AHCI_CONTROLLER_PRIVATE_DATA
> PEI_AHCI_CONTROLLER_PRIVATE_DATA;
>
> #include "AhciPeiPassThru.h"
> +#include "AhciPeiBlockIo.h"
> #include "AhciPeiStorageSecurity.h"
>
> //
> @@ -312,6 +314,8 @@ struct _PEI_AHCI_CONTROLLER_PRIVATE_DATA {
>
> EFI_ATA_PASS_THRU_MODE AtaPassThruMode;
> EDKII_PEI_ATA_PASS_THRU_PPI AtaPassThruPpi;
> + EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;
> + EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;
> EDKII_PEI_STORAGE_SECURITY_CMD_PPI StorageSecurityPpi;
> EFI_PEI_PPI_DESCRIPTOR AtaPassThruPpiList;
> EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;
> @@ -554,6 +558,32 @@ AhciModeInitialization (
> );
>
> /**
> + Transfer data from ATA device.
> +
> + This function performs one ATA pass through transaction to transfer data
> from/to
> + ATA device. It chooses the appropriate ATA command and protocol to
> invoke PassThru
> + interface of ATA pass through.
> +
> + @param[in] DeviceData A pointer to PEI_AHCI_ATA_DEVICE_DATA
> structure.
> + @param[in,out] Buffer The pointer to the current transaction buffer.
> + @param[in] StartLba The starting logical block address to be
> accessed.
> + @param[in] TransferLength The block number or sector count of the
> transfer.
> + @param[in] IsWrite Indicates whether it is a write operation.
> +
> + @retval EFI_SUCCESS The data transfer is complete successfully.
> + @return others Some error occurs when transferring data.
> +
> +**/
> +EFI_STATUS
> +TransferAtaDevice (
> + IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
> + IN OUT VOID *Buffer,
> + IN EFI_LBA StartLba,
> + IN UINT32 TransferLength,
> + IN BOOLEAN IsWrite
> + );
> +
> +/**
> Trust transfer data from/to ATA device.
>
> This function performs one ATA pass through transaction to do a trust
> transfer
> diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.h
> b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.h
> new file mode 100644
> index 0000000000..5896ae5acf
> --- /dev/null
> +++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.h
> @@ -0,0 +1,257 @@
> +/** @file
> + The AhciPei driver is used to manage ATA hard disk device working under
> AHCI
> + mode at PEI phase.
> +
> + Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _AHCI_PEI_BLOCKIO_H_
> +#define _AHCI_PEI_BLOCKIO_H_
> +
> +//
> +// ATA hard disk device for EFI_PEI_BLOCK_DEVICE_TYPE
> +//
> +#define EDKII_PEI_BLOCK_DEVICE_TYPE_ATA_HARD_DISK 8
> +
> +/**
> + Gets the count of block I/O devices that one specific block driver detects.
> +
> + This function is used for getting the count of block I/O devices that one
> + specific block driver detects. If no device is detected, then the function
> + will return zero.
> +
> + @param[in] PeiServices General-purpose services that are available
> + to every PEIM.
> + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
> + instance.
> + @param[out] NumberBlockDevices The number of block I/O devices
> discovered.
> +
> + @retval EFI_SUCCESS The operation performed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciBlockIoGetDeviceNo (
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
> + OUT UINTN *NumberBlockDevices
> + );
> +
> +/**
> + Gets a block device's media information.
> +
> + This function will provide the caller with the specified block device's media
> + information. If the media changes, calling this function will update the
> media
> + information accordingly.
> +
> + @param[in] PeiServices General-purpose services that are available to
> every
> + PEIM
> + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
> instance.
> + @param[in] DeviceIndex Specifies the block device to which the function
> wants
> + to talk. Because the driver that implements Block I/O
> + PPIs will manage multiple block devices, the PPIs that
> + want to talk to a single device must specify the
> + device index that was assigned during the enumeration
> + process. This index is a number from one to
> + NumberBlockDevices.
> + @param[out] MediaInfo The media information of the specified block
> media.
> + The caller is responsible for the ownership of this
> + data structure.
> +
> + @par Note:
> + The MediaInfo structure describes an enumeration of possible block
> device
> + types. This enumeration exists because no device paths are actually
> passed
> + across interfaces that describe the type or class of hardware that is
> publishing
> + the block I/O interface. This enumeration will allow for policy decisions
> + in the Recovery PEIM, such as "Try to recover from legacy floppy first,
> + LS-120 second, CD-ROM third." If there are multiple partitions
> abstracted
> + by a given device type, they should be reported in ascending order; this
> + order also applies to nested partitions, such as legacy MBR, where the
> + outermost partitions would have precedence in the reporting order.
> The
> + same logic applies to systems such as IDE that have precedence
> relationships
> + like "Master/Slave" or "Primary/Secondary". The master device should
> be
> + reported first, the slave second.
> +
> + @retval EFI_SUCCESS Media information about the specified block
> device
> + was obtained successfully.
> + @retval EFI_DEVICE_ERROR Cannot get the media information due to a
> hardware
> + error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciBlockIoGetMediaInfo (
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
> + IN UINTN DeviceIndex,
> + OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
> + );
> +
> +/**
> + Reads the requested number of blocks from the specified block device.
> +
> + The function reads the requested number of blocks from the device. All
> the
> + blocks are read, or an error is returned. If there is no media in the device,
> + the function returns EFI_NO_MEDIA.
> +
> + @param[in] PeiServices General-purpose services that are available to
> + every PEIM.
> + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
> instance.
> + @param[in] DeviceIndex Specifies the block device to which the function
> wants
> + to talk. Because the driver that implements Block I/O
> + PPIs will manage multiple block devices, PPIs that
> + want to talk to a single device must specify the device
> + index that was assigned during the enumeration process.
> + This index is a number from one to NumberBlockDevices.
> + @param[in] StartLBA The starting logical block address (LBA) to read
> from
> + on the device
> + @param[in] BufferSize The size of the Buffer in bytes. This number must
> be
> + a multiple of the intrinsic block size of the device.
> + @param[out] Buffer A pointer to the destination buffer for the data.
> + The caller is responsible for the ownership of the
> + buffer.
> +
> + @retval EFI_SUCCESS The data was read correctly from the device.
> + @retval EFI_DEVICE_ERROR The device reported an error while
> attempting
> + to perform the read operation.
> + @retval EFI_INVALID_PARAMETER The read request contains LBAs that
> are not
> + valid, or the buffer is not properly aligned.
> + @retval EFI_NO_MEDIA There is no media in the device.
> + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a
> multiple of
> + the intrinsic block size of the device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciBlockIoReadBlocks (
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
> + IN UINTN DeviceIndex,
> + IN EFI_PEI_LBA StartLBA,
> + IN UINTN BufferSize,
> + OUT VOID *Buffer
> + );
> +
> +/**
> + Gets the count of block I/O devices that one specific block driver detects.
> +
> + This function is used for getting the count of block I/O devices that one
> + specific block driver detects. If no device is detected, then the function
> + will return zero.
> +
> + @param[in] PeiServices General-purpose services that are available
> + to every PEIM.
> + @param[in] This Indicates the
> EFI_PEI_RECOVERY_BLOCK_IO2_PPI
> + instance.
> + @param[out] NumberBlockDevices The number of block I/O devices
> discovered.
> +
> + @retval EFI_SUCCESS The operation performed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciBlockIoGetDeviceNo2 (
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
> + OUT UINTN *NumberBlockDevices
> + );
> +
> +/**
> + Gets a block device's media information.
> +
> + This function will provide the caller with the specified block device's media
> + information. If the media changes, calling this function will update the
> media
> + information accordingly.
> +
> + @param[in] PeiServices General-purpose services that are available to
> every
> + PEIM
> + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
> instance.
> + @param[in] DeviceIndex Specifies the block device to which the function
> wants
> + to talk. Because the driver that implements Block I/O
> + PPIs will manage multiple block devices, the PPIs that
> + want to talk to a single device must specify the
> + device index that was assigned during the enumeration
> + process. This index is a number from one to
> + NumberBlockDevices.
> + @param[out] MediaInfo The media information of the specified block
> media.
> + The caller is responsible for the ownership of this
> + data structure.
> +
> + @par Note:
> + The MediaInfo structure describes an enumeration of possible block
> device
> + types. This enumeration exists because no device paths are actually
> passed
> + across interfaces that describe the type or class of hardware that is
> publishing
> + the block I/O interface. This enumeration will allow for policy decisions
> + in the Recovery PEIM, such as "Try to recover from legacy floppy first,
> + LS-120 second, CD-ROM third." If there are multiple partitions
> abstracted
> + by a given device type, they should be reported in ascending order; this
> + order also applies to nested partitions, such as legacy MBR, where the
> + outermost partitions would have precedence in the reporting order.
> The
> + same logic applies to systems such as IDE that have precedence
> relationships
> + like "Master/Slave" or "Primary/Secondary". The master device should
> be
> + reported first, the slave second.
> +
> + @retval EFI_SUCCESS Media information about the specified block
> device
> + was obtained successfully.
> + @retval EFI_DEVICE_ERROR Cannot get the media information due to a
> hardware
> + error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciBlockIoGetMediaInfo2 (
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
> + IN UINTN DeviceIndex,
> + OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
> + );
> +
> +/**
> + Reads the requested number of blocks from the specified block device.
> +
> + The function reads the requested number of blocks from the device. All
> the
> + blocks are read, or an error is returned. If there is no media in the device,
> + the function returns EFI_NO_MEDIA.
> +
> + @param[in] PeiServices General-purpose services that are available to
> + every PEIM.
> + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
> instance.
> + @param[in] DeviceIndex Specifies the block device to which the function
> wants
> + to talk. Because the driver that implements Block I/O
> + PPIs will manage multiple block devices, PPIs that
> + want to talk to a single device must specify the device
> + index that was assigned during the enumeration process.
> + This index is a number from one to NumberBlockDevices.
> + @param[in] StartLBA The starting logical block address (LBA) to read
> from
> + on the device
> + @param[in] BufferSize The size of the Buffer in bytes. This number must
> be
> + a multiple of the intrinsic block size of the device.
> + @param[out] Buffer A pointer to the destination buffer for the data.
> + The caller is responsible for the ownership of the
> + buffer.
> +
> + @retval EFI_SUCCESS The data was read correctly from the device.
> + @retval EFI_DEVICE_ERROR The device reported an error while
> attempting
> + to perform the read operation.
> + @retval EFI_INVALID_PARAMETER The read request contains LBAs that
> are not
> + valid, or the buffer is not properly aligned.
> + @retval EFI_NO_MEDIA There is no media in the device.
> + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a
> multiple of
> + the intrinsic block size of the device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciBlockIoReadBlocks2 (
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
> + IN UINTN DeviceIndex,
> + IN EFI_PEI_LBA StartLBA,
> + IN UINTN BufferSize,
> + OUT VOID *Buffer
> + );
> +
> +#endif
> diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
> b/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
> index 11754b3057..7287f8290e 100644
> --- a/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
> +++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
> @@ -1873,6 +1873,124 @@ AhciModeInitialization (
> }
>
> /**
> + Transfer data from ATA device.
> +
> + This function performs one ATA pass through transaction to transfer data
> from/to
> + ATA device. It chooses the appropriate ATA command and protocol to
> invoke PassThru
> + interface of ATA pass through.
> +
> + @param[in] DeviceData A pointer to PEI_AHCI_ATA_DEVICE_DATA
> structure.
> + @param[in,out] Buffer The pointer to the current transaction buffer.
> + @param[in] StartLba The starting logical block address to be
> accessed.
> + @param[in] TransferLength The block number or sector count of the
> transfer.
> + @param[in] IsWrite Indicates whether it is a write operation.
> +
> + @retval EFI_SUCCESS The data transfer is complete successfully.
> + @return others Some error occurs when transferring data.
> +
> +**/
> +EFI_STATUS
> +TransferAtaDevice (
> + IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
> + IN OUT VOID *Buffer,
> + IN EFI_LBA StartLba,
> + IN UINT32 TransferLength,
> + IN BOOLEAN IsWrite
> + )
> +{
> + PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
> + EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThru;
> + EFI_ATA_COMMAND_BLOCK Acb;
> + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
> +
> + Private = DeviceData->Private;
> + AtaPassThru = &Private->AtaPassThruPpi;
> +
> + //
> + // Ensure Lba48Bit and IsWrite are valid boolean values
> + //
> + ASSERT ((UINTN) DeviceData->Lba48Bit < 2);
> + ASSERT ((UINTN) IsWrite < 2);
> + if (((UINTN) DeviceData->Lba48Bit >= 2) ||
> + ((UINTN) IsWrite >= 2)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Prepare for ATA command block.
> + //
> + ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
> + Acb.AtaCommand = mAtaCommands[DeviceData->Lba48Bit][IsWrite];
> + Acb.AtaSectorNumber = (UINT8) StartLba;
> + Acb.AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8);
> + Acb.AtaCylinderHigh = (UINT8) RShiftU64 (StartLba, 16);
> + Acb.AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 |
> + (DeviceData->PortMultiplier == 0xFFFF ?
> + 0 : (DeviceData->PortMultiplier << 4)));
> + Acb.AtaSectorCount = (UINT8) TransferLength;
> + if (DeviceData->Lba48Bit) {
> + Acb.AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24);
> + Acb.AtaCylinderLowExp = (UINT8) RShiftU64 (StartLba, 32);
> + Acb.AtaCylinderHighExp = (UINT8) RShiftU64 (StartLba, 40);
> + Acb.AtaSectorCountExp = (UINT8) (TransferLength >> 8);
> + } else {
> + Acb.AtaDeviceHead = (UINT8) (Acb.AtaDeviceHead | RShiftU64
> (StartLba, 24));
> + }
> +
> + //
> + // Prepare for ATA pass through packet.
> + //
> + ZeroMem (&Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
> + if (IsWrite) {
> + Packet.OutDataBuffer = Buffer;
> + Packet.OutTransferLength = TransferLength;
> + } else {
> + Packet.InDataBuffer = Buffer;
> + Packet.InTransferLength = TransferLength;
> + }
> + Packet.Asb = NULL;
> + Packet.Acb = &Acb;
> + Packet.Protocol = mAtaPassThruCmdProtocols[IsWrite];
> + Packet.Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;
> + //
> + // |------------------------|-----------------|
> + // | ATA PIO Transfer Mode | Transfer Rate |
> + // |------------------------|-----------------|
> + // | PIO Mode 0 | 3.3Mbytes/sec |
> + // |------------------------|-----------------|
> + // | PIO Mode 1 | 5.2Mbytes/sec |
> + // |------------------------|-----------------|
> + // | PIO Mode 2 | 8.3Mbytes/sec |
> + // |------------------------|-----------------|
> + // | PIO Mode 3 | 11.1Mbytes/sec |
> + // |------------------------|-----------------|
> + // | PIO Mode 4 | 16.6Mbytes/sec |
> + // |------------------------|-----------------|
> + //
> + // As AtaBus is used to manage ATA devices, we have to use the lowest
> transfer
> + // rate to calculate the possible maximum timeout value for each
> read/write
> + // operation. The timout value is rounded up to nearest integar and here
> an
> + // additional 30s is added to follow ATA spec in which it mentioned that
> the
> + // device may take up to 30s to respond commands in the Standby/Idle
> mode.
> + //
> + // Calculate the maximum timeout value for PIO read/write operation.
> + //
> + Packet.Timeout = TIMER_PERIOD_SECONDS (
> + DivU64x32 (
> + MultU64x32 (TransferLength, DeviceData->Media.BlockSize),
> + 3300000
> + ) + 31
> + );
> +
> + return AtaPassThru->PassThru (
> + AtaPassThru,
> + DeviceData->Port,
> + DeviceData->PortMultiplier,
> + &Packet
> + );
> +}
> +
> +/**
> Trust transfer data from/to ATA device.
>
> This function performs one ATA pass through transaction to do a trust
> transfer
> diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
> b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
> index 29e0aa7d65..31b072c118 100644
> --- a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
> +++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
> @@ -16,6 +16,18 @@ EFI_PEI_PPI_DESCRIPTOR
> mAhciAtaPassThruPpiListTemplate = {
> NULL
> };
>
> +EFI_PEI_PPI_DESCRIPTOR mAhciBlkIoPpiListTemplate = {
> + (EFI_PEI_PPI_DESCRIPTOR_PPI |
> EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> + &gEfiPeiVirtualBlockIoPpiGuid,
> + NULL
> +};
> +
> +EFI_PEI_PPI_DESCRIPTOR mAhciBlkIo2PpiListTemplate = {
> + (EFI_PEI_PPI_DESCRIPTOR_PPI |
> EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> + &gEfiPeiVirtualBlockIo2PpiGuid,
> + NULL
> +};
> +
> EFI_PEI_PPI_DESCRIPTOR mAhciStorageSecurityPpiListTemplate = {
> (EFI_PEI_PPI_DESCRIPTOR_PPI |
> EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> &gEdkiiPeiStorageSecurityCommandPpiGuid,
> @@ -265,6 +277,29 @@ AtaAhciPeimEntry (
> Private->AtaPassThruPpiList.Ppi = &Private->AtaPassThruPpi;
> PeiServicesInstallPpi (&Private->AtaPassThruPpiList);
>
> + Private->BlkIoPpi.GetNumberOfBlockDevices = AhciBlockIoGetDeviceNo;
> + Private->BlkIoPpi.GetBlockDeviceMediaInfo = AhciBlockIoGetMediaInfo;
> + Private->BlkIoPpi.ReadBlocks = AhciBlockIoReadBlocks;
> + CopyMem (
> + &Private->BlkIoPpiList,
> + &mAhciBlkIoPpiListTemplate,
> + sizeof (EFI_PEI_PPI_DESCRIPTOR)
> + );
> + Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;
> + PeiServicesInstallPpi (&Private->BlkIoPpiList);
> +
> + Private->BlkIo2Ppi.Revision =
> EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;
> + Private->BlkIo2Ppi.GetNumberOfBlockDevices =
> AhciBlockIoGetDeviceNo2;
> + Private->BlkIo2Ppi.GetBlockDeviceMediaInfo =
> AhciBlockIoGetMediaInfo2;
> + Private->BlkIo2Ppi.ReadBlocks = AhciBlockIoReadBlocks2;
> + CopyMem (
> + &Private->BlkIo2PpiList,
> + &mAhciBlkIo2PpiListTemplate,
> + sizeof (EFI_PEI_PPI_DESCRIPTOR)
> + );
> + Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;
> + PeiServicesInstallPpi (&Private->BlkIo2PpiList);
> +
> if (Private->TrustComputingDevices != 0) {
> DEBUG ((
> DEBUG_INFO,
> diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c
> b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c
> new file mode 100644
> index 0000000000..e7c7a39539
> --- /dev/null
> +++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c
> @@ -0,0 +1,516 @@
> +/** @file
> + The AhciPei driver is used to manage ATA hard disk device working under
> AHCI
> + mode at PEI phase.
> +
> + Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "AhciPei.h"
> +
> +/**
> + Traverse the attached ATA devices list to find out the device with given
> index.
> +
> + @param[in] Private A pointer to the
> PEI_AHCI_CONTROLLER_PRIVATE_DATA
> + instance.
> + @param[in] DeviceIndex The device index.
> +
> + @retval The pointer to the PEI_AHCI_ATA_DEVICE_DATA structure of
> the device
> + info to access.
> +
> +**/
> +PEI_AHCI_ATA_DEVICE_DATA *
> +SearchDeviceByIndex (
> + IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
> + IN UINTN DeviceIndex
> + )
> +{
> + PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
> + LIST_ENTRY *Node;
> +
> + if ((DeviceIndex == 0) || (DeviceIndex > Private->ActiveDevices)) {
> + return NULL;
> + }
> +
> + Node = GetFirstNode (&Private->DeviceList);
> + while (!IsNull (&Private->DeviceList, Node)) {
> + DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
> +
> + if (DeviceData->DeviceIndex == DeviceIndex) {
> + return DeviceData;
> + }
> +
> + Node = GetNextNode (&Private->DeviceList, Node);
> + }
> +
> + return NULL;
> +}
> +
> +/**
> + Read a number of blocks from ATA device.
> +
> + This function performs ATA pass through transactions to read data from
> ATA device.
> + It may separate the read request into several ATA pass through
> transactions.
> +
> + @param[in] DeviceData The pointer to the
> PEI_AHCI_ATA_DEVICE_DATA
> + data structure.
> + @param[in,out] Buffer The pointer to the current transaction buffer.
> + @param[in] StartLba The starting logical block address to be
> accessed.
> + @param[in] NumberOfBlocks The block number or sector count of the
> transfer.
> +
> + @retval EFI_SUCCESS The data transfer is complete successfully.
> + @return Others Some error occurs when transferring data.
> +
> +**/
> +EFI_STATUS
> +AccessAtaDevice (
> + IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
> + IN OUT UINT8 *Buffer,
> + IN EFI_LBA StartLba,
> + IN UINTN NumberOfBlocks
> + )
> +{
> + EFI_STATUS Status;
> + UINTN MaxTransferBlockNumber;
> + UINTN TransferBlockNumber;
> + UINTN BlockSize;
> +
> + //
> + // Ensure Lba48Bit is a valid boolean value
> + //
> + ASSERT ((UINTN) DeviceData->Lba48Bit < 2);
> + if ((UINTN) DeviceData->Lba48Bit >= 2) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Status = EFI_SUCCESS;
> + MaxTransferBlockNumber = mMaxTransferBlockNumber[DeviceData-
> >Lba48Bit];
> + BlockSize = DeviceData->Media.BlockSize;
> +
> + do {
> + if (NumberOfBlocks > MaxTransferBlockNumber) {
> + TransferBlockNumber = MaxTransferBlockNumber;
> + NumberOfBlocks -= MaxTransferBlockNumber;
> + } else {
> + TransferBlockNumber = NumberOfBlocks;
> + NumberOfBlocks = 0;
> + }
> + DEBUG ((
> + DEBUG_BLKIO, "%a: Blocking AccessAtaDevice, TransferBlockNumber
> = %x; StartLba = %x\n",
> + __FUNCTION__, TransferBlockNumber, StartLba
> + ));
> +
> + Status = TransferAtaDevice (
> + DeviceData,
> + Buffer,
> + StartLba,
> + (UINT32) TransferBlockNumber,
> + FALSE // Read
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + StartLba += TransferBlockNumber;
> + Buffer += TransferBlockNumber * BlockSize;
> + } while (NumberOfBlocks > 0);
> +
> + return Status;
> +}
> +
> +/**
> + Read specified bytes from Lba from the device.
> +
> + @param[in] DeviceData The pointer to the
> PEI_AHCI_ATA_DEVICE_DATA data structure.
> + @param[out] Buffer The Buffer used to store the Data read from the
> device.
> + @param[in] StartLba The start block number.
> + @param[in] BufferSize Total bytes to be read.
> +
> + @retval EFI_SUCCESS Data are read from the device.
> + @retval Others Fail to read all the data.
> +
> +**/
> +EFI_STATUS
> +AhciRead (
> + IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
> + OUT VOID *Buffer,
> + IN EFI_LBA StartLba,
> + IN UINTN BufferSize
> + )
> +{
> + EFI_STATUS Status;
> + UINTN BlockSize;
> + UINTN NumberOfBlocks;
> +
> + //
> + // Check parameters.
> + //
> + if (Buffer == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (BufferSize == 0) {
> + return EFI_SUCCESS;
> + }
> +
> + BlockSize = DeviceData->Media.BlockSize;
> + if ((BufferSize % BlockSize) != 0) {
> + return EFI_BAD_BUFFER_SIZE;
> + }
> +
> + if (StartLba > DeviceData->Media.LastBlock) {
> + return EFI_INVALID_PARAMETER;
> + }
> + NumberOfBlocks = BufferSize / BlockSize;
> + if (NumberOfBlocks - 1 > DeviceData->Media.LastBlock - StartLba) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + //
> + // Invoke low level AtaDevice Access Routine.
> + //
> + Status = AccessAtaDevice (DeviceData, Buffer, StartLba, NumberOfBlocks);
> +
> + return Status;
> +}
> +
> +
> +/**
> + Gets the count of block I/O devices that one specific block driver detects.
> +
> + This function is used for getting the count of block I/O devices that one
> + specific block driver detects. If no device is detected, then the function
> + will return zero.
> +
> + @param[in] PeiServices General-purpose services that are available
> + to every PEIM.
> + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
> + instance.
> + @param[out] NumberBlockDevices The number of block I/O devices
> discovered.
> +
> + @retval EFI_SUCCESS The operation performed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciBlockIoGetDeviceNo (
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
> + OUT UINTN *NumberBlockDevices
> + )
> +{
> + PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
> +
> + if (This == NULL || NumberBlockDevices == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
> + *NumberBlockDevices = Private->ActiveDevices;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Gets a block device's media information.
> +
> + This function will provide the caller with the specified block device's media
> + information. If the media changes, calling this function will update the
> media
> + information accordingly.
> +
> + @param[in] PeiServices General-purpose services that are available to
> every
> + PEIM
> + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
> instance.
> + @param[in] DeviceIndex Specifies the block device to which the function
> wants
> + to talk. Because the driver that implements Block I/O
> + PPIs will manage multiple block devices, the PPIs that
> + want to talk to a single device must specify the
> + device index that was assigned during the enumeration
> + process. This index is a number from one to
> + NumberBlockDevices.
> + @param[out] MediaInfo The media information of the specified block
> media.
> + The caller is responsible for the ownership of this
> + data structure.
> +
> + @par Note:
> + The MediaInfo structure describes an enumeration of possible block
> device
> + types. This enumeration exists because no device paths are actually
> passed
> + across interfaces that describe the type or class of hardware that is
> publishing
> + the block I/O interface. This enumeration will allow for policy decisions
> + in the Recovery PEIM, such as "Try to recover from legacy floppy first,
> + LS-120 second, CD-ROM third." If there are multiple partitions
> abstracted
> + by a given device type, they should be reported in ascending order; this
> + order also applies to nested partitions, such as legacy MBR, where the
> + outermost partitions would have precedence in the reporting order.
> The
> + same logic applies to systems such as IDE that have precedence
> relationships
> + like "Master/Slave" or "Primary/Secondary". The master device should
> be
> + reported first, the slave second.
> +
> + @retval EFI_SUCCESS Media information about the specified block
> device
> + was obtained successfully.
> + @retval EFI_DEVICE_ERROR Cannot get the media information due to a
> hardware
> + error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciBlockIoGetMediaInfo (
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
> + IN UINTN DeviceIndex,
> + OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
> + )
> +{
> + PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
> + PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
> +
> + if (This == NULL || MediaInfo == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
> + DeviceData = SearchDeviceByIndex (Private, DeviceIndex);
> + if (DeviceData == NULL) {
> + return EFI_NOT_FOUND;
> + }
> +
> + MediaInfo->DeviceType = (EFI_PEI_BLOCK_DEVICE_TYPE)
> EDKII_PEI_BLOCK_DEVICE_TYPE_ATA_HARD_DISK;
> + MediaInfo->MediaPresent = TRUE;
> + MediaInfo->LastBlock = (UINTN) DeviceData->Media.LastBlock;
> + MediaInfo->BlockSize = DeviceData->Media.BlockSize;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Reads the requested number of blocks from the specified block device.
> +
> + The function reads the requested number of blocks from the device. All
> the
> + blocks are read, or an error is returned. If there is no media in the device,
> + the function returns EFI_NO_MEDIA.
> +
> + @param[in] PeiServices General-purpose services that are available to
> + every PEIM.
> + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
> instance.
> + @param[in] DeviceIndex Specifies the block device to which the function
> wants
> + to talk. Because the driver that implements Block I/O
> + PPIs will manage multiple block devices, PPIs that
> + want to talk to a single device must specify the device
> + index that was assigned during the enumeration process.
> + This index is a number from one to NumberBlockDevices.
> + @param[in] StartLBA The starting logical block address (LBA) to read
> from
> + on the device
> + @param[in] BufferSize The size of the Buffer in bytes. This number must
> be
> + a multiple of the intrinsic block size of the device.
> + @param[out] Buffer A pointer to the destination buffer for the data.
> + The caller is responsible for the ownership of the
> + buffer.
> +
> + @retval EFI_SUCCESS The data was read correctly from the device.
> + @retval EFI_DEVICE_ERROR The device reported an error while
> attempting
> + to perform the read operation.
> + @retval EFI_INVALID_PARAMETER The read request contains LBAs that
> are not
> + valid, or the buffer is not properly aligned.
> + @retval EFI_NO_MEDIA There is no media in the device.
> + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a
> multiple of
> + the intrinsic block size of the device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciBlockIoReadBlocks (
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
> + IN UINTN DeviceIndex,
> + IN EFI_PEI_LBA StartLBA,
> + IN UINTN BufferSize,
> + OUT VOID *Buffer
> + )
> +{
> + PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
> + PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
> +
> + if (This == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
> + DeviceData = SearchDeviceByIndex (Private, DeviceIndex);
> + if (DeviceData == NULL) {
> + return EFI_NOT_FOUND;
> + }
> +
> + return AhciRead (DeviceData, Buffer, StartLBA, BufferSize);
> +}
> +
> +/**
> + Gets the count of block I/O devices that one specific block driver detects.
> +
> + This function is used for getting the count of block I/O devices that one
> + specific block driver detects. If no device is detected, then the function
> + will return zero.
> +
> + @param[in] PeiServices General-purpose services that are available
> + to every PEIM.
> + @param[in] This Indicates the
> EFI_PEI_RECOVERY_BLOCK_IO2_PPI
> + instance.
> + @param[out] NumberBlockDevices The number of block I/O devices
> discovered.
> +
> + @retval EFI_SUCCESS The operation performed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciBlockIoGetDeviceNo2 (
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
> + OUT UINTN *NumberBlockDevices
> + )
> +{
> + PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
> +
> + if (This == NULL || NumberBlockDevices == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
> + *NumberBlockDevices = Private->ActiveDevices;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Gets a block device's media information.
> +
> + This function will provide the caller with the specified block device's media
> + information. If the media changes, calling this function will update the
> media
> + information accordingly.
> +
> + @param[in] PeiServices General-purpose services that are available to
> every
> + PEIM
> + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
> instance.
> + @param[in] DeviceIndex Specifies the block device to which the function
> wants
> + to talk. Because the driver that implements Block I/O
> + PPIs will manage multiple block devices, the PPIs that
> + want to talk to a single device must specify the
> + device index that was assigned during the enumeration
> + process. This index is a number from one to
> + NumberBlockDevices.
> + @param[out] MediaInfo The media information of the specified block
> media.
> + The caller is responsible for the ownership of this
> + data structure.
> +
> + @par Note:
> + The MediaInfo structure describes an enumeration of possible block
> device
> + types. This enumeration exists because no device paths are actually
> passed
> + across interfaces that describe the type or class of hardware that is
> publishing
> + the block I/O interface. This enumeration will allow for policy decisions
> + in the Recovery PEIM, such as "Try to recover from legacy floppy first,
> + LS-120 second, CD-ROM third." If there are multiple partitions
> abstracted
> + by a given device type, they should be reported in ascending order; this
> + order also applies to nested partitions, such as legacy MBR, where the
> + outermost partitions would have precedence in the reporting order.
> The
> + same logic applies to systems such as IDE that have precedence
> relationships
> + like "Master/Slave" or "Primary/Secondary". The master device should
> be
> + reported first, the slave second.
> +
> + @retval EFI_SUCCESS Media information about the specified block
> device
> + was obtained successfully.
> + @retval EFI_DEVICE_ERROR Cannot get the media information due to a
> hardware
> + error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciBlockIoGetMediaInfo2 (
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
> + IN UINTN DeviceIndex,
> + OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
> + )
> +{
> + PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
> + PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
> +
> + if (This == NULL || MediaInfo == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2
> (This);
> + DeviceData = SearchDeviceByIndex (Private, DeviceIndex);
> + if (DeviceData == NULL) {
> + return EFI_NOT_FOUND;
> + }
> +
> + CopyMem (
> + MediaInfo,
> + &DeviceData->Media,
> + sizeof (EFI_PEI_BLOCK_IO2_MEDIA)
> + );
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Reads the requested number of blocks from the specified block device.
> +
> + The function reads the requested number of blocks from the device. All
> the
> + blocks are read, or an error is returned. If there is no media in the device,
> + the function returns EFI_NO_MEDIA.
> +
> + @param[in] PeiServices General-purpose services that are available to
> + every PEIM.
> + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
> instance.
> + @param[in] DeviceIndex Specifies the block device to which the function
> wants
> + to talk. Because the driver that implements Block I/O
> + PPIs will manage multiple block devices, PPIs that
> + want to talk to a single device must specify the device
> + index that was assigned during the enumeration process.
> + This index is a number from one to NumberBlockDevices.
> + @param[in] StartLBA The starting logical block address (LBA) to read
> from
> + on the device
> + @param[in] BufferSize The size of the Buffer in bytes. This number must
> be
> + a multiple of the intrinsic block size of the device.
> + @param[out] Buffer A pointer to the destination buffer for the data.
> + The caller is responsible for the ownership of the
> + buffer.
> +
> + @retval EFI_SUCCESS The data was read correctly from the device.
> + @retval EFI_DEVICE_ERROR The device reported an error while
> attempting
> + to perform the read operation.
> + @retval EFI_INVALID_PARAMETER The read request contains LBAs that
> are not
> + valid, or the buffer is not properly aligned.
> + @retval EFI_NO_MEDIA There is no media in the device.
> + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a
> multiple of
> + the intrinsic block size of the device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +AhciBlockIoReadBlocks2 (
> + IN EFI_PEI_SERVICES **PeiServices,
> + IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
> + IN UINTN DeviceIndex,
> + IN EFI_PEI_LBA StartLBA,
> + IN UINTN BufferSize,
> + OUT VOID *Buffer
> + )
> +{
> + PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
> +
> + if (This == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
> + return AhciBlockIoReadBlocks (
> + PeiServices,
> + &Private->BlkIoPpi,
> + DeviceIndex,
> + StartLBA,
> + BufferSize,
> + Buffer
> + );
> +}
> --
> 2.12.0.windows.1
>
>
>
prev parent reply other threads:[~2019-04-23 18:15 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-23 8:06 [PATCH v3 0/2] Add PEI BlockIO support for ATA AHCI mode devices Wu, Hao A
2019-04-23 8:06 ` [PATCH v3 1/2] MdeModulePkg/AhciPei: Limit max transfer blocknum for 48-bit address Wu, Hao A
2019-04-23 18:12 ` [edk2-devel] " Ni, Ray
2019-04-23 8:06 ` [PATCH v3 2/2] MdeModulePkg/AhciPei: Add PEI BlockIO support Wu, Hao A
2019-04-23 18:14 ` Ni, Ray [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=734D49CCEBEEF84792F5B80ED585239D5C0FEB4D@SHSMSX104.ccr.corp.intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox