Add BlockIO2 Protocol.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11606 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
@@ -40,16 +40,15 @@ PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Test to see if this driver supports ControllerHandle. Any ControllerHandle
|
||||
than contains a BlockIo and DiskIo protocol can be supported.
|
||||
than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
|
||||
supported.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
@param ControllerHandle Handle of device to test
|
||||
@param RemainingDevicePath Optional parameter use to pick a specific child
|
||||
device to start.
|
||||
@param[in] This Protocol instance pointer.
|
||||
@param[in] ControllerHandle Handle of device to test.
|
||||
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
|
||||
device to start.
|
||||
|
||||
@retval EFI_SUCCESS This driver supports this device
|
||||
@retval EFI_ALREADY_STARTED This driver is already running on this device
|
||||
@@ -86,7 +85,7 @@ PartitionDriverBindingSupported (
|
||||
if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||
|
||||
Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||
|
||||
DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) {
|
||||
return EFI_UNSUPPORTED;
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,7 +104,6 @@ PartitionDriverBindingSupported (
|
||||
if (Status == EFI_ALREADY_STARTED) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
@@ -159,20 +157,39 @@ PartitionDriverBindingSupported (
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
||||
);
|
||||
|
||||
return Status;
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIo2ProtocolGuid,
|
||||
NULL,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// According to UEFI Spec 2.3.1, if a driver is written for a disk device,
|
||||
// then the EFI_BLOCK_IO_PROTOCOL and EFI_BLOCK_IO2_PROTOCOAL must be implemented.
|
||||
// Currently, SCSI disk driver only produce the EFI_BLOCK_IO_PROTOCOL, it will
|
||||
// not be updated until the non blocking SCSI Pass Thru Protocol is provided.
|
||||
// If there is no EFI_BLOCK_IO2_PROTOCOL, skip here.
|
||||
//
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Start this driver on ControllerHandle by opening a Block IO and Disk IO
|
||||
protocol, reading Device Path, and creating a child handle with a
|
||||
Disk IO and device path protocol.
|
||||
Start this driver on ControllerHandle by opening a Block IO or a Block IO2
|
||||
or both, and Disk IO protocol, reading Device Path, and creating a child
|
||||
handle with a Disk IO and device path protocol.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
@param ControllerHandle Handle of device to bind driver to
|
||||
@param RemainingDevicePath Optional parameter use to pick a specific child
|
||||
device to start.
|
||||
@param[in] This Protocol instance pointer.
|
||||
@param[in] ControllerHandle Handle of device to bind driver to
|
||||
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
|
||||
device to start.
|
||||
|
||||
@retval EFI_SUCCESS This driver is added to ControllerHandle
|
||||
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
|
||||
@@ -190,6 +207,7 @@ PartitionDriverBindingStart (
|
||||
EFI_STATUS Status;
|
||||
EFI_STATUS OpenStatus;
|
||||
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
||||
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
|
||||
EFI_DISK_IO_PROTOCOL *DiskIo;
|
||||
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
|
||||
PARTITION_DETECT_ROUTINE *Routine;
|
||||
@@ -211,6 +229,10 @@ PartitionDriverBindingStart (
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
|
||||
// otherwise, return error.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
@@ -222,8 +244,27 @@ PartitionDriverBindingStart (
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIo2ProtocolGuid,
|
||||
(VOID **) &BlockIo2,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
//
|
||||
// According to UEFI Spec 2.3.1, if a driver is written for a disk device,
|
||||
// then the EFI_BLOCK_IO_PROTOCOL and EFI_BLOCK_IO2_PROTOCOAL must be implemented.
|
||||
// Currently, SCSI disk driver only produce the EFI_BLOCK_IO_PROTOCOL, it will
|
||||
// not be updated until the non blocking SCSI Pass Thru Protocol is provided.
|
||||
// If there is no EFI_BLOCK_IO2_PROTOCOL, skip here.
|
||||
//
|
||||
}
|
||||
|
||||
//
|
||||
// Get the Device Path Protocol on ControllerHandle's handle
|
||||
// Get the Device Path Protocol on ControllerHandle's handle.
|
||||
//
|
||||
Status = gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
@@ -276,6 +317,7 @@ PartitionDriverBindingStart (
|
||||
ControllerHandle,
|
||||
DiskIo,
|
||||
BlockIo,
|
||||
BlockIo2,
|
||||
ParentDevicePath
|
||||
);
|
||||
if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {
|
||||
@@ -306,6 +348,15 @@ PartitionDriverBindingStart (
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
//
|
||||
// Close Parent BlockIO2 if has.
|
||||
//
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIo2ProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
@@ -320,7 +371,6 @@ Exit:
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Stop this driver on ControllerHandle. Support stopping any child handles
|
||||
created by this driver.
|
||||
@@ -347,10 +397,15 @@ PartitionDriverBindingStop (
|
||||
EFI_STATUS Status;
|
||||
UINTN Index;
|
||||
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
||||
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
|
||||
BOOLEAN AllChildrenStopped;
|
||||
PARTITION_PRIVATE_DATA *Private;
|
||||
EFI_DISK_IO_PROTOCOL *DiskIo;
|
||||
|
||||
BlockIo = NULL;
|
||||
BlockIo2 = NULL;
|
||||
Private = NULL;
|
||||
|
||||
if (NumberOfChildren == 0) {
|
||||
//
|
||||
// Close the bus driver
|
||||
@@ -361,6 +416,15 @@ PartitionDriverBindingStop (
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
//
|
||||
// Close Parent BlockIO2 if has.
|
||||
//
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiBlockIo2ProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
|
||||
gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
@@ -368,60 +432,91 @@ PartitionDriverBindingStop (
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle
|
||||
);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
AllChildrenStopped = TRUE;
|
||||
for (Index = 0; Index < NumberOfChildren; Index++) {
|
||||
Status = gBS->OpenProtocol (
|
||||
ChildHandleBuffer[Index],
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
(VOID **) &BlockIo,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
gBS->OpenProtocol (
|
||||
ChildHandleBuffer[Index],
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
(VOID **) &BlockIo,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
//
|
||||
// Try to locate BlockIo2.
|
||||
//
|
||||
gBS->OpenProtocol (
|
||||
ChildHandleBuffer[Index],
|
||||
&gEfiBlockIo2ProtocolGuid,
|
||||
(VOID **) &BlockIo2,
|
||||
This->DriverBindingHandle,
|
||||
ControllerHandle,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
|
||||
if (BlockIo != NULL) {
|
||||
Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
|
||||
} else if (BlockIo2 != NULL) {
|
||||
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (BlockIo2);
|
||||
} else {
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
|
||||
//
|
||||
// All Software protocols have be freed from the handle so remove it.
|
||||
//
|
||||
Status = gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
ChildHandleBuffer[Index]
|
||||
);
|
||||
//
|
||||
// All Software protocols have be freed from the handle so remove it.
|
||||
// Remove the BlockIo Protocol if has.
|
||||
// Remove the BlockIo2 Protocol if has.
|
||||
//
|
||||
if (BlockIo2 != NULL) {
|
||||
BlockIo->FlushBlocks (BlockIo);
|
||||
|
||||
Status = gBS->CloseProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
This->DriverBindingHandle,
|
||||
ChildHandleBuffer[Index]
|
||||
);
|
||||
|
||||
BlockIo2->FlushBlocksEx (BlockIo2, NULL);
|
||||
Status = gBS->UninstallMultipleProtocolInterfaces (
|
||||
ChildHandleBuffer[Index],
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
Private->DevicePath,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
&Private->BlockIo,
|
||||
Private->EspGuid,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
(VOID **) &DiskIo,
|
||||
This->DriverBindingHandle,
|
||||
ChildHandleBuffer[Index],
|
||||
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
||||
);
|
||||
} else {
|
||||
FreePool (Private->DevicePath);
|
||||
FreePool (Private);
|
||||
}
|
||||
ChildHandleBuffer[Index],
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
Private->DevicePath,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
&Private->BlockIo,
|
||||
&gEfiBlockIo2ProtocolGuid,
|
||||
&Private->BlockIo2,
|
||||
Private->EspGuid,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
} else {
|
||||
BlockIo->FlushBlocks (BlockIo);
|
||||
Status = gBS->UninstallMultipleProtocolInterfaces (
|
||||
ChildHandleBuffer[Index],
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
Private->DevicePath,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
&Private->BlockIo,
|
||||
Private->EspGuid,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->OpenProtocol (
|
||||
ControllerHandle,
|
||||
&gEfiDiskIoProtocolGuid,
|
||||
(VOID **) &DiskIo,
|
||||
This->DriverBindingHandle,
|
||||
ChildHandleBuffer[Index],
|
||||
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
||||
);
|
||||
} else {
|
||||
FreePool (Private->DevicePath);
|
||||
FreePool (Private);
|
||||
}
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
@@ -551,11 +646,11 @@ PartitionReadBlocks (
|
||||
Write by using the Disk IO protocol on the parent device. Lba addresses
|
||||
must be converted to byte offsets.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
@param MediaId Id of the media, changes every time the media is replaced.
|
||||
@param Lba The starting Logical Block Address to read from
|
||||
@param BufferSize Size of Buffer, must be a multiple of device block size.
|
||||
@param Buffer Buffer containing read data
|
||||
@param[in] This Protocol instance pointer.
|
||||
@param[in] MediaId Id of the media, changes every time the media is replaced.
|
||||
@param[in] Lba The starting Logical Block Address to read from
|
||||
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
|
||||
@param[in] Buffer Buffer containing data to be written to device.
|
||||
|
||||
@retval EFI_SUCCESS The data was written correctly to the device.
|
||||
@retval EFI_WRITE_PROTECTED The device can not be written to.
|
||||
@@ -574,7 +669,7 @@ PartitionWriteBlocks (
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
OUT VOID *Buffer
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
PARTITION_PRIVATE_DATA *Private;
|
||||
@@ -622,25 +717,261 @@ PartitionFlushBlocks (
|
||||
return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
|
||||
}
|
||||
|
||||
/**
|
||||
Reset the Block Device throught Block I/O2 protocol.
|
||||
|
||||
@param This Protocol instance pointer.
|
||||
@param ExtendedVerification Driver may perform diagnostics on reset.
|
||||
|
||||
@retval EFI_SUCCESS The device was reset.
|
||||
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
|
||||
not be reset.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
PartitionResetEx (
|
||||
IN EFI_BLOCK_IO2_PROTOCOL *This,
|
||||
IN BOOLEAN ExtendedVerification
|
||||
)
|
||||
{
|
||||
PARTITION_PRIVATE_DATA *Private;
|
||||
|
||||
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
|
||||
|
||||
return Private->ParentBlockIo2->Reset (
|
||||
Private->ParentBlockIo2,
|
||||
ExtendedVerification
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Read BufferSize bytes from Lba into Buffer.
|
||||
|
||||
This function reads the requested number of blocks from the device. All the
|
||||
blocks are read, or an error is returned.
|
||||
If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
|
||||
non-blocking I/O is being used, the Event associated with this request will
|
||||
not be signaled.
|
||||
|
||||
@param[in] This Indicates a pointer to the calling context.
|
||||
@param[in] MediaId Id of the media, changes every time the media is
|
||||
replaced.
|
||||
@param[in] Lba The starting Logical Block Address to read from.
|
||||
@param[in, out] Token A pointer to the token associated with the transaction.
|
||||
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
|
||||
@param[out] Buffer A pointer to the destination buffer for the data. The
|
||||
caller is responsible for either having implicit or
|
||||
explicit ownership of the buffer.
|
||||
|
||||
@retval EFI_SUCCESS The read request was queued if Token->Event is
|
||||
not NULL.The data was read correctly from the
|
||||
device if the Token->Event is NULL.
|
||||
@retval EFI_DEVICE_ERROR The device reported an error while performing
|
||||
the read.
|
||||
@retval EFI_NO_MEDIA There is no media in the device.
|
||||
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
|
||||
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
|
||||
intrinsic block size of the device.
|
||||
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
|
||||
or the buffer is not on proper alignment.
|
||||
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
|
||||
of resources.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
PartitionReadBlocksEx (
|
||||
IN EFI_BLOCK_IO2_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
|
||||
IN UINTN BufferSize,
|
||||
OUT VOID *Buffer
|
||||
)
|
||||
{
|
||||
PARTITION_PRIVATE_DATA *Private;
|
||||
UINT64 Offset;
|
||||
UINT32 UnderRun;
|
||||
|
||||
if (Token == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
|
||||
if (BufferSize % Private->BlockSize != 0) {
|
||||
return EFI_BAD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
|
||||
if (Offset + BufferSize > Private->End) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
|
||||
// be multiple of BlockSize. If the Spec will be updated the DiskIO to support
|
||||
// BlockIO2, this limitation will be removed and call DiskIO here.
|
||||
//
|
||||
Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
|
||||
if (UnderRun != 0) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// Because some partitions have different block size from their parent
|
||||
// device, in that case the Block I/O2 couldn't be called.
|
||||
//
|
||||
if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return Private->ParentBlockIo2->ReadBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
Write BufferSize bytes from Lba into Buffer.
|
||||
|
||||
This function writes the requested number of blocks to the device. All blocks
|
||||
are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
|
||||
EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
|
||||
being used, the Event associated with this request will not be signaled.
|
||||
|
||||
@param[in] This Indicates a pointer to the calling context.
|
||||
@param[in] MediaId The media ID that the write request is for.
|
||||
@param[in] Lba The starting logical block address to be written. The
|
||||
caller is responsible for writing to only legitimate
|
||||
locations.
|
||||
@param[in, out] Token A pointer to the token associated with the transaction.
|
||||
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
|
||||
@param[in] Buffer A pointer to the source buffer for the data.
|
||||
|
||||
@retval EFI_SUCCESS The write request was queued if Event is not NULL.
|
||||
The data was written correctly to the device if
|
||||
the Event is NULL.
|
||||
@retval EFI_WRITE_PROTECTED The device can not be written to.
|
||||
@retval EFI_NO_MEDIA There is no media in the device.
|
||||
@retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
|
||||
@retval EFI_DEVICE_ERROR The device reported an error while performing the write.
|
||||
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
|
||||
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
|
||||
or the buffer is not on proper alignment.
|
||||
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
|
||||
of resources.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
PartitionWriteBlocksEx (
|
||||
IN EFI_BLOCK_IO2_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
|
||||
IN UINTN BufferSize,
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
PARTITION_PRIVATE_DATA *Private;
|
||||
UINT64 Offset;
|
||||
UINT32 UnderRun;
|
||||
|
||||
if (Token == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
|
||||
if (BufferSize % Private->BlockSize != 0) {
|
||||
return EFI_BAD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
|
||||
if (Offset + BufferSize > Private->End) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must
|
||||
// be multiple of BlockSize. If the Spec will be updated the DiskIO to support
|
||||
// BlockIO2, this limitation will be removed and call DiskIO here.
|
||||
//
|
||||
Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun);
|
||||
if (UnderRun != 0) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// Because some kinds of partition have different block size from their parent,
|
||||
// in that case it couldn't call parent Block I/O2.
|
||||
//
|
||||
if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return Private->ParentBlockIo2->WriteBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
Flush the Block Device.
|
||||
|
||||
If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
|
||||
is returned and non-blocking I/O is being used, the Event associated with
|
||||
this request will not be signaled.
|
||||
|
||||
@param[in] This Indicates a pointer to the calling context.
|
||||
@param[in,out] Token A pointer to the token associated with the transaction
|
||||
|
||||
@retval EFI_SUCCESS The flush request was queued if Event is not NULL.
|
||||
All outstanding data was written correctly to the
|
||||
device if the Event is NULL.
|
||||
@retval EFI_DEVICE_ERROR The device reported an error while writting back
|
||||
the data.
|
||||
@retval EFI_WRITE_PROTECTED The device cannot be written to.
|
||||
@retval EFI_NO_MEDIA There is no media in the device.
|
||||
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
|
||||
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
|
||||
of resources.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
PartitionFlushBlocksEx (
|
||||
IN EFI_BLOCK_IO2_PROTOCOL *This,
|
||||
IN OUT EFI_BLOCK_IO2_TOKEN *Token
|
||||
)
|
||||
{
|
||||
PARTITION_PRIVATE_DATA *Private;
|
||||
|
||||
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
|
||||
|
||||
//
|
||||
// Because some kinds of partition have different block size from their parent,
|
||||
// in that case it couldn't call parent Block I/O2.
|
||||
//
|
||||
if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return Private->ParentBlockIo2->FlushBlocksEx (Private->ParentBlockIo2, Token);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Create a child handle for a logical block device that represents the
|
||||
bytes Start to End of the Parent Block IO device.
|
||||
|
||||
@param[in] This Protocol instance pointer
|
||||
@param[in] ParentHandle Parent Handle for new child
|
||||
@param[in] ParentDiskIo Parent DiskIo interface
|
||||
@param[in] ParentBlockIo Parent BlockIo interface
|
||||
@param[in] ParentDevicePath Parent Device Path
|
||||
@param[in] DevicePathNode Child Device Path node
|
||||
@param[in] Start Start Block
|
||||
@param[in] End End Block
|
||||
@param[in] BlockSize Child block size
|
||||
@param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle
|
||||
@param[in] This Protocol instance pointer.
|
||||
@param[in] ParentHandle Parent Handle for new child.
|
||||
@param[in] ParentDiskIo Parent DiskIo interface.
|
||||
@param[in] ParentBlockIo Parent BlockIo interface.
|
||||
@param[in] ParentBlockIo2 Parent BlockIo2 interface.
|
||||
@param[in] ParentDevicePath Parent Device Path.
|
||||
@param[in] DevicePathNode Child Device Path node.
|
||||
@param[in] Start Start Block.
|
||||
@param[in] End End Block.
|
||||
@param[in] BlockSize Child block size.
|
||||
@param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle.
|
||||
|
||||
@retval EFI_SUCCESS A child handle was added
|
||||
@retval other A child handle was not added
|
||||
@retval EFI_SUCCESS A child handle was added.
|
||||
@retval other A child handle was not added.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
@@ -649,6 +980,7 @@ PartitionInstallChildHandle (
|
||||
IN EFI_HANDLE ParentHandle,
|
||||
IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
|
||||
IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
|
||||
IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
|
||||
IN EFI_LBA Start,
|
||||
@@ -660,6 +992,7 @@ PartitionInstallChildHandle (
|
||||
EFI_STATUS Status;
|
||||
PARTITION_PRIVATE_DATA *Private;
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
|
||||
if (Private == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
@@ -672,28 +1005,51 @@ PartitionInstallChildHandle (
|
||||
|
||||
Private->BlockSize = BlockSize;
|
||||
Private->ParentBlockIo = ParentBlockIo;
|
||||
Private->ParentBlockIo2 = ParentBlockIo2;
|
||||
Private->DiskIo = ParentDiskIo;
|
||||
|
||||
Private->BlockIo.Revision = ParentBlockIo->Revision;
|
||||
if (Private->ParentBlockIo != NULL) {
|
||||
Private->BlockIo.Revision = ParentBlockIo->Revision;
|
||||
|
||||
Private->BlockIo.Media = &Private->Media;
|
||||
CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
|
||||
Private->Media.LogicalPartition = TRUE;
|
||||
Private->BlockIo.Media = &Private->Media;
|
||||
CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
|
||||
|
||||
|
||||
Private->BlockIo.Reset = PartitionReset;
|
||||
Private->BlockIo.ReadBlocks = PartitionReadBlocks;
|
||||
Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
|
||||
Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
|
||||
}
|
||||
|
||||
if (Private->ParentBlockIo2 != NULL) {
|
||||
Private->BlockIo2.Media = &Private->Media2;
|
||||
CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));
|
||||
|
||||
Private->BlockIo2.Reset = PartitionResetEx;
|
||||
Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;
|
||||
Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;
|
||||
Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
|
||||
}
|
||||
|
||||
//
|
||||
// Logical BlockIo instance doesn't have IoAlign restriction because it implements block io operation based on DiskIo
|
||||
//
|
||||
Private->Media.IoAlign = 0;
|
||||
Private->Media.LogicalPartition = TRUE;
|
||||
Private->Media.LastBlock = DivU64x32 (
|
||||
MultU64x32 (
|
||||
End - Start + 1,
|
||||
ParentBlockIo->Media->BlockSize
|
||||
(ParentBlockIo != NULL) ? ParentBlockIo->Media->BlockSize : ParentBlockIo2->Media->BlockSize
|
||||
),
|
||||
BlockSize
|
||||
BlockSize
|
||||
) - 1;
|
||||
|
||||
Private->Media.BlockSize = (UINT32) BlockSize;
|
||||
|
||||
//
|
||||
// For BlockIO2, it should keep the same alignment with the parent BlockIO2's.
|
||||
//
|
||||
Private->Media2.LogicalPartition = TRUE;
|
||||
Private->Media2.LastBlock = Private->Media.LastBlock;
|
||||
Private->Media2.BlockSize = (UINT32) BlockSize;
|
||||
|
||||
//
|
||||
// Per UEFI Spec, LowestAlignedLba and LogicalBlocksPerPhysicalBlock must be 0
|
||||
// for logical partitions.
|
||||
@@ -703,12 +1059,7 @@ PartitionInstallChildHandle (
|
||||
Private->BlockIo.Media->LogicalBlocksPerPhysicalBlock = 0;
|
||||
}
|
||||
|
||||
Private->BlockIo.Reset = PartitionReset;
|
||||
Private->BlockIo.ReadBlocks = PartitionReadBlocks;
|
||||
Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
|
||||
Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
|
||||
|
||||
Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
|
||||
Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
|
||||
|
||||
if (Private->DevicePath == NULL) {
|
||||
FreePool (Private);
|
||||
@@ -723,20 +1074,61 @@ PartitionInstallChildHandle (
|
||||
//
|
||||
Private->EspGuid = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Create the new handle
|
||||
// Create the new handle.
|
||||
// BlockIO2 will be installed on the condition that the blocksize of parent BlockIO
|
||||
// is same with the child BlockIO's. Instead of calling the DiskIO, the child BlockIO2
|
||||
// directly call the parent BlockIO and doesn't handle the different block size issue.
|
||||
// If SPEC will update the DiskIO to support the Non-Blocking model, the BlockIO2 will call
|
||||
// DiskIO to handle the blocksize unequal issue and the limitation will be remove from
|
||||
// here.
|
||||
//
|
||||
Private->Handle = NULL;
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&Private->Handle,
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
Private->DevicePath,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
&Private->BlockIo,
|
||||
Private->EspGuid,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
if ((Private->ParentBlockIo != NULL) &&
|
||||
(Private->ParentBlockIo2 != NULL) &&
|
||||
(Private->ParentBlockIo2->Media->BlockSize == BlockSize)
|
||||
) {
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&Private->Handle,
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
Private->DevicePath,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
&Private->BlockIo,
|
||||
&gEfiBlockIo2ProtocolGuid,
|
||||
&Private->BlockIo2,
|
||||
Private->EspGuid,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
} else {
|
||||
if (Private->ParentBlockIo != NULL) {
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&Private->Handle,
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
Private->DevicePath,
|
||||
&gEfiBlockIoProtocolGuid,
|
||||
&Private->BlockIo,
|
||||
Private->EspGuid,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
if (Private->ParentBlockIo2 != NULL &&
|
||||
Private->ParentBlockIo2->Media->BlockSize == BlockSize
|
||||
) {
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&Private->Handle,
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
Private->DevicePath,
|
||||
&gEfiBlockIo2ProtocolGuid,
|
||||
&Private->BlockIo2,
|
||||
Private->EspGuid,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
//
|
||||
|
Reference in New Issue
Block a user