]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaBusDxe / AtaPassThruExecute.c
index 1f204193fd39f7d0a1308fd2e967bb8ec7d030df..fd483cb9a465cf3f00a650697b1fd9473d064acd 100644 (file)
@@ -3,22 +3,28 @@
 \r
   This file implements the low level execution of ATA pass through transaction.\r
   It transforms the high level identity, read/write, reset command to ATA pass\r
-  through command and protocol. \r
-    \r
-  Copyright (c) 2009 - 2011, 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
+  through command and protocol.\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
+  NOTE: This file also implements the StorageSecurityCommandProtocol(SSP). For input\r
+  parameter SecurityProtocolSpecificData, ATA spec has no explicitly definition\r
+  for Security Protocol Specific layout. This implementation uses big endian for\r
+  Cylinder register.\r
+\r
+  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 \r
 **/\r
 \r
 #include "AtaBus.h"\r
 \r
+#define ATA_CMD_TRUST_NON_DATA    0x5B\r
+#define ATA_CMD_TRUST_RECEIVE     0x5C\r
+#define ATA_CMD_TRUST_RECEIVE_DMA 0x5D\r
+#define ATA_CMD_TRUST_SEND        0x5E\r
+#define ATA_CMD_TRUST_SEND_DMA    0x5F\r
+\r
 //\r
 // Look up table (UdmaValid, IsWrite) for EFI_ATA_PASS_THRU_CMD_PROTOCOL\r
 //\r
@@ -59,6 +65,21 @@ UINT8 mAtaCommands[][2][2] = {
   }\r
 };\r
 \r
+//\r
+// Look up table (UdmaValid, IsTrustSend) for ATA_CMD\r
+//\r
+UINT8 mAtaTrustCommands[2][2] = {\r
+  {\r
+    ATA_CMD_TRUST_RECEIVE,            // PIO read\r
+    ATA_CMD_TRUST_SEND                // PIO write\r
+  },\r
+  {\r
+    ATA_CMD_TRUST_RECEIVE_DMA,        // DMA read\r
+    ATA_CMD_TRUST_SEND_DMA            // DMA write\r
+  }\r
+};\r
+\r
+\r
 //\r
 // Look up table (Lba48Bit) for maximum transfer block number\r
 //\r
