]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / DiskIoDxe / DiskIo.c
index 0658299288afa6aad95d56d669f46a712c7513f7..38af39f41ec25578718f7ef4bb14771386d161b1 100644 (file)
@@ -9,14 +9,8 @@
     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
@@ -25,7 +19,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 //\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
@@ -38,7 +32,7 @@ EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
 // 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
@@ -55,7 +49,7 @@ DISK_IO_PRIVATE_DATA        gDiskIoPrivateDataTemplate = {
 };\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
@@ -75,8 +69,8 @@ DiskIoDriverBindingSupported (
   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
@@ -84,7 +78,7 @@ DiskIoDriverBindingSupported (
   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
@@ -105,7 +99,6 @@ DiskIoDriverBindingSupported (
   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
@@ -142,7 +135,7 @@ DiskIoDriverBindingStart (
   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
@@ -154,7 +147,7 @@ DiskIoDriverBindingStart (
   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
@@ -162,7 +155,7 @@ DiskIoDriverBindingStart (
   if (EFI_ERROR (Status)) {\r
     gDiskIoPrivateDataTemplate.BlockIo2 = NULL;\r
   }\r
-  \r
+\r
   //\r
   // Initialize the Disk IO device instance.\r
   //\r
@@ -171,15 +164,17 @@ DiskIoDriverBindingStart (
     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
@@ -197,21 +192,24 @@ DiskIoDriverBindingStart (
   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
@@ -252,17 +250,17 @@ ErrorExit1:
 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
@@ -270,7 +268,7 @@ DiskIoDriverBindingStop (
   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
@@ -278,10 +276,11 @@ DiskIoDriverBindingStop (
   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
@@ -289,7 +288,7 @@ DiskIoDriverBindingStop (
   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
@@ -301,21 +300,25 @@ DiskIoDriverBindingStop (
     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
@@ -343,14 +346,13 @@ DiskIoDriverBindingStop (
                       );\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
@@ -361,25 +363,36 @@ DiskIoDriverBindingStop (
 **/\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
@@ -394,8 +407,8 @@ DiskIoDestroySubtask (
 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
@@ -403,7 +416,7 @@ DiskIo2OnReadWriteComplete (
   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
@@ -412,9 +425,10 @@ DiskIo2OnReadWriteComplete (
   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
@@ -430,19 +444,11 @@ DiskIo2OnReadWriteComplete (
       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
@@ -460,22 +466,23 @@ DiskIo2OnReadWriteComplete (
 **/\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
@@ -497,10 +504,16 @@ DiskIoCreateSubtask (
       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
@@ -533,29 +546,29 @@ DiskIoCreateSubtaskList (
   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
@@ -565,6 +578,7 @@ DiskIoCreateSubtaskList (
     if (Subtask == NULL) {\r
       goto Done;\r
     }\r
+\r
     InsertTailList (Subtasks, &Subtask->Link);\r
     return TRUE;\r
   }\r
@@ -579,6 +593,7 @@ DiskIoCreateSubtaskList (
         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
@@ -588,6 +603,7 @@ DiskIoCreateSubtaskList (
       if (Subtask == NULL) {\r
         goto Done;\r
       }\r
+\r
       InsertTailList (Subtasks, &Subtask->Link);\r
     }\r
 \r
@@ -595,12 +611,13 @@ DiskIoCreateSubtaskList (
     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
@@ -615,6 +632,7 @@ DiskIoCreateSubtaskList (
         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
@@ -624,6 +642,7 @@ DiskIoCreateSubtaskList (
       if (Subtask == NULL) {\r
         goto Done;\r
       }\r
+\r
       InsertTailList (Subtasks, &Subtask->Link);\r
     }\r
 \r
@@ -631,9 +650,10 @@ DiskIoCreateSubtaskList (
     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
@@ -643,25 +663,26 @@ DiskIoCreateSubtaskList (
       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
@@ -674,7 +695,7 @@ DiskIoCreateSubtaskList (
           //\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
@@ -683,6 +704,7 @@ DiskIoCreateSubtaskList (
           if (Subtask == NULL) {\r
             goto Done;\r
           }\r
+\r
           InsertTailList (Subtasks, &Subtask->Link);\r
         }\r
 \r
@@ -703,8 +725,9 @@ Done:
   //\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
@@ -720,21 +743,22 @@ Done:
 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
@@ -752,6 +776,43 @@ DiskIo2Cancel (
   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
@@ -763,64 +824,55 @@ DiskIo2Cancel (
                      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
@@ -828,6 +880,7 @@ DiskIo2ReadWriteDisk (
     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
@@ -837,17 +890,23 @@ DiskIo2ReadWriteDisk (
     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
@@ -860,12 +919,12 @@ DiskIo2ReadWriteDisk (
         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
@@ -874,21 +933,20 @@ DiskIo2ReadWriteDisk (
                              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
@@ -900,17 +958,25 @@ DiskIo2ReadWriteDisk (
                              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
@@ -918,28 +984,15 @@ DiskIo2ReadWriteDisk (
   // 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
@@ -951,7 +1004,7 @@ DiskIo2ReadWriteDisk (
       // 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
@@ -989,17 +1042,22 @@ DiskIo2ReadWriteDisk (
 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
@@ -1028,17 +1086,22 @@ DiskIo2ReadDiskEx (
 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
@@ -1051,18 +1114,20 @@ DiskIo2WriteDiskEx (
 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
@@ -1083,13 +1148,13 @@ DiskIo2OnFlushComplete (
 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
@@ -1110,9 +1175,10 @@ DiskIo2FlushDiskEx (
       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
@@ -1159,11 +1225,15 @@ DiskIoReadDisk (
 {\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
@@ -1201,16 +1271,21 @@ DiskIoWriteDisk (
 {\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
@@ -1218,11 +1293,11 @@ DiskIoWriteDisk (
 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