X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FDisk%2FDiskIoDxe%2FDiskIo.c;h=38af39f41ec25578718f7ef4bb14771386d161b1;hb=HEAD;hp=0658299288afa6aad95d56d669f46a712c7513f7;hpb=e645bd857df95a8e2fac220fe98772cc6d37dee4;p=mirror_edk2.git
diff --git a/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c b/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
index 0658299288..38af39f41e 100644
--- a/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
+++ b/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
@@ -9,14 +9,8 @@
Aligned - A read of N contiguous sectors.
OverRun - The last byte is not on a sector boundary.
-Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution. The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -25,7 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
// Driver binding protocol implementation for DiskIo driver.
//
-EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
+EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
DiskIoDriverBindingSupported,
DiskIoDriverBindingStart,
DiskIoDriverBindingStop,
@@ -38,7 +32,7 @@ EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
// Template for DiskIo private data structure.
// The pointer to BlockIo protocol interface is assigned dynamically.
//
-DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate = {
+DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate = {
DISK_IO_PRIVATE_DATA_SIGNATURE,
{
EFI_DISK_IO_PROTOCOL_REVISION,
@@ -55,7 +49,7 @@ DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate = {
};
/**
- Test to see if this driver supports ControllerHandle.
+ Test to see if this driver supports ControllerHandle.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to test
@@ -75,8 +69,8 @@ DiskIoDriverBindingSupported (
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
- EFI_STATUS Status;
- EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
//
// Open the IO Abstraction(s) needed to perform the supported test.
@@ -84,7 +78,7 @@ DiskIoDriverBindingSupported (
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiBlockIoProtocolGuid,
- (VOID **) &BlockIo,
+ (VOID **)&BlockIo,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
@@ -105,7 +99,6 @@ DiskIoDriverBindingSupported (
return EFI_SUCCESS;
}
-
/**
Start this driver on ControllerHandle by opening a Block IO protocol and
installing a Disk IO protocol on ControllerHandle.
@@ -142,7 +135,7 @@ DiskIoDriverBindingStart (
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiBlockIoProtocolGuid,
- (VOID **) &gDiskIoPrivateDataTemplate.BlockIo,
+ (VOID **)&gDiskIoPrivateDataTemplate.BlockIo,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
@@ -154,7 +147,7 @@ DiskIoDriverBindingStart (
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiBlockIo2ProtocolGuid,
- (VOID **) &gDiskIoPrivateDataTemplate.BlockIo2,
+ (VOID **)&gDiskIoPrivateDataTemplate.BlockIo2,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
@@ -162,7 +155,7 @@ DiskIoDriverBindingStart (
if (EFI_ERROR (Status)) {
gDiskIoPrivateDataTemplate.BlockIo2 = NULL;
}
-
+
//
// Initialize the Disk IO device instance.
//
@@ -171,15 +164,17 @@ DiskIoDriverBindingStart (
Status = EFI_OUT_OF_RESOURCES;
goto ErrorExit;
}
-
+
//
// The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.
//
- ASSERT ((Instance->BlockIo2 == NULL) ||
- ((Instance->BlockIo->Media->IoAlign == Instance->BlockIo2->Media->IoAlign) &&
- (Instance->BlockIo->Media->BlockSize == Instance->BlockIo2->Media->BlockSize)
- ));
-
+ ASSERT (
+ (Instance->BlockIo2 == NULL) ||
+ ((Instance->BlockIo->Media->IoAlign == Instance->BlockIo2->Media->IoAlign) &&
+ (Instance->BlockIo->Media->BlockSize == Instance->BlockIo2->Media->BlockSize)
+ )
+ );
+
InitializeListHead (&Instance->TaskQueue);
EfiInitializeLock (&Instance->TaskQueueLock, TPL_NOTIFY);
Instance->SharedWorkingBuffer = AllocateAlignedPages (
@@ -197,21 +192,24 @@ DiskIoDriverBindingStart (
if (Instance->BlockIo2 != NULL) {
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
- &gEfiDiskIoProtocolGuid, &Instance->DiskIo,
- &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
+ &gEfiDiskIoProtocolGuid,
+ &Instance->DiskIo,
+ &gEfiDiskIo2ProtocolGuid,
+ &Instance->DiskIo2,
NULL
);
} else {
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
- &gEfiDiskIoProtocolGuid, &Instance->DiskIo,
+ &gEfiDiskIoProtocolGuid,
+ &Instance->DiskIo,
NULL
);
}
ErrorExit:
if (EFI_ERROR (Status)) {
- if (Instance != NULL && Instance->SharedWorkingBuffer != NULL) {
+ if ((Instance != NULL) && (Instance->SharedWorkingBuffer != NULL)) {
FreeAlignedPages (
Instance->SharedWorkingBuffer,
EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
@@ -252,17 +250,17 @@ ErrorExit1:
EFI_STATUS
EFIAPI
DiskIoDriverBindingStop (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN UINTN NumberOfChildren,
- IN EFI_HANDLE *ChildHandleBuffer
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
)
{
- EFI_STATUS Status;
- EFI_DISK_IO_PROTOCOL *DiskIo;
- EFI_DISK_IO2_PROTOCOL *DiskIo2;
- DISK_IO_PRIVATE_DATA *Instance;
- BOOLEAN AllTaskDone;
+ EFI_STATUS Status;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;
+ DISK_IO_PRIVATE_DATA *Instance;
+ BOOLEAN AllTaskDone;
//
// Get our context back.
@@ -270,7 +268,7 @@ DiskIoDriverBindingStop (
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiDiskIoProtocolGuid,
- (VOID **) &DiskIo,
+ (VOID **)&DiskIo,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
@@ -278,10 +276,11 @@ DiskIoDriverBindingStop (
if (EFI_ERROR (Status)) {
return Status;
}
+
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiDiskIo2ProtocolGuid,
- (VOID **) &DiskIo2,
+ (VOID **)&DiskIo2,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
@@ -289,7 +288,7 @@ DiskIoDriverBindingStop (
if (EFI_ERROR (Status)) {
DiskIo2 = NULL;
}
-
+
Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo);
if (DiskIo2 != NULL) {
@@ -301,21 +300,25 @@ DiskIoDriverBindingStop (
if (EFI_ERROR (Status)) {
return Status;
}
+
Status = gBS->UninstallMultipleProtocolInterfaces (
ControllerHandle,
- &gEfiDiskIoProtocolGuid, &Instance->DiskIo,
- &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
+ &gEfiDiskIoProtocolGuid,
+ &Instance->DiskIo,
+ &gEfiDiskIo2ProtocolGuid,
+ &Instance->DiskIo2,
NULL
);
} else {
Status = gBS->UninstallMultipleProtocolInterfaces (
ControllerHandle,
- &gEfiDiskIoProtocolGuid, &Instance->DiskIo,
+ &gEfiDiskIoProtocolGuid,
+ &Instance->DiskIo,
NULL
);
}
+
if (!EFI_ERROR (Status)) {
-
do {
EfiAcquireLock (&Instance->TaskQueueLock);
AllTaskDone = IsListEmpty (&Instance->TaskQueue);
@@ -343,14 +346,13 @@ DiskIoDriverBindingStop (
);
ASSERT_EFI_ERROR (Status);
}
-
+
FreePool (Instance);
}
return Status;
}
-
/**
Destroy the sub task.
@@ -361,25 +363,36 @@ DiskIoDriverBindingStop (
**/
LIST_ENTRY *
DiskIoDestroySubtask (
- IN DISK_IO_PRIVATE_DATA *Instance,
- IN DISK_IO_SUBTASK *Subtask
+ IN DISK_IO_PRIVATE_DATA *Instance,
+ IN DISK_IO_SUBTASK *Subtask
)
{
- LIST_ENTRY *Link;
+ LIST_ENTRY *Link;
+
+ if (Subtask->Task != NULL) {
+ EfiAcquireLock (&Subtask->Task->SubtasksLock);
+ }
+
Link = RemoveEntryList (&Subtask->Link);
+ if (Subtask->Task != NULL) {
+ EfiReleaseLock (&Subtask->Task->SubtasksLock);
+ }
+
if (!Subtask->Blocking) {
if (Subtask->WorkingBuffer != NULL) {
FreeAlignedPages (
- Subtask->WorkingBuffer,
+ Subtask->WorkingBuffer,
Subtask->Length < Instance->BlockIo->Media->BlockSize
? EFI_SIZE_TO_PAGES (Instance->BlockIo->Media->BlockSize)
: EFI_SIZE_TO_PAGES (Subtask->Length)
);
}
+
if (Subtask->BlockIo2Token.Event != NULL) {
gBS->CloseEvent (Subtask->BlockIo2Token.Event);
}
}
+
FreePool (Subtask);
return Link;
@@ -394,8 +407,8 @@ DiskIoDestroySubtask (
VOID
EFIAPI
DiskIo2OnReadWriteComplete (
- IN EFI_EVENT Event,
- IN VOID *Context
+ IN EFI_EVENT Event,
+ IN VOID *Context
)
{
DISK_IO_SUBTASK *Subtask;
@@ -403,7 +416,7 @@ DiskIo2OnReadWriteComplete (
EFI_STATUS TransactionStatus;
DISK_IO_PRIVATE_DATA *Instance;
- Subtask = (DISK_IO_SUBTASK *) Context;
+ Subtask = (DISK_IO_SUBTASK *)Context;
TransactionStatus = Subtask->BlockIo2Token.TransactionStatus;
Task = Subtask->Task;
Instance = Task->Instance;
@@ -412,9 +425,10 @@ DiskIo2OnReadWriteComplete (
ASSERT (Instance->Signature == DISK_IO_PRIVATE_DATA_SIGNATURE);
ASSERT (Task->Signature == DISK_IO2_TASK_SIGNATURE);
- if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) &&
+ if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) &&
(Task->Token != NULL) && !Subtask->Write
- ) {
+ )
+ {
CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
}
@@ -430,19 +444,11 @@ DiskIo2OnReadWriteComplete (
gBS->SignalEvent (Task->Token->Event);
//
- // Mark token to NULL
+ // Mark token to NULL indicating the Task is a dead task.
//
Task->Token = NULL;
}
}
-
- if (IsListEmpty (&Task->Subtasks)) {
- EfiAcquireLock (&Instance->TaskQueueLock);
- RemoveEntryList (&Task->Link);
- EfiReleaseLock (&Instance->TaskQueueLock);
-
- FreePool (Task);
- }
}
/**
@@ -460,22 +466,23 @@ DiskIo2OnReadWriteComplete (
**/
DISK_IO_SUBTASK *
DiskIoCreateSubtask (
- IN BOOLEAN Write,
- IN UINT64 Lba,
- IN UINT32 Offset,
- IN UINTN Length,
- IN VOID *WorkingBuffer, OPTIONAL
- IN VOID *Buffer,
- IN BOOLEAN Blocking
+ IN BOOLEAN Write,
+ IN UINT64 Lba,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *WorkingBuffer OPTIONAL,
+ IN VOID *Buffer,
+ IN BOOLEAN Blocking
)
{
- DISK_IO_SUBTASK *Subtask;
- EFI_STATUS Status;
+ DISK_IO_SUBTASK *Subtask;
+ EFI_STATUS Status;
Subtask = AllocateZeroPool (sizeof (DISK_IO_SUBTASK));
if (Subtask == NULL) {
return NULL;
}
+
Subtask->Signature = DISK_IO_SUBTASK_SIGNATURE;
Subtask->Write = Write;
Subtask->Lba = Lba;
@@ -497,10 +504,16 @@ DiskIoCreateSubtask (
return NULL;
}
}
+
DEBUG ((
- EFI_D_BLKIO,
+ DEBUG_BLKIO,
" %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
- Write ? 'W': 'R', Lba, Offset, Length, WorkingBuffer, Buffer
+ Write ? 'W' : 'R',
+ Lba,
+ Offset,
+ Length,
+ WorkingBuffer,
+ Buffer
));
return Subtask;
@@ -533,29 +546,29 @@ DiskIoCreateSubtaskList (
IN OUT LIST_ENTRY *Subtasks
)
{
- UINT32 BlockSize;
- UINT32 IoAlign;
- UINT64 Lba;
- UINT64 OverRunLba;
- UINT32 UnderRun;
- UINT32 OverRun;
- UINT8 *BufferPtr;
- UINTN Length;
- UINTN DataBufferSize;
- DISK_IO_SUBTASK *Subtask;
- VOID *WorkingBuffer;
- LIST_ENTRY *Link;
-
- DEBUG ((EFI_D_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));
+ UINT32 BlockSize;
+ UINT32 IoAlign;
+ UINT64 Lba;
+ UINT64 OverRunLba;
+ UINT32 UnderRun;
+ UINT32 OverRun;
+ UINT8 *BufferPtr;
+ UINTN Length;
+ UINTN DataBufferSize;
+ DISK_IO_SUBTASK *Subtask;
+ VOID *WorkingBuffer;
+ LIST_ENTRY *Link;
+
+ DEBUG ((DEBUG_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));
BlockSize = Instance->BlockIo->Media->BlockSize;
IoAlign = Instance->BlockIo->Media->IoAlign;
if (IoAlign == 0) {
IoAlign = 1;
}
-
+
Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);
- BufferPtr = (UINT8 *) Buffer;
+ BufferPtr = (UINT8 *)Buffer;
//
// Special handling for zero BufferSize
@@ -565,6 +578,7 @@ DiskIoCreateSubtaskList (
if (Subtask == NULL) {
goto Done;
}
+
InsertTailList (Subtasks, &Subtask->Link);
return TRUE;
}
@@ -579,6 +593,7 @@ DiskIoCreateSubtaskList (
goto Done;
}
}
+
if (Write) {
//
// A half write operation can be splitted to a blocking block-read and half write operation
@@ -588,6 +603,7 @@ DiskIoCreateSubtaskList (
if (Subtask == NULL) {
goto Done;
}
+
InsertTailList (Subtasks, &Subtask->Link);
}
@@ -595,12 +611,13 @@ DiskIoCreateSubtaskList (
if (Subtask == NULL) {
goto Done;
}
+
InsertTailList (Subtasks, &Subtask->Link);
-
+
BufferPtr += Length;
Offset += Length;
BufferSize -= Length;
- Lba ++;
+ Lba++;
}
OverRunLba = Lba + DivU64x32Remainder (BufferSize, BlockSize, &OverRun);
@@ -615,6 +632,7 @@ DiskIoCreateSubtaskList (
goto Done;
}
}
+
if (Write) {
//
// A half write operation can be splitted to a blocking block-read and half write operation
@@ -624,6 +642,7 @@ DiskIoCreateSubtaskList (
if (Subtask == NULL) {
goto Done;
}
+
InsertTailList (Subtasks, &Subtask->Link);
}
@@ -631,9 +650,10 @@ DiskIoCreateSubtaskList (
if (Subtask == NULL) {
goto Done;
}
+
InsertTailList (Subtasks, &Subtask->Link);
}
-
+
if (OverRunLba > Lba) {
//
// If the DiskIo maps directly to a BlockIo device do the read.
@@ -643,25 +663,26 @@ DiskIoCreateSubtaskList (
if (Subtask == NULL) {
goto Done;
}
+
InsertTailList (Subtasks, &Subtask->Link);
BufferPtr += BufferSize;
Offset += BufferSize;
BufferSize -= BufferSize;
-
} else {
if (Blocking) {
//
// Use the allocated buffer instead of the original buffer
// to avoid alignment issue.
//
- for (; Lba < OverRunLba; Lba += PcdGet32 (PcdDiskIoDataBufferBlockNum)) {
+ for ( ; Lba < OverRunLba; Lba += PcdGet32 (PcdDiskIoDataBufferBlockNum)) {
DataBufferSize = MIN (BufferSize, PcdGet32 (PcdDiskIoDataBufferBlockNum) * BlockSize);
Subtask = DiskIoCreateSubtask (Write, Lba, 0, DataBufferSize, SharedWorkingBuffer, BufferPtr, Blocking);
if (Subtask == NULL) {
goto Done;
}
+
InsertTailList (Subtasks, &Subtask->Link);
BufferPtr += DataBufferSize;
@@ -674,7 +695,7 @@ DiskIoCreateSubtaskList (
//
// If there is not enough memory, downgrade to blocking access
//
- DEBUG ((EFI_D_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n"));
+ DEBUG ((DEBUG_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n"));
if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, BufferPtr, TRUE, SharedWorkingBuffer, Subtasks)) {
goto Done;
}
@@ -683,6 +704,7 @@ DiskIoCreateSubtaskList (
if (Subtask == NULL) {
goto Done;
}
+
InsertTailList (Subtasks, &Subtask->Link);
}
@@ -703,8 +725,9 @@ Done:
//
for (Link = GetFirstNode (Subtasks); !IsNull (Subtasks, Link); ) {
Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
- Link = DiskIoDestroySubtask (Instance, Subtask);
+ Link = DiskIoDestroySubtask (Instance, Subtask);
}
+
return FALSE;
}
@@ -720,21 +743,22 @@ Done:
EFI_STATUS
EFIAPI
DiskIo2Cancel (
- IN EFI_DISK_IO2_PROTOCOL *This
+ IN EFI_DISK_IO2_PROTOCOL *This
)
{
DISK_IO_PRIVATE_DATA *Instance;
DISK_IO2_TASK *Task;
LIST_ENTRY *Link;
-
+
Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
EfiAcquireLock (&Instance->TaskQueueLock);
for (Link = GetFirstNode (&Instance->TaskQueue)
- ; !IsNull (&Instance->TaskQueue, Link)
- ; Link = GetNextNode (&Instance->TaskQueue, Link)
- ) {
+ ; !IsNull (&Instance->TaskQueue, Link)
+ ; Link = GetNextNode (&Instance->TaskQueue, Link)
+ )
+ {
Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
if (Task->Token != NULL) {
@@ -752,6 +776,43 @@ DiskIo2Cancel (
return EFI_SUCCESS;
}
+/**
+ Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks.
+
+ @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
+
+ @retval TRUE The Instance->TaskQueue is empty after the completed tasks are removed.
+ @retval FALSE The Instance->TaskQueue is not empty after the completed tasks are removed.
+**/
+BOOLEAN
+DiskIo2RemoveCompletedTask (
+ IN DISK_IO_PRIVATE_DATA *Instance
+ )
+{
+ BOOLEAN QueueEmpty;
+ LIST_ENTRY *Link;
+ DISK_IO2_TASK *Task;
+
+ QueueEmpty = TRUE;
+
+ EfiAcquireLock (&Instance->TaskQueueLock);
+ for (Link = GetFirstNode (&Instance->TaskQueue); !IsNull (&Instance->TaskQueue, Link); ) {
+ Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
+ if (IsListEmpty (&Task->Subtasks)) {
+ Link = RemoveEntryList (&Task->Link);
+ ASSERT (Task->Token == NULL);
+ FreePool (Task);
+ } else {
+ Link = GetNextNode (&Instance->TaskQueue, Link);
+ QueueEmpty = FALSE;
+ }
+ }
+
+ EfiReleaseLock (&Instance->TaskQueueLock);
+
+ return QueueEmpty;
+}
+
/**
Common routine to access the disk.
@@ -763,64 +824,55 @@ DiskIo2Cancel (
If this field is NULL, synchronous/blocking IO is performed.
@param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
@param Buffer A pointer to the destination buffer for the data.
- The caller is responsible either having implicit or explicit ownership of the buffer.
+ The caller is responsible either having implicit or explicit ownership of the buffer.
**/
EFI_STATUS
DiskIo2ReadWriteDisk (
- IN DISK_IO_PRIVATE_DATA *Instance,
- IN BOOLEAN Write,
- IN UINT32 MediaId,
- IN UINT64 Offset,
- IN EFI_DISK_IO2_TOKEN *Token,
- IN UINTN BufferSize,
- IN UINT8 *Buffer
+ IN DISK_IO_PRIVATE_DATA *Instance,
+ IN BOOLEAN Write,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN UINT8 *Buffer
)
{
- EFI_STATUS Status;
- EFI_BLOCK_IO_PROTOCOL *BlockIo;
- EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
- EFI_BLOCK_IO_MEDIA *Media;
- LIST_ENTRY *Link;
- LIST_ENTRY Subtasks;
- DISK_IO_SUBTASK *Subtask;
- DISK_IO2_TASK *Task;
- BOOLEAN TaskQueueEmpty;
- EFI_TPL OldTpl;
- BOOLEAN Blocking;
- LIST_ENTRY *SubtasksPtr;
-
- Task = NULL;
- BlockIo = Instance->BlockIo;
- BlockIo2 = Instance->BlockIo2;
- Media = BlockIo->Media;
- Status = EFI_SUCCESS;
- Blocking = (BOOLEAN) ((Token == NULL) || (Token->Event == NULL));
-
- if (Media->MediaId != MediaId) {
- return EFI_MEDIA_CHANGED;
- }
-
- if (Write && Media->ReadOnly) {
- return EFI_WRITE_PROTECTED;
- }
-
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ EFI_BLOCK_IO_MEDIA *Media;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ LIST_ENTRY Subtasks;
+ DISK_IO_SUBTASK *Subtask;
+ DISK_IO2_TASK *Task;
+ EFI_TPL OldTpl;
+ BOOLEAN Blocking;
+ BOOLEAN SubtaskBlocking;
+ LIST_ENTRY *SubtasksPtr;
+
+ Task = NULL;
+ BlockIo = Instance->BlockIo;
+ BlockIo2 = Instance->BlockIo2;
+ Media = BlockIo->Media;
+ Status = EFI_SUCCESS;
+ Blocking = (BOOLEAN)((Token == NULL) || (Token->Event == NULL));
+
if (Blocking) {
//
// Wait till pending async task is completed.
//
- do {
- EfiAcquireLock (&Instance->TaskQueueLock);
- TaskQueueEmpty = IsListEmpty (&Instance->TaskQueue);
- EfiReleaseLock (&Instance->TaskQueueLock);
- } while (!TaskQueueEmpty);
+ while (!DiskIo2RemoveCompletedTask (Instance)) {
+ }
SubtasksPtr = &Subtasks;
} else {
+ DiskIo2RemoveCompletedTask (Instance);
Task = AllocatePool (sizeof (DISK_IO2_TASK));
if (Task == NULL) {
return EFI_OUT_OF_RESOURCES;
}
-
+
EfiAcquireLock (&Instance->TaskQueueLock);
InsertTailList (&Instance->TaskQueue, &Task->Link);
EfiReleaseLock (&Instance->TaskQueueLock);
@@ -828,6 +880,7 @@ DiskIo2ReadWriteDisk (
Task->Signature = DISK_IO2_TASK_SIGNATURE;
Task->Instance = Instance;
Task->Token = Token;
+ EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY);
SubtasksPtr = &Task->Subtasks;
}
@@ -837,17 +890,23 @@ DiskIo2ReadWriteDisk (
if (Task != NULL) {
FreePool (Task);
}
+
return EFI_OUT_OF_RESOURCES;
}
+
ASSERT (!IsListEmpty (SubtasksPtr));
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- for (Link = GetFirstNode (SubtasksPtr); !IsNull (SubtasksPtr, Link); Link = GetNextNode (SubtasksPtr, Link)) {
- Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
+ for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link)
+ ; !IsNull (SubtasksPtr, Link)
+ ; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink)
+ )
+ {
+ Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
+ Subtask->Task = Task;
+ SubtaskBlocking = Subtask->Blocking;
- if (!Subtask->Blocking) {
- Subtask->Task = Task;
- }
+ ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize));
if (Subtask->Write) {
//
@@ -860,12 +919,12 @@ DiskIo2ReadWriteDisk (
CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);
}
- if (Subtask->Blocking) {
+ if (SubtaskBlocking) {
Status = BlockIo->WriteBlocks (
BlockIo,
MediaId,
Subtask->Lba,
- Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
);
} else {
@@ -874,21 +933,20 @@ DiskIo2ReadWriteDisk (
MediaId,
Subtask->Lba,
&Subtask->BlockIo2Token,
- Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
);
}
-
} else {
//
// Read
//
- if (Subtask->Blocking) {
+ if (SubtaskBlocking) {
Status = BlockIo->ReadBlocks (
BlockIo,
MediaId,
Subtask->Lba,
- Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
);
if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {
@@ -900,17 +958,25 @@ DiskIo2ReadWriteDisk (
MediaId,
Subtask->Lba,
&Subtask->BlockIo2Token,
- Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
);
}
}
-
+
+ if (SubtaskBlocking || EFI_ERROR (Status)) {
+ //
+ // Make sure the subtask list only contains non-blocking subtasks.
+ // Remove failed non-blocking subtasks as well because the callback won't be called.
+ //
+ DiskIoDestroySubtask (Instance, Subtask);
+ }
+
if (EFI_ERROR (Status)) {
break;
}
}
-
+
gBS->RaiseTPL (TPL_NOTIFY);
//
@@ -918,28 +984,15 @@ DiskIo2ReadWriteDisk (
// We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
//
if (EFI_ERROR (Status)) {
- while (!IsNull (SubtasksPtr, Link)) {
- Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
- Link = DiskIoDestroySubtask (Instance, Subtask);
+ while (!IsNull (SubtasksPtr, NextLink)) {
+ Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
+ NextLink = DiskIoDestroySubtask (Instance, Subtask);
}
}
//
- // Remove all the blocking subtasks because the non-blocking callback only removes the non-blocking subtask.
- //
- for (Link = GetFirstNode (SubtasksPtr); !IsNull (SubtasksPtr, Link); ) {
- Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
- if (Subtask->Blocking) {
- Link = DiskIoDestroySubtask (Instance, Subtask);
- } else {
- Link = GetNextNode (SubtasksPtr, Link);
- }
- }
-
- //
- // It's possible that the callback runs before raising TPL to NOTIFY,
- // so the subtasks list only contains blocking subtask.
- // Remove the Task after the blocking subtasks are removed in above.
+ // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
+ // so the subtasks list might be empty at this point.
//
if (!Blocking && IsListEmpty (SubtasksPtr)) {
EfiAcquireLock (&Instance->TaskQueueLock);
@@ -951,7 +1004,7 @@ DiskIo2ReadWriteDisk (
// Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
// It it's not, that means the non-blocking request was downgraded to blocking request.
//
- DEBUG ((EFI_D_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
+ DEBUG ((DEBUG_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
Task->Token->TransactionStatus = Status;
gBS->SignalEvent (Task->Token->Event);
}
@@ -989,17 +1042,22 @@ DiskIo2ReadWriteDisk (
EFI_STATUS
EFIAPI
DiskIo2ReadDiskEx (
- IN EFI_DISK_IO2_PROTOCOL *This,
- IN UINT32 MediaId,
- IN UINT64 Offset,
- IN OUT EFI_DISK_IO2_TOKEN *Token,
- IN UINTN BufferSize,
- OUT VOID *Buffer
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN OUT EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
)
{
return DiskIo2ReadWriteDisk (
DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
- FALSE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
+ FALSE,
+ MediaId,
+ Offset,
+ Token,
+ BufferSize,
+ (UINT8 *)Buffer
);
}
@@ -1028,17 +1086,22 @@ DiskIo2ReadDiskEx (
EFI_STATUS
EFIAPI
DiskIo2WriteDiskEx (
- IN EFI_DISK_IO2_PROTOCOL *This,
- IN UINT32 MediaId,
- IN UINT64 Offset,
- IN OUT EFI_DISK_IO2_TOKEN *Token,
- IN UINTN BufferSize,
- IN VOID *Buffer
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN OUT EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
)
{
return DiskIo2ReadWriteDisk (
DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
- TRUE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
+ TRUE,
+ MediaId,
+ Offset,
+ Token,
+ BufferSize,
+ (UINT8 *)Buffer
);
}
@@ -1051,18 +1114,20 @@ DiskIo2WriteDiskEx (
VOID
EFIAPI
DiskIo2OnFlushComplete (
- IN EFI_EVENT Event,
- IN VOID *Context
+ IN EFI_EVENT Event,
+ IN VOID *Context
)
{
- DISK_IO2_FLUSH_TASK *Task;
+ DISK_IO2_FLUSH_TASK *Task;
gBS->CloseEvent (Event);
- Task = (DISK_IO2_FLUSH_TASK *) Context;
+ Task = (DISK_IO2_FLUSH_TASK *)Context;
ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);
Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;
gBS->SignalEvent (Task->Token->Event);
+
+ FreePool (Task);
}
/**
@@ -1083,13 +1148,13 @@ DiskIo2OnFlushComplete (
EFI_STATUS
EFIAPI
DiskIo2FlushDiskEx (
- IN EFI_DISK_IO2_PROTOCOL *This,
- IN OUT EFI_DISK_IO2_TOKEN *Token
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN OUT EFI_DISK_IO2_TOKEN *Token
)
{
- EFI_STATUS Status;
- DISK_IO2_FLUSH_TASK *Task;
- DISK_IO_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ DISK_IO2_FLUSH_TASK *Task;
+ DISK_IO_PRIVATE_DATA *Private;
Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
@@ -1110,9 +1175,10 @@ DiskIo2FlushDiskEx (
FreePool (Task);
return Status;
}
+
Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE;
Task->Token = Token;
- Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);
+ Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);
if (EFI_ERROR (Status)) {
gBS->CloseEvent (Task->BlockIo2Token.Event);
FreePool (Task);
@@ -1159,11 +1225,15 @@ DiskIoReadDisk (
{
return DiskIo2ReadWriteDisk (
DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
- FALSE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
+ FALSE,
+ MediaId,
+ Offset,
+ NULL,
+ BufferSize,
+ (UINT8 *)Buffer
);
}
-
/**
Writes BufferSize bytes from Buffer into Offset.
Writes may require a read modify write to support writes that are not
@@ -1201,16 +1271,21 @@ DiskIoWriteDisk (
{
return DiskIo2ReadWriteDisk (
DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
- TRUE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
+ TRUE,
+ MediaId,
+ Offset,
+ NULL,
+ BufferSize,
+ (UINT8 *)Buffer
);
}
/**
The user Entry Point for module DiskIo. The user code starts with this function.
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
-
+
@retval EFI_SUCCESS The entry point is executed successfully.
@retval other Some error occurs when executing this entry point.
@@ -1218,11 +1293,11 @@ DiskIoWriteDisk (
EFI_STATUS
EFIAPI
InitializeDiskIo (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
)
{
- EFI_STATUS Status;
+ EFI_STATUS Status;
//
// Install driver model protocol(s).