Aligned - A read of N contiguous sectors.\r
OverRun - The last byte is not on a sector boundary.\r
\r
-Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
//\r
// Driver binding protocol implementation for DiskIo driver.\r
//\r
-EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {\r
+EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {\r
DiskIoDriverBindingSupported,\r
DiskIoDriverBindingStart,\r
DiskIoDriverBindingStop,\r
// Template for DiskIo private data structure.\r
// The pointer to BlockIo protocol interface is assigned dynamically.\r
//\r
-DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate = {\r
+DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate = {\r
DISK_IO_PRIVATE_DATA_SIGNATURE,\r
{\r
EFI_DISK_IO_PROTOCOL_REVISION,\r
};\r
\r
/**\r
- Test to see if this driver supports ControllerHandle. \r
+ Test to see if this driver supports ControllerHandle.\r
\r
@param This Protocol instance pointer.\r
@param ControllerHandle Handle of device to test\r
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
\r
//\r
// Open the IO Abstraction(s) needed to perform the supported test.\r
Status = gBS->OpenProtocol (\r
ControllerHandle,\r
&gEfiBlockIoProtocolGuid,\r
- (VOID **) &BlockIo,\r
+ (VOID **)&BlockIo,\r
This->DriverBindingHandle,\r
ControllerHandle,\r
EFI_OPEN_PROTOCOL_BY_DRIVER\r
return EFI_SUCCESS;\r
}\r
\r
-\r
/**\r
Start this driver on ControllerHandle by opening a Block IO protocol and\r
installing a Disk IO protocol on ControllerHandle.\r
Status = gBS->OpenProtocol (\r
ControllerHandle,\r
&gEfiBlockIoProtocolGuid,\r
- (VOID **) &gDiskIoPrivateDataTemplate.BlockIo,\r
+ (VOID **)&gDiskIoPrivateDataTemplate.BlockIo,\r
This->DriverBindingHandle,\r
ControllerHandle,\r
EFI_OPEN_PROTOCOL_BY_DRIVER\r
Status = gBS->OpenProtocol (\r
ControllerHandle,\r
&gEfiBlockIo2ProtocolGuid,\r
- (VOID **) &gDiskIoPrivateDataTemplate.BlockIo2,\r
+ (VOID **)&gDiskIoPrivateDataTemplate.BlockIo2,\r
This->DriverBindingHandle,\r
ControllerHandle,\r
EFI_OPEN_PROTOCOL_BY_DRIVER\r
if (EFI_ERROR (Status)) {\r
gDiskIoPrivateDataTemplate.BlockIo2 = NULL;\r
}\r
- \r
+\r
//\r
// Initialize the Disk IO device instance.\r
//\r
Status = EFI_OUT_OF_RESOURCES;\r
goto ErrorExit;\r
}\r
- \r
+\r
//\r
// The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.\r
//\r
- ASSERT ((Instance->BlockIo2 == NULL) ||\r
- ((Instance->BlockIo->Media->IoAlign == Instance->BlockIo2->Media->IoAlign) && \r
- (Instance->BlockIo->Media->BlockSize == Instance->BlockIo2->Media->BlockSize)\r
- ));\r
- \r
+ ASSERT (\r
+ (Instance->BlockIo2 == NULL) ||\r
+ ((Instance->BlockIo->Media->IoAlign == Instance->BlockIo2->Media->IoAlign) &&\r
+ (Instance->BlockIo->Media->BlockSize == Instance->BlockIo2->Media->BlockSize)\r
+ )\r
+ );\r
+\r
InitializeListHead (&Instance->TaskQueue);\r
EfiInitializeLock (&Instance->TaskQueueLock, TPL_NOTIFY);\r
Instance->SharedWorkingBuffer = AllocateAlignedPages (\r
if (Instance->BlockIo2 != NULL) {\r
Status = gBS->InstallMultipleProtocolInterfaces (\r
&ControllerHandle,\r
- &gEfiDiskIoProtocolGuid, &Instance->DiskIo,\r
- &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,\r
+ &gEfiDiskIoProtocolGuid,\r
+ &Instance->DiskIo,\r
+ &gEfiDiskIo2ProtocolGuid,\r
+ &Instance->DiskIo2,\r
NULL\r
);\r
} else {\r
Status = gBS->InstallMultipleProtocolInterfaces (\r
&ControllerHandle,\r
- &gEfiDiskIoProtocolGuid, &Instance->DiskIo,\r
+ &gEfiDiskIoProtocolGuid,\r
+ &Instance->DiskIo,\r
NULL\r
);\r
}\r
\r
ErrorExit:\r
if (EFI_ERROR (Status)) {\r
- if (Instance != NULL && Instance->SharedWorkingBuffer != NULL) {\r
+ if ((Instance != NULL) && (Instance->SharedWorkingBuffer != NULL)) {\r
FreeAlignedPages (\r
Instance->SharedWorkingBuffer,\r
EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)\r
EFI_STATUS\r
EFIAPI\r
DiskIoDriverBindingStop (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE ControllerHandle,\r
- IN UINTN NumberOfChildren,\r
- IN EFI_HANDLE *ChildHandleBuffer\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_DISK_IO_PROTOCOL *DiskIo;\r
- EFI_DISK_IO2_PROTOCOL *DiskIo2;\r
- DISK_IO_PRIVATE_DATA *Instance;\r
- BOOLEAN AllTaskDone;\r
+ EFI_STATUS Status;\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;\r
+ DISK_IO_PRIVATE_DATA *Instance;\r
+ BOOLEAN AllTaskDone;\r
\r
//\r
// Get our context back.\r
Status = gBS->OpenProtocol (\r
ControllerHandle,\r
&gEfiDiskIoProtocolGuid,\r
- (VOID **) &DiskIo,\r
+ (VOID **)&DiskIo,\r
This->DriverBindingHandle,\r
ControllerHandle,\r
EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
+\r
Status = gBS->OpenProtocol (\r
ControllerHandle,\r
&gEfiDiskIo2ProtocolGuid,\r
- (VOID **) &DiskIo2,\r
+ (VOID **)&DiskIo2,\r
This->DriverBindingHandle,\r
ControllerHandle,\r
EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
if (EFI_ERROR (Status)) {\r
DiskIo2 = NULL;\r
}\r
- \r
+\r
Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo);\r
\r
if (DiskIo2 != NULL) {\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
+\r
Status = gBS->UninstallMultipleProtocolInterfaces (\r
ControllerHandle,\r
- &gEfiDiskIoProtocolGuid, &Instance->DiskIo,\r
- &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,\r
+ &gEfiDiskIoProtocolGuid,\r
+ &Instance->DiskIo,\r
+ &gEfiDiskIo2ProtocolGuid,\r
+ &Instance->DiskIo2,\r
NULL\r
);\r
} else {\r
Status = gBS->UninstallMultipleProtocolInterfaces (\r
ControllerHandle,\r
- &gEfiDiskIoProtocolGuid, &Instance->DiskIo,\r
+ &gEfiDiskIoProtocolGuid,\r
+ &Instance->DiskIo,\r
NULL\r
);\r
}\r
+\r
if (!EFI_ERROR (Status)) {\r
- \r
do {\r
EfiAcquireLock (&Instance->TaskQueueLock);\r
AllTaskDone = IsListEmpty (&Instance->TaskQueue);\r
);\r
ASSERT_EFI_ERROR (Status);\r
}\r
- \r
+\r
FreePool (Instance);\r
}\r
\r
return Status;\r
}\r
\r
-\r
/**\r
Destroy the sub task.\r
\r
**/\r
LIST_ENTRY *\r
DiskIoDestroySubtask (\r
- IN DISK_IO_PRIVATE_DATA *Instance,\r
- IN DISK_IO_SUBTASK *Subtask\r
+ IN DISK_IO_PRIVATE_DATA *Instance,\r
+ IN DISK_IO_SUBTASK *Subtask\r
)\r
{\r
- LIST_ENTRY *Link;\r
+ LIST_ENTRY *Link;\r
+\r
+ if (Subtask->Task != NULL) {\r
+ EfiAcquireLock (&Subtask->Task->SubtasksLock);\r
+ }\r
+\r
Link = RemoveEntryList (&Subtask->Link);\r
+ if (Subtask->Task != NULL) {\r
+ EfiReleaseLock (&Subtask->Task->SubtasksLock);\r
+ }\r
+\r
if (!Subtask->Blocking) {\r
if (Subtask->WorkingBuffer != NULL) {\r
FreeAlignedPages (\r
- Subtask->WorkingBuffer, \r
+ Subtask->WorkingBuffer,\r
Subtask->Length < Instance->BlockIo->Media->BlockSize\r
? EFI_SIZE_TO_PAGES (Instance->BlockIo->Media->BlockSize)\r
: EFI_SIZE_TO_PAGES (Subtask->Length)\r
);\r
}\r
+\r
if (Subtask->BlockIo2Token.Event != NULL) {\r
gBS->CloseEvent (Subtask->BlockIo2Token.Event);\r
}\r
}\r
+\r
FreePool (Subtask);\r
\r
return Link;\r
VOID\r
EFIAPI\r
DiskIo2OnReadWriteComplete (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
)\r
{\r
DISK_IO_SUBTASK *Subtask;\r
EFI_STATUS TransactionStatus;\r
DISK_IO_PRIVATE_DATA *Instance;\r
\r
- Subtask = (DISK_IO_SUBTASK *) Context;\r
+ Subtask = (DISK_IO_SUBTASK *)Context;\r
TransactionStatus = Subtask->BlockIo2Token.TransactionStatus;\r
Task = Subtask->Task;\r
Instance = Task->Instance;\r
ASSERT (Instance->Signature == DISK_IO_PRIVATE_DATA_SIGNATURE);\r
ASSERT (Task->Signature == DISK_IO2_TASK_SIGNATURE);\r
\r
- if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) && \r
+ if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) &&\r
(Task->Token != NULL) && !Subtask->Write\r
- ) {\r
+ )\r
+ {\r
CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);\r
}\r
\r
gBS->SignalEvent (Task->Token->Event);\r
\r
//\r
- // Mark token to NULL\r
+ // Mark token to NULL indicating the Task is a dead task.\r
//\r
Task->Token = NULL;\r
}\r
}\r
-\r
- if (IsListEmpty (&Task->Subtasks)) {\r
- EfiAcquireLock (&Instance->TaskQueueLock);\r
- RemoveEntryList (&Task->Link);\r
- EfiReleaseLock (&Instance->TaskQueueLock);\r
-\r
- FreePool (Task);\r
- }\r
}\r
\r
/**\r
**/\r
DISK_IO_SUBTASK *\r
DiskIoCreateSubtask (\r
- IN BOOLEAN Write,\r
- IN UINT64 Lba,\r
- IN UINT32 Offset,\r
- IN UINTN Length,\r
- IN VOID *WorkingBuffer, OPTIONAL\r
- IN VOID *Buffer,\r
- IN BOOLEAN Blocking\r
+ IN BOOLEAN Write,\r
+ IN UINT64 Lba,\r
+ IN UINT32 Offset,\r
+ IN UINTN Length,\r
+ IN VOID *WorkingBuffer OPTIONAL,\r
+ IN VOID *Buffer,\r
+ IN BOOLEAN Blocking\r
)\r
{\r
- DISK_IO_SUBTASK *Subtask;\r
- EFI_STATUS Status;\r
+ DISK_IO_SUBTASK *Subtask;\r
+ EFI_STATUS Status;\r
\r
Subtask = AllocateZeroPool (sizeof (DISK_IO_SUBTASK));\r
if (Subtask == NULL) {\r
return NULL;\r
}\r
+\r
Subtask->Signature = DISK_IO_SUBTASK_SIGNATURE;\r
Subtask->Write = Write;\r
Subtask->Lba = Lba;\r
return NULL;\r
}\r
}\r
+\r
DEBUG ((\r
- EFI_D_BLKIO, \r
+ DEBUG_BLKIO,\r
" %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",\r
- Write ? 'W': 'R', Lba, Offset, Length, WorkingBuffer, Buffer\r
+ Write ? 'W' : 'R',\r
+ Lba,\r
+ Offset,\r
+ Length,\r
+ WorkingBuffer,\r
+ Buffer\r
));\r
\r
return Subtask;\r
IN OUT LIST_ENTRY *Subtasks\r
)\r
{\r
- UINT32 BlockSize;\r
- UINT32 IoAlign;\r
- UINT64 Lba;\r
- UINT64 OverRunLba;\r
- UINT32 UnderRun;\r
- UINT32 OverRun;\r
- UINT8 *BufferPtr;\r
- UINTN Length;\r
- UINTN DataBufferSize;\r
- DISK_IO_SUBTASK *Subtask;\r
- VOID *WorkingBuffer;\r
- LIST_ENTRY *Link;\r
-\r
- DEBUG ((EFI_D_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));\r
+ UINT32 BlockSize;\r
+ UINT32 IoAlign;\r
+ UINT64 Lba;\r
+ UINT64 OverRunLba;\r
+ UINT32 UnderRun;\r
+ UINT32 OverRun;\r
+ UINT8 *BufferPtr;\r
+ UINTN Length;\r
+ UINTN DataBufferSize;\r
+ DISK_IO_SUBTASK *Subtask;\r
+ VOID *WorkingBuffer;\r
+ LIST_ENTRY *Link;\r
+\r
+ DEBUG ((DEBUG_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));\r
\r
BlockSize = Instance->BlockIo->Media->BlockSize;\r
IoAlign = Instance->BlockIo->Media->IoAlign;\r
if (IoAlign == 0) {\r
IoAlign = 1;\r
}\r
- \r
+\r
Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);\r
- BufferPtr = (UINT8 *) Buffer;\r
+ BufferPtr = (UINT8 *)Buffer;\r
\r
//\r
// Special handling for zero BufferSize\r
if (Subtask == NULL) {\r
goto Done;\r
}\r
+\r
InsertTailList (Subtasks, &Subtask->Link);\r
return TRUE;\r
}\r
goto Done;\r
}\r
}\r
+\r
if (Write) {\r
//\r
// A half write operation can be splitted to a blocking block-read and half write operation\r
if (Subtask == NULL) {\r
goto Done;\r
}\r
+\r
InsertTailList (Subtasks, &Subtask->Link);\r
}\r
\r
if (Subtask == NULL) {\r
goto Done;\r
}\r
+\r
InsertTailList (Subtasks, &Subtask->Link);\r
- \r
+\r
BufferPtr += Length;\r
Offset += Length;\r
BufferSize -= Length;\r
- Lba ++;\r
+ Lba++;\r
}\r
\r
OverRunLba = Lba + DivU64x32Remainder (BufferSize, BlockSize, &OverRun);\r
goto Done;\r
}\r
}\r
+\r
if (Write) {\r
//\r
// A half write operation can be splitted to a blocking block-read and half write operation\r
if (Subtask == NULL) {\r
goto Done;\r
}\r
+\r
InsertTailList (Subtasks, &Subtask->Link);\r
}\r
\r
if (Subtask == NULL) {\r
goto Done;\r
}\r
+\r
InsertTailList (Subtasks, &Subtask->Link);\r
}\r
- \r
+\r
if (OverRunLba > Lba) {\r
//\r
// If the DiskIo maps directly to a BlockIo device do the read.\r
if (Subtask == NULL) {\r
goto Done;\r
}\r
+\r
InsertTailList (Subtasks, &Subtask->Link);\r
\r
BufferPtr += BufferSize;\r
Offset += BufferSize;\r
BufferSize -= BufferSize;\r
-\r
} else {\r
if (Blocking) {\r
//\r
// Use the allocated buffer instead of the original buffer\r
// to avoid alignment issue.\r
//\r
- for (; Lba < OverRunLba; Lba += PcdGet32 (PcdDiskIoDataBufferBlockNum)) {\r
+ for ( ; Lba < OverRunLba; Lba += PcdGet32 (PcdDiskIoDataBufferBlockNum)) {\r
DataBufferSize = MIN (BufferSize, PcdGet32 (PcdDiskIoDataBufferBlockNum) * BlockSize);\r
\r
Subtask = DiskIoCreateSubtask (Write, Lba, 0, DataBufferSize, SharedWorkingBuffer, BufferPtr, Blocking);\r
if (Subtask == NULL) {\r
goto Done;\r
}\r
+\r
InsertTailList (Subtasks, &Subtask->Link);\r
\r
BufferPtr += DataBufferSize;\r
//\r
// If there is not enough memory, downgrade to blocking access\r
//\r
- DEBUG ((EFI_D_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n"));\r
if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, BufferPtr, TRUE, SharedWorkingBuffer, Subtasks)) {\r
goto Done;\r
}\r
if (Subtask == NULL) {\r
goto Done;\r
}\r
+\r
InsertTailList (Subtasks, &Subtask->Link);\r
}\r
\r
//\r
for (Link = GetFirstNode (Subtasks); !IsNull (Subtasks, Link); ) {\r
Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
- Link = DiskIoDestroySubtask (Instance, Subtask);\r
+ Link = DiskIoDestroySubtask (Instance, Subtask);\r
}\r
+\r
return FALSE;\r
}\r
\r
EFI_STATUS\r
EFIAPI\r
DiskIo2Cancel (\r
- IN EFI_DISK_IO2_PROTOCOL *This\r
+ IN EFI_DISK_IO2_PROTOCOL *This\r
)\r
{\r
DISK_IO_PRIVATE_DATA *Instance;\r
DISK_IO2_TASK *Task;\r
LIST_ENTRY *Link;\r
- \r
+\r
Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);\r
\r
EfiAcquireLock (&Instance->TaskQueueLock);\r
\r
for (Link = GetFirstNode (&Instance->TaskQueue)\r
- ; !IsNull (&Instance->TaskQueue, Link)\r
- ; Link = GetNextNode (&Instance->TaskQueue, Link)\r
- ) {\r
+ ; !IsNull (&Instance->TaskQueue, Link)\r
+ ; Link = GetNextNode (&Instance->TaskQueue, Link)\r
+ )\r
+ {\r
Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);\r
\r
if (Task->Token != NULL) {\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks.\r
+\r
+ @param Instance Pointer to the DISK_IO_PRIVATE_DATA.\r
+\r
+ @retval TRUE The Instance->TaskQueue is empty after the completed tasks are removed.\r
+ @retval FALSE The Instance->TaskQueue is not empty after the completed tasks are removed.\r
+**/\r
+BOOLEAN\r
+DiskIo2RemoveCompletedTask (\r
+ IN DISK_IO_PRIVATE_DATA *Instance\r
+ )\r
+{\r
+ BOOLEAN QueueEmpty;\r
+ LIST_ENTRY *Link;\r
+ DISK_IO2_TASK *Task;\r
+\r
+ QueueEmpty = TRUE;\r
+\r
+ EfiAcquireLock (&Instance->TaskQueueLock);\r
+ for (Link = GetFirstNode (&Instance->TaskQueue); !IsNull (&Instance->TaskQueue, Link); ) {\r
+ Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);\r
+ if (IsListEmpty (&Task->Subtasks)) {\r
+ Link = RemoveEntryList (&Task->Link);\r
+ ASSERT (Task->Token == NULL);\r
+ FreePool (Task);\r
+ } else {\r
+ Link = GetNextNode (&Instance->TaskQueue, Link);\r
+ QueueEmpty = FALSE;\r
+ }\r
+ }\r
+\r
+ EfiReleaseLock (&Instance->TaskQueueLock);\r
+\r
+ return QueueEmpty;\r
+}\r
+\r
/**\r
Common routine to access the disk.\r
\r
If this field is NULL, synchronous/blocking IO is performed.\r
@param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.\r
@param Buffer A pointer to the destination buffer for the data.\r
- The caller is responsible either having implicit or explicit ownership of the buffer. \r
+ The caller is responsible either having implicit or explicit ownership of the buffer.\r
**/\r
EFI_STATUS\r
DiskIo2ReadWriteDisk (\r
- IN DISK_IO_PRIVATE_DATA *Instance,\r
- IN BOOLEAN Write,\r
- IN UINT32 MediaId,\r
- IN UINT64 Offset,\r
- IN EFI_DISK_IO2_TOKEN *Token,\r
- IN UINTN BufferSize,\r
- IN UINT8 *Buffer\r
+ IN DISK_IO_PRIVATE_DATA *Instance,\r
+ IN BOOLEAN Write,\r
+ IN UINT32 MediaId,\r
+ IN UINT64 Offset,\r
+ IN EFI_DISK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ IN UINT8 *Buffer\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
- EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
- EFI_BLOCK_IO_MEDIA *Media;\r
- LIST_ENTRY *Link;\r
- LIST_ENTRY Subtasks;\r
- DISK_IO_SUBTASK *Subtask;\r
- DISK_IO2_TASK *Task;\r
- BOOLEAN TaskQueueEmpty;\r
- EFI_TPL OldTpl;\r
- BOOLEAN Blocking;\r
- LIST_ENTRY *SubtasksPtr;\r
-\r
- Task = NULL;\r
- BlockIo = Instance->BlockIo;\r
- BlockIo2 = Instance->BlockIo2;\r
- Media = BlockIo->Media;\r
- Status = EFI_SUCCESS;\r
- Blocking = (BOOLEAN) ((Token == NULL) || (Token->Event == NULL));\r
-\r
- if (Media->MediaId != MediaId) {\r
- return EFI_MEDIA_CHANGED;\r
- }\r
- \r
- if (Write && Media->ReadOnly) {\r
- return EFI_WRITE_PROTECTED;\r
- }\r
- \r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NextLink;\r
+ LIST_ENTRY Subtasks;\r
+ DISK_IO_SUBTASK *Subtask;\r
+ DISK_IO2_TASK *Task;\r
+ EFI_TPL OldTpl;\r
+ BOOLEAN Blocking;\r
+ BOOLEAN SubtaskBlocking;\r
+ LIST_ENTRY *SubtasksPtr;\r
+\r
+ Task = NULL;\r
+ BlockIo = Instance->BlockIo;\r
+ BlockIo2 = Instance->BlockIo2;\r
+ Media = BlockIo->Media;\r
+ Status = EFI_SUCCESS;\r
+ Blocking = (BOOLEAN)((Token == NULL) || (Token->Event == NULL));\r
+\r
if (Blocking) {\r
//\r
// Wait till pending async task is completed.\r
//\r
- do {\r
- EfiAcquireLock (&Instance->TaskQueueLock);\r
- TaskQueueEmpty = IsListEmpty (&Instance->TaskQueue);\r
- EfiReleaseLock (&Instance->TaskQueueLock);\r
- } while (!TaskQueueEmpty);\r
+ while (!DiskIo2RemoveCompletedTask (Instance)) {\r
+ }\r
\r
SubtasksPtr = &Subtasks;\r
} else {\r
+ DiskIo2RemoveCompletedTask (Instance);\r
Task = AllocatePool (sizeof (DISK_IO2_TASK));\r
if (Task == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
- \r
+\r
EfiAcquireLock (&Instance->TaskQueueLock);\r
InsertTailList (&Instance->TaskQueue, &Task->Link);\r
EfiReleaseLock (&Instance->TaskQueueLock);\r
Task->Signature = DISK_IO2_TASK_SIGNATURE;\r
Task->Instance = Instance;\r
Task->Token = Token;\r
+ EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY);\r
\r
SubtasksPtr = &Task->Subtasks;\r
}\r
if (Task != NULL) {\r
FreePool (Task);\r
}\r
+\r
return EFI_OUT_OF_RESOURCES;\r
}\r
+\r
ASSERT (!IsListEmpty (SubtasksPtr));\r
\r
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
- for (Link = GetFirstNode (SubtasksPtr); !IsNull (SubtasksPtr, Link); Link = GetNextNode (SubtasksPtr, Link)) {\r
- Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
+ for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link)\r
+ ; !IsNull (SubtasksPtr, Link)\r
+ ; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink)\r
+ )\r
+ {\r
+ Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
+ Subtask->Task = Task;\r
+ SubtaskBlocking = Subtask->Blocking;\r
\r
- if (!Subtask->Blocking) {\r
- Subtask->Task = Task;\r
- }\r
+ ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize));\r
\r
if (Subtask->Write) {\r
//\r
CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);\r
}\r
\r
- if (Subtask->Blocking) {\r
+ if (SubtaskBlocking) {\r
Status = BlockIo->WriteBlocks (\r
BlockIo,\r
MediaId,\r
Subtask->Lba,\r
- Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,\r
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,\r
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer\r
);\r
} else {\r
MediaId,\r
Subtask->Lba,\r
&Subtask->BlockIo2Token,\r
- Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,\r
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,\r
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer\r
);\r
}\r
-\r
} else {\r
//\r
// Read\r
//\r
- if (Subtask->Blocking) {\r
+ if (SubtaskBlocking) {\r
Status = BlockIo->ReadBlocks (\r
BlockIo,\r
MediaId,\r
Subtask->Lba,\r
- Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,\r
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,\r
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer\r
);\r
if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {\r
MediaId,\r
Subtask->Lba,\r
&Subtask->BlockIo2Token,\r
- Subtask->Length < Media->BlockSize ? Media->BlockSize : Subtask->Length,\r
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,\r
(Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer\r
);\r
}\r
}\r
- \r
+\r
+ if (SubtaskBlocking || EFI_ERROR (Status)) {\r
+ //\r
+ // Make sure the subtask list only contains non-blocking subtasks.\r
+ // Remove failed non-blocking subtasks as well because the callback won't be called.\r
+ //\r
+ DiskIoDestroySubtask (Instance, Subtask);\r
+ }\r
+\r
if (EFI_ERROR (Status)) {\r
break;\r
}\r
}\r
- \r
+\r
gBS->RaiseTPL (TPL_NOTIFY);\r
\r
//\r
// We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.\r
//\r
if (EFI_ERROR (Status)) {\r
- while (!IsNull (SubtasksPtr, Link)) {\r
- Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
- Link = DiskIoDestroySubtask (Instance, Subtask);\r
+ while (!IsNull (SubtasksPtr, NextLink)) {\r
+ Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
+ NextLink = DiskIoDestroySubtask (Instance, Subtask);\r
}\r
}\r
\r
//\r
- // Remove all the blocking subtasks because the non-blocking callback only removes the non-blocking subtask.\r
- //\r
- for (Link = GetFirstNode (SubtasksPtr); !IsNull (SubtasksPtr, Link); ) {\r
- Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);\r
- if (Subtask->Blocking) {\r
- Link = DiskIoDestroySubtask (Instance, Subtask);\r
- } else {\r
- Link = GetNextNode (SubtasksPtr, Link);\r
- }\r
- }\r
-\r
- //\r
- // It's possible that the callback runs before raising TPL to NOTIFY,\r
- // so the subtasks list only contains blocking subtask.\r
- // Remove the Task after the blocking subtasks are removed in above.\r
+ // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,\r
+ // so the subtasks list might be empty at this point.\r
//\r
if (!Blocking && IsListEmpty (SubtasksPtr)) {\r
EfiAcquireLock (&Instance->TaskQueueLock);\r
// Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete\r
// It it's not, that means the non-blocking request was downgraded to blocking request.\r
//\r
- DEBUG ((EFI_D_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));\r
Task->Token->TransactionStatus = Status;\r
gBS->SignalEvent (Task->Token->Event);\r
}\r
EFI_STATUS\r
EFIAPI\r
DiskIo2ReadDiskEx (\r
- IN EFI_DISK_IO2_PROTOCOL *This,\r
- IN UINT32 MediaId,\r
- IN UINT64 Offset,\r
- IN OUT EFI_DISK_IO2_TOKEN *Token,\r
- IN UINTN BufferSize,\r
- OUT VOID *Buffer\r
+ IN EFI_DISK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN UINT64 Offset,\r
+ IN OUT EFI_DISK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
)\r
{\r
return DiskIo2ReadWriteDisk (\r
DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),\r
- FALSE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer\r
+ FALSE,\r
+ MediaId,\r
+ Offset,\r
+ Token,\r
+ BufferSize,\r
+ (UINT8 *)Buffer\r
);\r
}\r
\r
EFI_STATUS\r
EFIAPI\r
DiskIo2WriteDiskEx (\r
- IN EFI_DISK_IO2_PROTOCOL *This,\r
- IN UINT32 MediaId,\r
- IN UINT64 Offset,\r
- IN OUT EFI_DISK_IO2_TOKEN *Token,\r
- IN UINTN BufferSize,\r
- IN VOID *Buffer\r
+ IN EFI_DISK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN UINT64 Offset,\r
+ IN OUT EFI_DISK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
)\r
{\r
return DiskIo2ReadWriteDisk (\r
DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),\r
- TRUE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer\r
+ TRUE,\r
+ MediaId,\r
+ Offset,\r
+ Token,\r
+ BufferSize,\r
+ (UINT8 *)Buffer\r
);\r
}\r
\r
VOID\r
EFIAPI\r
DiskIo2OnFlushComplete (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
)\r
{\r
- DISK_IO2_FLUSH_TASK *Task;\r
+ DISK_IO2_FLUSH_TASK *Task;\r
\r
gBS->CloseEvent (Event);\r
\r
- Task = (DISK_IO2_FLUSH_TASK *) Context;\r
+ Task = (DISK_IO2_FLUSH_TASK *)Context;\r
ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);\r
Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;\r
gBS->SignalEvent (Task->Token->Event);\r
+\r
+ FreePool (Task);\r
}\r
\r
/**\r
EFI_STATUS\r
EFIAPI\r
DiskIo2FlushDiskEx (\r
- IN EFI_DISK_IO2_PROTOCOL *This,\r
- IN OUT EFI_DISK_IO2_TOKEN *Token\r
+ IN EFI_DISK_IO2_PROTOCOL *This,\r
+ IN OUT EFI_DISK_IO2_TOKEN *Token\r
)\r
{\r
- EFI_STATUS Status;\r
- DISK_IO2_FLUSH_TASK *Task;\r
- DISK_IO_PRIVATE_DATA *Private;\r
+ EFI_STATUS Status;\r
+ DISK_IO2_FLUSH_TASK *Task;\r
+ DISK_IO_PRIVATE_DATA *Private;\r
\r
Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);\r
\r
FreePool (Task);\r
return Status;\r
}\r
+\r
Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE;\r
Task->Token = Token;\r
- Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);\r
+ Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);\r
if (EFI_ERROR (Status)) {\r
gBS->CloseEvent (Task->BlockIo2Token.Event);\r
FreePool (Task);\r
{\r
return DiskIo2ReadWriteDisk (\r
DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),\r
- FALSE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer\r
+ FALSE,\r
+ MediaId,\r
+ Offset,\r
+ NULL,\r
+ BufferSize,\r
+ (UINT8 *)Buffer\r
);\r
}\r
\r
-\r
/**\r
Writes BufferSize bytes from Buffer into Offset.\r
Writes may require a read modify write to support writes that are not\r
{\r
return DiskIo2ReadWriteDisk (\r
DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),\r
- TRUE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer\r
+ TRUE,\r
+ MediaId,\r
+ Offset,\r
+ NULL,\r
+ BufferSize,\r
+ (UINT8 *)Buffer\r
);\r
}\r
\r
/**\r
The user Entry Point for module DiskIo. The user code starts with this function.\r
\r
- @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
@param[in] SystemTable A pointer to the EFI System Table.\r
- \r
+\r
@retval EFI_SUCCESS The entry point is executed successfully.\r
@retval other Some error occurs when executing this entry point.\r
\r
EFI_STATUS\r
EFIAPI\r
InitializeDiskIo (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
)\r
{\r
- EFI_STATUS Status;\r
+ EFI_STATUS Status;\r
\r
//\r
// Install driver model protocol(s).\r