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).