@@ -76,11 +97,11 @@ UINTN mMaxTransferBlockNumber[] = {
   transaction.\r
 \r
   @param[in, out]  AtaDevice   The ATA child device involved for the operation.\r
-  @param[in, out]  TaskPacket  Pointer to a Pass Thru Command Packet. Optional, \r
+  @param[in, out]  TaskPacket  Pointer to a Pass Thru Command Packet. Optional,\r
                                if it is NULL, blocking mode, and use the packet\r
                                in AtaDevice. If it is not NULL, non blocking mode,\r
                                and pass down this Packet.\r
-  @param[in]       Event       If Event is NULL, then blocking I/O is performed.\r
+  @param[in, out]  Event       If Event is NULL, then blocking I/O is performed.\r
                                If Event is not NULL and non-blocking I/O is\r
                                supported,then non-blocking I/O is performed,\r
                                and Event will be signaled when the write\r
@@ -101,14 +122,18 @@ AtaDevicePassThru (
   EFI_ATA_PASS_THRU_COMMAND_PACKET        *Packet;\r
 \r
   //\r
-  // Assemble packet. If it is non blocking mode, the Ata driver should keep each \r
+  // Assemble packet. If it is non blocking mode, the Ata driver should keep each\r
   // subtask and clean them when the event is signaled.\r
   //\r
   if (TaskPacket != NULL) {\r
     Packet = TaskPacket;\r
-    Packet->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (*AtaDevice->Asb));\r
-    CopyMem (Packet->Asb, AtaDevice->Asb, sizeof (*AtaDevice->Asb));\r
-    Packet->Acb = AllocateCopyPool(sizeof (EFI_ATA_COMMAND_BLOCK), &AtaDevice->Acb);\r
+    Packet->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (EFI_ATA_STATUS_BLOCK));\r
+    if (Packet->Asb == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    CopyMem (Packet->Asb, AtaDevice->Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
+    Packet->Acb = AllocateCopyPool (sizeof (EFI_ATA_COMMAND_BLOCK), &AtaDevice->Acb);\r
   } else {\r
     Packet = &AtaDevice->Packet;\r
     Packet->Asb = AtaDevice->Asb;\r
@@ -126,7 +151,7 @@ AtaDevicePassThru (
                           );\r
   //\r
   // Ensure ATA pass through caller and callee have the same\r
-  // interpretation of ATA pass through protocol. \r
+  // interpretation of ATA pass through protocol.\r
   //\r
   ASSERT (Status != EFI_INVALID_PARAMETER);\r
   ASSERT (Status != EFI_BAD_BUFFER_SIZE);\r
@@ -139,7 +164,7 @@ AtaDevicePassThru (
   Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.ResetDevice().\r
 \r
   This function wraps the ResetDevice() invocation for ATA pass through function\r
-  for an ATA device. \r
+  for an ATA device.\r
 \r
   @param  AtaDevice         The ATA child device involved for the operation.\r
 \r
@@ -152,9 +177,18 @@ ResetAtaDevice (
   )\r
 {\r
   EFI_ATA_PASS_THRU_PROTOCOL              *AtaPassThru;\r
-  \r
+\r
   AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;\r
-  \r
+\r
+  //\r
+  // Report Status Code to indicate reset happens\r
+  //\r
+  REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),\r
+    AtaDevice->AtaBusDriverData->ParentDevicePath\r
+    );\r
+\r
   return AtaPassThru->ResetDevice (\r
                         AtaPassThru,\r
                         AtaDevice->Port,\r
@@ -166,7 +200,7 @@ ResetAtaDevice (
 /**\r
   Prints ATA model name to ATA device structure.\r
 \r
-  This function converts ATA device model name from ATA identify data \r
+  This function converts ATA device model name from ATA identify data\r
   to a string in ATA device structure. It needs to change the character\r
   order in the original model name string.\r
 \r
@@ -245,7 +279,7 @@ GetAtapi6Capacity (
 /**\r
   Identifies ATA device via the Identify data.\r
 \r
-  This function identifies the ATA device and initializes the Media information in \r
+  This function identifies the ATA device and initializes the Media information in\r
   Block IO protocol interface.\r
 \r
   @param  AtaDevice         The ATA child device involved for the operation.\r
@@ -275,7 +309,7 @@ IdentifyAtaDevice (
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  DEBUG ((EFI_D_INFO, "AtaBus - Identify Device (%x %x)\n", (UINTN)AtaDevice->Port, (UINTN)AtaDevice->PortMultiplierPort));\r
+  DEBUG ((EFI_D_INFO, "AtaBus - Identify Device: Port %x PortMultiplierPort %x\n", AtaDevice->Port, AtaDevice->PortMultiplierPort));\r
 \r
   //\r
   // Check whether the WORD 88 (supported UltraDMA by drive) is valid\r
@@ -337,7 +371,7 @@ IdentifyAtaDevice (
     AtaDevice->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
   }\r
   //\r
-  // Get ATA model name from identify data structure. \r
+  // Get ATA model name from identify data structure.\r
   //\r
   PrintAtaModelName (AtaDevice);\r
 \r
@@ -356,7 +390,7 @@ IdentifyAtaDevice (
 \r
   @retval EFI_SUCCESS       The device is successfully identified and Media information\r
                             is correctly initialized.\r
-  @return others            Some error occurs when discovering the ATA device. \r
+  @return others            Some error occurs when discovering the ATA device.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -372,16 +406,16 @@ DiscoverAtaDevice (
   //\r
   // Prepare for ATA command block.\r
   //\r
-  Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb));\r
+  Acb = ZeroMem (&AtaDevice->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));\r
   Acb->AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
-  Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort << 4));\r
+  Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort == 0xFFFF ? 0 : (AtaDevice->PortMultiplierPort << 4)));\r
 \r
   //\r
   // Prepare for ATA pass through packet.\r
   //\r
-  Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet));\r
+  Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
   Packet->InDataBuffer = AtaDevice->IdentifyData;\r
-  Packet->InTransferLength = sizeof (*AtaDevice->IdentifyData);\r
+  Packet->InTransferLength = sizeof (ATA_IDENTIFY_DATA);\r
   Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN;\r
   Packet->Length   = EFI_ATA_PASS_THRU_LENGTH_BYTES | EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;\r
   Packet->Timeout  = ATA_TIMEOUT;\r
@@ -394,9 +428,7 @@ DiscoverAtaDevice (
       // The command is issued successfully\r
       //\r
       Status = IdentifyAtaDevice (AtaDevice);\r
-      if (!EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
+      return Status;\r
     }\r
   } while (Retry-- > 0);\r
 \r
@@ -411,7 +443,7 @@ DiscoverAtaDevice (
   interface of ATA pass through.\r
 \r
   @param[in, out]  AtaDevice       The ATA child device involved for the operation.\r
-  @param[in, out]  TaskPacket      Pointer to a Pass Thru Command Packet. Optional, \r
+  @param[in, out]  TaskPacket      Pointer to a Pass Thru Command Packet. Optional,\r
                                    if it is NULL, blocking mode, and use the packet\r
                                    in AtaDevice. If it is not NULL, non blocking mode,\r
                                    and pass down this Packet.\r
@@ -426,7 +458,7 @@ DiscoverAtaDevice (
                                    request is completed.\r
 \r
   @retval EFI_SUCCESS       The data transfer is complete successfully.\r
-  @return others            Some error occurs when transferring data. \r
+  @return others            Some error occurs when transferring data.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -436,7 +468,7 @@ TransferAtaDevice (
   IN OUT VOID                             *Buffer,\r
   IN EFI_LBA                              StartLba,\r
   IN UINT32                               TransferLength,\r
-  IN BOOLEAN                              IsWrite, \r
+  IN BOOLEAN                              IsWrite,\r
   IN EFI_EVENT                            Event OPTIONAL\r
   )\r
 {\r
@@ -444,7 +476,7 @@ TransferAtaDevice (
   EFI_ATA_PASS_THRU_COMMAND_PACKET  *Packet;\r
 \r
   //\r
-  // Ensure AtaDevice->UdmaValid, AtaDevice->Lba48Bit and IsWrite are valid boolean values \r
+  // Ensure AtaDevice->UdmaValid, AtaDevice->Lba48Bit and IsWrite are valid boolean values\r
   //\r
   ASSERT ((UINTN) AtaDevice->UdmaValid < 2);\r
   ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);\r
@@ -452,12 +484,12 @@ TransferAtaDevice (
   //\r
   // Prepare for ATA command block.\r
   //\r
-  Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb));\r
+  Acb = ZeroMem (&AtaDevice->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));\r
   Acb->AtaCommand = mAtaCommands[AtaDevice->UdmaValid][AtaDevice->Lba48Bit][IsWrite];\r
   Acb->AtaSectorNumber = (UINT8) StartLba;\r
   Acb->AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8);\r
   Acb->AtaCylinderHigh = (UINT8) RShiftU64 (StartLba, 16);\r
-  Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort << 4));\r
+  Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort == 0xFFFF ? 0 : (AtaDevice->PortMultiplierPort << 4)));\r
   Acb->AtaSectorCount = (UINT8) TransferLength;\r
   if (AtaDevice->Lba48Bit) {\r
     Acb->AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24);\r
@@ -472,9 +504,9 @@ TransferAtaDevice (
   // Prepare for ATA pass through packet.\r
   //\r
   if (TaskPacket != NULL) {\r
-    Packet = ZeroMem (TaskPacket, sizeof (*Packet));\r
+    Packet = ZeroMem (TaskPacket, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
   } else {\r
-    Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet));\r
+    Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
   }\r
 \r
   if (IsWrite) {\r
@@ -487,25 +519,56 @@ TransferAtaDevice (
 \r
   Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsWrite];\r
   Packet->Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;\r
-  Packet->Timeout  = ATA_TIMEOUT;\r
+  //\r
+  // |------------------------|-----------------|------------------------|-----------------|\r
+  // | ATA PIO Transfer Mode  |  Transfer Rate  | ATA DMA Transfer Mode  |  Transfer Rate  |\r
+  // |------------------------|-----------------|------------------------|-----------------|\r
+  // |       PIO Mode 0       |  3.3Mbytes/sec  | Single-word DMA Mode 0 |  2.1Mbytes/sec  |\r
+  // |------------------------|-----------------|------------------------|-----------------|\r
+  // |       PIO Mode 1       |  5.2Mbytes/sec  | Single-word DMA Mode 1 |  4.2Mbytes/sec  |\r
+  // |------------------------|-----------------|------------------------|-----------------|\r
+  // |       PIO Mode 2       |  8.3Mbytes/sec  | Single-word DMA Mode 2 |  8.4Mbytes/sec  |\r
+  // |------------------------|-----------------|------------------------|-----------------|\r
+  // |       PIO Mode 3       | 11.1Mbytes/sec  | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |\r
+  // |------------------------|-----------------|------------------------|-----------------|\r
+  // |       PIO Mode 4       | 16.6Mbytes/sec  | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |\r
+  // |------------------------|-----------------|------------------------|-----------------|\r
+  //\r
+  // As AtaBus is used to manage ATA devices, we have to use the lowest transfer rate to\r
+  // calculate the possible maximum timeout value for each read/write operation.\r
+  // The timout value is rounded up to nearest integar and here an additional 30s is added\r
+  // to follow ATA spec in which it mentioned that the device may take up to 30s to respond\r
+  // commands in the Standby/Idle mode.\r
+  //\r
+  if (AtaDevice->UdmaValid) {\r
+    //\r
+    // Calculate the maximum timeout value for DMA read/write operation.\r
+    //\r
+    Packet->Timeout  = EFI_TIMER_PERIOD_SECONDS (DivU64x32 (MultU64x32 (TransferLength, AtaDevice->BlockMedia.BlockSize), 2100000) + 31);\r
+  } else {\r
+    //\r
+    // Calculate the maximum timeout value for PIO read/write operation\r
+    //\r
+    Packet->Timeout  = EFI_TIMER_PERIOD_SECONDS (DivU64x32 (MultU64x32 (TransferLength, AtaDevice->BlockMedia.BlockSize), 3300000) + 31);\r
+  }\r
 \r
   return AtaDevicePassThru (AtaDevice, TaskPacket, Event);\r
 }\r
 \r
 /**\r
-  Free SubTask. \r
+  Free SubTask.\r
 \r
   @param[in, out]  Task      Pointer to task to be freed.\r
 \r
 **/\r
 VOID\r
-EFIAPI \r
+EFIAPI\r
 FreeAtaSubTask (\r
-  IN ATA_BUS_ASYN_TASK  *Task\r
+  IN OUT ATA_BUS_ASYN_SUB_TASK  *Task\r
   )\r
 {\r
   if (Task->Packet.Asb != NULL) {\r
-    FreeAlignedBuffer (Task->Packet.Asb, sizeof (Task->Packet.Asb));\r
+    FreeAlignedBuffer (Task->Packet.Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
   }\r
   if (Task->Packet.Acb != NULL) {\r
     FreePool (Task->Packet.Acb);\r
@@ -514,38 +577,105 @@ FreeAtaSubTask (
   FreePool (Task);\r
 }\r
 \r
+/**\r
+  Terminate any in-flight non-blocking I/O requests by signaling an EFI_ABORTED\r
+  in the TransactionStatus member of the EFI_BLOCK_IO2_TOKEN for the non-blocking\r
+  I/O. After that it is safe to free any Token or Buffer data structures that\r
+  were allocated to initiate the non-blockingI/O requests that were in-flight for\r
+  this device.\r
+\r
+  @param[in]  AtaDevice     The ATA child device involved for the operation.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AtaTerminateNonBlockingTask (\r
+  IN ATA_DEVICE               *AtaDevice\r
+  )\r
+{\r
+  BOOLEAN               SubTaskEmpty;\r
+  EFI_TPL               OldTpl;\r
+  ATA_BUS_ASYN_TASK     *AtaTask;\r
+  LIST_ENTRY            *Entry;\r
+  LIST_ENTRY            *List;\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+  //\r
+  // Abort all executing tasks from now.\r
+  //\r
+  AtaDevice->Abort = TRUE;\r
+\r
+  List = &AtaDevice->AtaTaskList;\r
+  for (Entry = GetFirstNode (List); !IsNull (List, Entry);) {\r
+    AtaTask  = ATA_ASYN_TASK_FROM_ENTRY (Entry);\r
+    AtaTask->Token->TransactionStatus = EFI_ABORTED;\r
+    gBS->SignalEvent (AtaTask->Token->Event);\r
+\r
+    Entry = RemoveEntryList (Entry);\r
+    FreePool (AtaTask);\r
+  }\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  do {\r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    //\r
+    // Wait for executing subtasks done.\r
+    //\r
+    SubTaskEmpty = IsListEmpty (&AtaDevice->AtaSubTaskList);\r
+    gBS->RestoreTPL (OldTpl);\r
+  } while (!SubTaskEmpty);\r
+\r
+  //\r
+  // Aborting operation has been done. From now on, don't need to abort normal operation.\r
+  //\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+  AtaDevice->Abort = FALSE;\r
+  gBS->RestoreTPL (OldTpl);\r
+}\r
+\r
 /**\r
   Call back funtion when the event is signaled.\r
 \r
   @param[in]  Event     The Event this notify function registered to.\r
-  @param[in]  Context   Pointer to the context data registerd to the\r
+  @param[in]  Context   Pointer to the context data registered to the\r
                         Event.\r
 \r
 **/\r
 VOID\r
-EFIAPI \r
+EFIAPI\r
 AtaNonBlockingCallBack (\r
   IN EFI_EVENT                Event,\r
   IN VOID                     *Context\r
   )\r
 {\r
-  ATA_BUS_ASYN_TASK *Task;\r
+  ATA_BUS_ASYN_SUB_TASK *Task;\r
+  ATA_BUS_ASYN_TASK     *AtaTask;\r
+  ATA_DEVICE            *AtaDevice;\r
+  LIST_ENTRY            *Entry;\r
+  EFI_STATUS            Status;\r
 \r
-  Task = (ATA_BUS_ASYN_TASK *) Context;\r
+  Task = (ATA_BUS_ASYN_SUB_TASK *) Context;\r
   gBS->CloseEvent (Event);\r
 \r
+  AtaDevice = Task->AtaDevice;\r
+\r
   //\r
   // Check the command status.\r
   // If there is error during the sub task source allocation, the error status\r
   // should be returned to the caller directly, so here the Task->Token may already\r
   // be deleted by the caller and no need to update the status.\r
   //\r
-  if ((!(*Task->IsError)) && (Task->Packet.Asb->AtaStatus & 0x01) == 0x01) {\r
+  if ((!(*Task->IsError)) && ((Task->Packet.Asb->AtaStatus & 0x01) == 0x01)) {\r
     Task->Token->TransactionStatus = EFI_DEVICE_ERROR;\r
   }\r
+\r
+  if (AtaDevice->Abort) {\r
+    Task->Token->TransactionStatus = EFI_ABORTED;\r
+  }\r
+\r
   DEBUG ((\r
-    DEBUG_INFO, \r
-    "NON-BLOCKING EVENT FINISHED!- STATUS = %r\n", \r
+    EFI_D_BLKIO,\r
+    "NON-BLOCKING EVENT FINISHED!- STATUS = %r\n",\r
     Task->Token->TransactionStatus\r
     ));\r
 \r
@@ -553,7 +683,7 @@ AtaNonBlockingCallBack (
   // Reduce the SubEventCount, till it comes to zero.\r
   //\r
   (*Task->UnsignalledEventCount) --;\r
-  DEBUG ((DEBUG_INFO, "UnsignalledEventCount = %x\n", *Task->UnsignalledEventCount));\r
+  DEBUG ((EFI_D_BLKIO, "UnsignalledEventCount = %d\n", *Task->UnsignalledEventCount));\r
 \r
   //\r
   // Remove the SubTask from the Task list.\r
@@ -561,21 +691,46 @@ AtaNonBlockingCallBack (
   RemoveEntryList (&Task->TaskEntry);\r
   if ((*Task->UnsignalledEventCount) == 0) {\r
     //\r
-    // All Sub tasks are done, then signal the upper layyer event.\r
+    // All Sub tasks are done, then signal the upper layer event.\r
     // Except there is error during the sub task source allocation.\r
     //\r
     if (!(*Task->IsError)) {\r
       gBS->SignalEvent (Task->Token->Event);\r
-      DEBUG ((DEBUG_INFO, "Signal Up Level Event UnsignalledEventCount = %x!\n", *Task->UnsignalledEventCount));\r
+      DEBUG ((EFI_D_BLKIO, "Signal the upper layer event!\n"));\r
     }\r
-    \r
+\r
     FreePool (Task->UnsignalledEventCount);\r
     FreePool (Task->IsError);\r
+\r
+\r
+    //\r
+    // Finish all subtasks and move to the next task in AtaTaskList.\r
+    //\r
+    if (!IsListEmpty (&AtaDevice->AtaTaskList)) {\r
+      Entry   = GetFirstNode (&AtaDevice->AtaTaskList);\r
+      AtaTask = ATA_ASYN_TASK_FROM_ENTRY (Entry);\r
+      DEBUG ((EFI_D_BLKIO, "Start to embark a new Ata Task\n"));\r
+      DEBUG ((EFI_D_BLKIO, "AtaTask->NumberOfBlocks = %x; AtaTask->Token=%x\n", AtaTask->NumberOfBlocks, AtaTask->Token));\r
+      Status = AccessAtaDevice (\r
+                 AtaTask->AtaDevice,\r
+                 AtaTask->Buffer,\r
+                 AtaTask->StartLba,\r
+                 AtaTask->NumberOfBlocks,\r
+                 AtaTask->IsWrite,\r
+                 AtaTask->Token\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        AtaTask->Token->TransactionStatus = Status;\r
+        gBS->SignalEvent (AtaTask->Token->Event);\r
+      }\r
+      RemoveEntryList (Entry);\r
+      FreePool (AtaTask);\r
+    }\r
   }\r
 \r
   DEBUG ((\r
-    DEBUG_INFO, \r
-    "PACKET INFO: Write=%s, Lenght=%x, LowCylinder=%x, HighCylinder=%x,SectionNumber=%x",\r
+    EFI_D_BLKIO,\r
+    "PACKET INFO: Write=%s, Length=%x, LowCylinder=%x, HighCylinder=%x, SectionNumber=%x\n",\r
     Task->Packet.OutDataBuffer != NULL ? L"YES" : L"NO",\r
     Task->Packet.OutDataBuffer != NULL ? Task->Packet.OutTransferLength : Task->Packet.InTransferLength,\r
     Task->Packet.Acb->AtaCylinderLow,\r
@@ -604,10 +759,10 @@ AtaNonBlockingCallBack (
   @param[in, out]  Token           A pointer to the token associated with the transaction.\r
 \r
   @retval EFI_SUCCESS       The data transfer is complete successfully.\r
-  @return others            Some error occurs when transferring data. \r
+  @return others            Some error occurs when transferring data.\r
 \r
 **/\r
-EFI_STATUS \r
+EFI_STATUS\r
 AccessAtaDevice(\r
   IN OUT ATA_DEVICE                 *AtaDevice,\r
   IN OUT UINT8                      *Buffer,\r
@@ -621,45 +776,83 @@ AccessAtaDevice(
   UINTN                             MaxTransferBlockNumber;\r
   UINTN                             TransferBlockNumber;\r
   UINTN                             BlockSize;\r
+  ATA_BUS_ASYN_SUB_TASK             *SubTask;\r
   UINTN                             *EventCount;\r
   UINTN                             TempCount;\r
-  ATA_BUS_ASYN_TASK                 *Task;\r
+  ATA_BUS_ASYN_TASK                 *AtaTask;\r
   EFI_EVENT                         SubEvent;\r
   UINTN                             Index;\r
   BOOLEAN                           *IsError;\r
   EFI_TPL                           OldTpl;\r
 \r
-  SubEvent  = NULL;\r
-  TempCount = 0;\r
-  Status    = EFI_SUCCESS;\r
-\r
-  EventCount = AllocateZeroPool (sizeof (UINTN));\r
-  if (EventCount == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
-  \r
-  IsError = AllocateZeroPool (sizeof (BOOLEAN));\r
-  if (IsError == NULL) {\r
-    goto EXIT;\r
-  }\r
-  *IsError = FALSE;\r
+  TempCount  = 0;\r
+  Status     = EFI_SUCCESS;\r
+  EventCount = NULL;\r
+  IsError    = NULL;\r
+  Index      = 0;\r
+  SubTask    = NULL;\r
+  SubEvent   = NULL;\r
+  AtaTask    = NULL;\r
 \r
   //\r
-  // Initial the return status for Non Blocking.\r
-  //\r
-  if (Token != NULL && Token->Event != NULL) {\r
-    Token->TransactionStatus = EFI_SUCCESS;\r
-  }\r
-  //\r
-  // Ensure AtaDevice->Lba48Bit is a valid boolean value \r
+  // Ensure AtaDevice->Lba48Bit is a valid boolean value\r
   //\r
   ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);\r
   MaxTransferBlockNumber = mMaxTransferBlockNumber[AtaDevice->Lba48Bit];\r
   BlockSize              = AtaDevice->BlockMedia.BlockSize;\r
 \r
-  TempCount     = (NumberOfBlocks + MaxTransferBlockNumber - 1) / MaxTransferBlockNumber;\r
-  *EventCount   = TempCount;\r
-  Index         = 0;\r
+  //\r
+  // Initial the return status and shared account for Non Blocking.\r
+  //\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+    if (!IsListEmpty (&AtaDevice->AtaSubTaskList)) {\r
+      AtaTask = AllocateZeroPool (sizeof (ATA_BUS_ASYN_TASK));\r
+      if (AtaTask == NULL) {\r
+        gBS->RestoreTPL (OldTpl);\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      AtaTask->AtaDevice      = AtaDevice;\r
+      AtaTask->Buffer         = Buffer;\r
+      AtaTask->IsWrite        = IsWrite;\r
+      AtaTask->NumberOfBlocks = NumberOfBlocks;\r
+      AtaTask->Signature      = ATA_TASK_SIGNATURE;\r
+      AtaTask->StartLba       = StartLba;\r
+      AtaTask->Token          = Token;\r
+\r
+      InsertTailList (&AtaDevice->AtaTaskList, &AtaTask->TaskEntry);\r
+      gBS->RestoreTPL (OldTpl);\r
+      return EFI_SUCCESS;\r
+    }\r
+    gBS->RestoreTPL (OldTpl);\r
+\r
+    Token->TransactionStatus = EFI_SUCCESS;\r
+    EventCount = AllocateZeroPool (sizeof (UINTN));\r
+    if (EventCount == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    IsError = AllocateZeroPool (sizeof (BOOLEAN));\r
+    if (IsError == NULL) {\r
+      FreePool (EventCount);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    DEBUG ((EFI_D_BLKIO, "Allocation IsError Addr=%x\n", IsError));\r
+    *IsError = FALSE;\r
+    TempCount   = (NumberOfBlocks + MaxTransferBlockNumber - 1) / MaxTransferBlockNumber;\r
+    *EventCount = TempCount;\r
+    DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, NumberOfBlocks=%x\n", NumberOfBlocks));\r
+    DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, MaxTransferBlockNumber=%x\n", MaxTransferBlockNumber));\r
+    DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, EventCount=%x\n", TempCount));\r
+  } else {\r
+    while (!IsListEmpty (&AtaDevice->AtaTaskList) || !IsListEmpty (&AtaDevice->AtaSubTaskList)) {\r
+      //\r
+      // Stall for 100us.\r
+      //\r
+      MicroSecondDelay (100);\r
+    }\r
+  }\r
 \r
   do {\r
     if (NumberOfBlocks > MaxTransferBlockNumber) {\r
@@ -667,39 +860,36 @@ AccessAtaDevice(
       NumberOfBlocks     -= MaxTransferBlockNumber;\r
     } else  {\r
       TransferBlockNumber = NumberOfBlocks;\r
-      NumberOfBlocks  = 0;\r
+      NumberOfBlocks      = 0;\r
     }\r
 \r
     //\r
-    // Create sub event for the sub Ata task. Non-Blocking Mode.\r
+    // Create sub event for the sub ata task. Non-blocking mode.\r
     //\r
-    if (Token != NULL && Token->Event != NULL) {\r
-      OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-      Task   = AllocateZeroPool (sizeof (ATA_BUS_ASYN_TASK));\r
-      if (Task == NULL) {\r
-        //\r
-        // If resource allocation fail, reduce the total sub event counts.\r
-        //\r
-        *EventCount              = (*EventCount) - (TempCount - Index);\r
-        *IsError                 = TRUE;\r
-        Token->TransactionStatus = EFI_OUT_OF_RESOURCES;\r
-        Status                   = EFI_OUT_OF_RESOURCES;\r
+    if ((Token != NULL) && (Token->Event != NULL)) {\r
+      SubTask  = NULL;\r
+      SubEvent = NULL;\r
 \r
-        gBS->RestoreTPL (OldTpl);\r
+      SubTask = AllocateZeroPool (sizeof (ATA_BUS_ASYN_SUB_TASK));\r
+      if (SubTask == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
         goto EXIT;\r
       }\r
 \r
-      Task->UnsignalledEventCount = EventCount;\r
-      Task->Token                 = Token;\r
-      Task->IsError               = IsError;\r
-\r
-      InsertTailList (&AtaDevice->AtaTaskList, &Task->TaskEntry);\r
+      OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+      SubTask->UnsignalledEventCount = EventCount;\r
+      SubTask->Signature             = ATA_SUB_TASK_SIGNATURE;\r
+      SubTask->AtaDevice             = AtaDevice;\r
+      SubTask->Token                 = Token;\r
+      SubTask->IsError               = IsError;\r
+      InsertTailList (&AtaDevice->AtaSubTaskList, &SubTask->TaskEntry);\r
+      gBS->RestoreTPL (OldTpl);\r
 \r
       Status = gBS->CreateEvent (\r
                       EVT_NOTIFY_SIGNAL,\r
                       TPL_NOTIFY,\r
                       AtaNonBlockingCallBack,\r
-                      Task,\r
+                      SubTask,\r
                       &SubEvent\r
                       );\r
       //\r
@@ -707,52 +897,171 @@ AccessAtaDevice(
       // the original one minus the unassigned subtasks number.\r
       //\r
       if (EFI_ERROR (Status)) {\r
-        *EventCount = (*EventCount) - (TempCount - Index);\r
-        *IsError    = TRUE;\r
-        gBS->RestoreTPL (OldTpl);\r
+        Status = EFI_OUT_OF_RESOURCES;\r
         goto EXIT;\r
       }\r
-      Index++;\r
-      gBS->RestoreTPL (OldTpl); \r
-\r
-      DEBUG ((EFI_D_INFO, "NON-BLOCKING SET EVENT START: WRITE = %d\n", IsWrite));\r
-      Status = TransferAtaDevice (AtaDevice, &Task->Packet, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, SubEvent);\r
-      DEBUG ((\r
-        EFI_D_INFO,\r
-        "NON-BLOCKING SET EVENT END:StartLba=%x, TransferBlockNumbers=%x, Status=%r\n",\r
-        StartLba,\r
-        TransferBlockNumber,\r
-        Status\r
-        ));\r
-    }else {\r
+\r
+      Status = TransferAtaDevice (AtaDevice, &SubTask->Packet, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, SubEvent);\r
+    } else {\r
       //\r
       // Blocking Mode.\r
       //\r
-      DEBUG ((EFI_D_INFO, "BLOCKING BLOCK I/O START: WRITE = %d\n", IsWrite));\r
+      DEBUG ((EFI_D_BLKIO, "Blocking AccessAtaDevice, TransferBlockNumber=%x; StartLba = %x\n", TransferBlockNumber, StartLba));\r
       Status = TransferAtaDevice (AtaDevice, NULL, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, NULL);\r
-      DEBUG ((\r
-        EFI_D_INFO,\r
-        "BLOCKING BLOCK I/O FINISHE - StartLba = %x; TransferBlockNumbers = %x, status = %r\n", \r
-        StartLba,\r
-        TransferBlockNumber,\r
-        Status\r
-        ));\r
     }\r
 \r
     if (EFI_ERROR (Status)) {\r
       goto EXIT;\r
     }\r
 \r
+    Index++;\r
     StartLba += TransferBlockNumber;\r
     Buffer   += TransferBlockNumber * BlockSize;\r
   } while (NumberOfBlocks > 0);\r
 \r
 EXIT:\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    //\r
+    // Release resource at non-blocking mode.\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+      Token->TransactionStatus = Status;\r
+      *EventCount = (*EventCount) - (TempCount - Index);\r
+      *IsError    = TRUE;\r
+\r
+      if (*EventCount == 0) {\r
+        FreePool (EventCount);\r
+        FreePool (IsError);\r
+      }\r
+\r
+      if (SubTask != NULL) {\r
+        RemoveEntryList (&SubTask->TaskEntry);\r
+        FreeAtaSubTask (SubTask);\r
+      }\r
+\r
+      if (SubEvent != NULL) {\r
+        gBS->CloseEvent (SubEvent);\r
+      }\r
+      gBS->RestoreTPL (OldTpl);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Trust transfer data from/to ATA device.\r
+\r
+  This function performs one ATA pass through transaction to do a trust transfer from/to\r
+  ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru\r
+  interface of ATA pass through.\r
+\r
+  @param  AtaDevice                    The ATA child device involved for the operation.\r
+  @param  Buffer                       The pointer to the current transaction buffer.\r
+  @param  SecurityProtocolId           The value of the "Security Protocol" parameter of\r
+                                       the security protocol command to be sent.\r
+  @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+                                       of the security protocol command to be sent.\r
+  @param  TransferLength               The block number or sector count of the transfer.\r
+  @param  IsTrustSend                  Indicates whether it is a trust send operation or not.\r
+  @param  Timeout                      The timeout, in 100ns units, to use for the execution\r
+                                       of the security protocol command. A Timeout value of 0\r
+                                       means that this function will wait indefinitely for the\r
+                                       security protocol command to execute. If Timeout is greater\r
+                                       than zero, then this function will return EFI_TIMEOUT\r
+                                       if the time required to execute the receive data command\r
+                                       is greater than Timeout.\r
+  @param  TransferLengthOut            A pointer to a buffer to store the size in bytes of the data\r
+                                       written to the buffer. Ignore it when IsTrustSend is TRUE.\r
 \r
-  if (*EventCount == 0) {\r
-    FreePool (EventCount);\r
-    FreePool (IsError);\r
+  @retval EFI_SUCCESS       The data transfer is complete successfully.\r
+  @return others            Some error occurs when transferring data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TrustTransferAtaDevice (\r
+  IN OUT ATA_DEVICE                 *AtaDevice,\r
+  IN OUT VOID                       *Buffer,\r
+  IN UINT8                          SecurityProtocolId,\r
+  IN UINT16                         SecurityProtocolSpecificData,\r
+  IN UINTN                          TransferLength,\r
+  IN BOOLEAN                        IsTrustSend,\r
+  IN UINT64                         Timeout,\r
+  OUT UINTN                         *TransferLengthOut\r
+  )\r
+{\r
+  EFI_ATA_COMMAND_BLOCK             *Acb;\r
+  EFI_ATA_PASS_THRU_COMMAND_PACKET  *Packet;\r
+  EFI_STATUS                        Status;\r
+  VOID                              *NewBuffer;\r
+  EFI_ATA_PASS_THRU_PROTOCOL        *AtaPassThru;\r
+\r
+  //\r
+  // Ensure AtaDevice->UdmaValid and IsTrustSend are valid boolean values\r
+  //\r
+  ASSERT ((UINTN) AtaDevice->UdmaValid < 2);\r
+  ASSERT ((UINTN) IsTrustSend < 2);\r
+  //\r
+  // Prepare for ATA command block.\r
+  //\r
+  Acb = ZeroMem (&AtaDevice->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+  if (TransferLength == 0) {\r
+    Acb->AtaCommand    = ATA_CMD_TRUST_NON_DATA;\r
+  } else {\r
+    Acb->AtaCommand    = mAtaTrustCommands[AtaDevice->UdmaValid][IsTrustSend];\r
+  }\r
+  Acb->AtaFeatures      = SecurityProtocolId;\r
+  Acb->AtaSectorCount   = (UINT8) (TransferLength / 512);\r
+  Acb->AtaSectorNumber  = (UINT8) ((TransferLength / 512) >> 8);\r
+  //\r
+  // NOTE: ATA Spec has no explicitly definition for Security Protocol Specific layout.\r
+  // Here use big endian for Cylinder register.\r
+  //\r
+  Acb->AtaCylinderHigh  = (UINT8) SecurityProtocolSpecificData;\r
+  Acb->AtaCylinderLow   = (UINT8) (SecurityProtocolSpecificData >> 8);\r
+  Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort == 0xFFFF ? 0 : (AtaDevice->PortMultiplierPort << 4)));\r
+\r
+  //\r
+  // Prepare for ATA pass through packet.\r
+  //\r
+  Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
+  if (TransferLength == 0) {\r
+    Packet->InTransferLength  = 0;\r
+    Packet->OutTransferLength = 0;\r
+    Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;\r
+  } else if (IsTrustSend) {\r
+    //\r
+    // Check the alignment of the incoming buffer prior to invoking underlying ATA PassThru\r
+    //\r
+    AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;\r
+    if ((AtaPassThru->Mode->IoAlign > 1) && !IS_ALIGNED (Buffer, AtaPassThru->Mode->IoAlign)) {\r
+      NewBuffer = AllocateAlignedBuffer (AtaDevice, TransferLength);\r
+      if (NewBuffer == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      CopyMem (NewBuffer, Buffer, TransferLength);\r
+      FreePool (Buffer);\r
+      Buffer = NewBuffer;\r
+    }\r
+    Packet->OutDataBuffer = Buffer;\r
+    Packet->OutTransferLength = (UINT32) TransferLength;\r
+    Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsTrustSend];\r
+  } else {\r
+    Packet->InDataBuffer = Buffer;\r
+    Packet->InTransferLength = (UINT32) TransferLength;\r
+    Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsTrustSend];\r
   }\r
+  Packet->Length   = EFI_ATA_PASS_THRU_LENGTH_BYTES;\r
+  Packet->Timeout  = Timeout;\r
 \r
+  Status = AtaDevicePassThru (AtaDevice, NULL, NULL);\r
+  if (TransferLengthOut != NULL) {\r
+    if (! IsTrustSend) {\r
+      *TransferLengthOut = Packet->InTransferLength;\r
+    }\r
+  }\r
   return Status;\r
 }\r