]> 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 05496a9d1682fce5020414f621c667f251026042..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 Intel Corporation. <BR>\r
-  All rights reserved. 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
@@ -75,14 +96,25 @@ UINTN mMaxTransferBlockNumber[] = {
   for an ATA device. It assembles the ATA pass through command packet for ATA\r
   transaction.\r
 \r
-  @param  AtaDevice         The ATA child device involved for the operation.\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
+                               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, 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
+                               request is completed.\r
 \r
   @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru().\r
 \r
 **/\r
 EFI_STATUS\r
 AtaDevicePassThru (\r
-  IN OUT ATA_DEVICE                       *AtaDevice\r
+  IN OUT ATA_DEVICE                       *AtaDevice,\r
+  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *TaskPacket, OPTIONAL\r
+  IN OUT EFI_EVENT                        Event OPTIONAL\r
   )\r
 {\r
   EFI_STATUS                              Status;\r
@@ -90,12 +122,23 @@ AtaDevicePassThru (
   EFI_ATA_PASS_THRU_COMMAND_PACKET        *Packet;\r
 \r
   //\r
-  // Assemble packet\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
-  Packet = &AtaDevice->Packet;\r
-  Packet->Asb = AtaDevice->Asb;\r
-  Packet->Acb = &AtaDevice->Acb;\r
-  Packet->Timeout = ATA_TIMEOUT;\r
+  if (TaskPacket != NULL) {\r
+    Packet = TaskPacket;\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
+    Packet->Acb = &AtaDevice->Acb;\r
+  }\r
 \r
   AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;\r
 \r
@@ -104,11 +147,11 @@ AtaDevicePassThru (
                           AtaDevice->Port,\r
                           AtaDevice->PortMultiplierPort,\r
                           Packet,\r
-                          NULL\r
+                          Event\r
                           );\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
@@ -121,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
@@ -134,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
@@ -148,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
@@ -164,7 +216,7 @@ PrintAtaModelName (
   CHAR8   *Source;\r
   CHAR16  *Destination;\r
 \r
-  Source = AtaDevice->IdentifyData->AtaData.ModelName;\r
+  Source = AtaDevice->IdentifyData->ModelName;\r
   Destination = AtaDevice->ModelName;\r
 \r
   //\r
@@ -198,10 +250,10 @@ GetAtapi6Capacity (
   EFI_LBA                       Capacity;\r
   EFI_LBA                       TmpLba;\r
   UINTN                         Index;\r
-  ATAPI_IDENTIFY_DATA           *IdentifyData;\r
+  ATA_IDENTIFY_DATA             *IdentifyData;\r
 \r
-  IdentifyData = (ATAPI_IDENTIFY_DATA *) AtaDevice->IdentifyData;\r
-  if ((IdentifyData->cmd_set_support_83 & BIT10) == 0) {\r
+  IdentifyData = AtaDevice->IdentifyData;\r
+  if ((IdentifyData->command_set_supported_83 & BIT10) == 0) {\r
     //\r
     // The device doesn't support 48 bit addressing\r
     //\r
@@ -216,7 +268,7 @@ GetAtapi6Capacity (
     //\r
     // Lower byte goes first: word[100] is the lowest word, word[103] is highest\r
     //\r
-    TmpLba = IdentifyData->max_user_lba_for_48bit_addr[Index];\r
+    TmpLba = IdentifyData->maximum_lba_for_48bit_addressing[Index];\r
     Capacity |= LShiftU64 (TmpLba, 16 * Index);\r
   }\r
 \r
@@ -227,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
@@ -242,13 +294,13 @@ IdentifyAtaDevice (
   IN OUT ATA_DEVICE                 *AtaDevice\r
   )\r
 {\r
-  EFI_ATA_IDENTIFY_DATA             *IdentifyData;\r
+  ATA_IDENTIFY_DATA                 *IdentifyData;\r
   EFI_BLOCK_IO_MEDIA                *BlockMedia;\r
   EFI_LBA                           Capacity;\r
   UINT16                            PhyLogicSectorSupport;\r
   UINT16                            UdmaMode;\r
 \r
-  IdentifyData = &AtaDevice->IdentifyData->AtaData;\r
+  IdentifyData = AtaDevice->IdentifyData;\r
 \r
   if ((IdentifyData->config & BIT15) != 0) {\r
     //\r
@@ -257,6 +309,8 @@ IdentifyAtaDevice (
     return EFI_UNSUPPORTED;\r
   }\r
 \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
   //\r
@@ -304,7 +358,8 @@ IdentifyAtaDevice (
       // Check lowest alignment of logical blocks within physical block\r
       //\r
       if ((IdentifyData->alignment_logic_in_phy_blocks & (BIT14 | BIT15)) == BIT14) {\r
-        BlockMedia->LowestAlignedLba = (EFI_LBA) (IdentifyData->alignment_logic_in_phy_blocks & 0x3fff);\r
+        BlockMedia->LowestAlignedLba = (EFI_LBA) ((BlockMedia->LogicalBlocksPerPhysicalBlock - ((UINT32)IdentifyData->alignment_logic_in_phy_blocks & 0x3fff)) %\r
+          BlockMedia->LogicalBlocksPerPhysicalBlock);\r
       }\r
     }\r
     //\r
@@ -316,9 +371,9 @@ 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
+  PrintAtaModelName (AtaDevice);\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -335,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
@@ -351,29 +406,29 @@ 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 == 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->Length   = EFI_ATA_PASS_THRU_LENGTH_BYTES | EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;\r
+  Packet->Timeout  = ATA_TIMEOUT;\r
 \r
   Retry = MAX_RETRY_TIMES;\r
   do {\r
-    Status = AtaDevicePassThru (AtaDevice);\r
+    Status = AtaDevicePassThru (AtaDevice, NULL, NULL);\r
     if (!EFI_ERROR (Status)) {\r
       //\r
       // 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
@@ -387,30 +442,41 @@ DiscoverAtaDevice (
   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  StartLba          The starting logical block address to be accessed.\r
-  @param  TransferLength    The block number or sector count of the transfer.\r
-  @param  IsWrite           Indicates whether it is a write operation.\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
+                                   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, out]  Buffer          The pointer to the current transaction buffer.\r
+  @param[in]       StartLba        The starting logical block address to be accessed.\r
+  @param[in]       TransferLength  The block number or sector count of the transfer.\r
+  @param[in]       IsWrite         Indicates whether it is a write operation.\r
+  @param[in]       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
+                                   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
 TransferAtaDevice (\r
-  IN OUT ATA_DEVICE                 *AtaDevice,\r
-  IN OUT VOID                       *Buffer,\r
-  IN EFI_LBA                        StartLba,\r
-  IN UINT32                         TransferLength,\r
-  IN BOOLEAN                        IsWrite\r
+  IN OUT ATA_DEVICE                       *AtaDevice,\r
+  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *TaskPacket, OPTIONAL\r
+  IN OUT VOID                             *Buffer,\r
+  IN EFI_LBA                              StartLba,\r
+  IN UINT32                               TransferLength,\r
+  IN BOOLEAN                              IsWrite,\r
+  IN EFI_EVENT                            Event OPTIONAL\r
   )\r
 {\r
   EFI_ATA_COMMAND_BLOCK             *Acb;\r
   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
@@ -418,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
@@ -437,7 +503,12 @@ TransferAtaDevice (
   //\r
   // Prepare for ATA pass through packet.\r
   //\r
-  Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet));\r
+  if (TaskPacket != NULL) {\r
+    Packet = ZeroMem (TaskPacket, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
+  } else {\r
+    Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
+  }\r
+\r
   if (IsWrite) {\r
     Packet->OutDataBuffer = Buffer;\r
     Packet->OutTransferLength = TransferLength;\r
@@ -445,10 +516,232 @@ TransferAtaDevice (
     Packet->InDataBuffer = Buffer;\r
     Packet->InTransferLength = TransferLength;\r
   }\r
+\r
   Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsWrite];\r
   Packet->Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;\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
+\r
+  @param[in, out]  Task      Pointer to task to be freed.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FreeAtaSubTask (\r
+  IN OUT ATA_BUS_ASYN_SUB_TASK  *Task\r
+  )\r
+{\r
+  if (Task->Packet.Asb != NULL) {\r
+    FreeAlignedBuffer (Task->Packet.Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
+  }\r
+  if (Task->Packet.Acb != NULL) {\r
+    FreePool (Task->Packet.Acb);\r
+  }\r
+\r
+  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 registered to the\r
+                        Event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AtaNonBlockingCallBack (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\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_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
+    Task->Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (AtaDevice->Abort) {\r
+    Task->Token->TransactionStatus = EFI_ABORTED;\r
+  }\r
+\r
+  DEBUG ((\r
+    EFI_D_BLKIO,\r
+    "NON-BLOCKING EVENT FINISHED!- STATUS = %r\n",\r
+    Task->Token->TransactionStatus\r
+    ));\r
+\r
+  //\r
+  // Reduce the SubEventCount, till it comes to zero.\r
+  //\r
+  (*Task->UnsignalledEventCount) --;\r
+  DEBUG ((EFI_D_BLKIO, "UnsignalledEventCount = %d\n", *Task->UnsignalledEventCount));\r
+\r
+  //\r
+  // Remove the SubTask from the Task list.\r
+  //\r
+  RemoveEntryList (&Task->TaskEntry);\r
+  if ((*Task->UnsignalledEventCount) == 0) {\r
+    //\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 ((EFI_D_BLKIO, "Signal the upper layer event!\n"));\r
+    }\r
+\r
+    FreePool (Task->UnsignalledEventCount);\r
+    FreePool (Task->IsError);\r
 \r
-  return AtaDevicePassThru (AtaDevice); \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
+    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
+    Task->Packet.Acb->AtaCylinderHigh,\r
+    Task->Packet.Acb->AtaSectorCount\r
+    ));\r
+\r
+  //\r
+  // Free the buffer of SubTask.\r
+  //\r
+  FreeAtaSubTask (Task);\r
 }\r
 \r
 /**\r
@@ -458,52 +751,317 @@ TransferAtaDevice (
   ATA device. It may separate the read/write request into several ATA pass through\r
   transactions.\r
 \r
-  @param  AtaDevice         The ATA child device involved for the operation.\r
-  @param  Buffer            The pointer to the current transaction buffer.\r
-  @param  StartLba          The starting logical block address to be accessed.\r
-  @param  NumberOfBlocks    The block number or sector count of the transfer.\r
-  @param  IsWrite           Indicates whether it is a write operation.\r
+  @param[in, out]  AtaDevice       The ATA child device involved for the operation.\r
+  @param[in, out]  Buffer          The pointer to the current transaction buffer.\r
+  @param[in]       StartLba        The starting logical block address to be accessed.\r
+  @param[in]       NumberOfBlocks  The block number or sector count of the transfer.\r
+  @param[in]       IsWrite         Indicates whether it is a write operation.\r
+  @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
   IN EFI_LBA                        StartLba,\r
   IN UINTN                          NumberOfBlocks,\r
-  IN BOOLEAN                        IsWrite\r
+  IN BOOLEAN                        IsWrite,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN        *Token\r
   )\r
 {\r
   EFI_STATUS                        Status;\r
   UINTN                             MaxTransferBlockNumber;\r
   UINTN                             TransferBlockNumber;\r
   UINTN                             BlockSize;\r
\r
+  ATA_BUS_ASYN_SUB_TASK             *SubTask;\r
+  UINTN                             *EventCount;\r
+  UINTN                             TempCount;\r
+  ATA_BUS_ASYN_TASK                 *AtaTask;\r
+  EFI_EVENT                         SubEvent;\r
+  UINTN                             Index;\r
+  BOOLEAN                           *IsError;\r
+  EFI_TPL                           OldTpl;\r
+\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
-  // 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
+  BlockSize              = AtaDevice->BlockMedia.BlockSize;\r
+\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
       TransferBlockNumber = MaxTransferBlockNumber;\r
-      NumberOfBlocks -= MaxTransferBlockNumber;\r
+      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
+    //\r
+    if ((Token != NULL) && (Token->Event != NULL)) {\r
+      SubTask  = NULL;\r
+      SubEvent = NULL;\r
+\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
+      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
+                      SubTask,\r
+                      &SubEvent\r
+                      );\r
+      //\r
+      // If resource allocation fail, the un-signalled event count should equal to\r
+      // the original one minus the unassigned subtasks number.\r
+      //\r
+      if (EFI_ERROR (Status)) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto EXIT;\r
+      }\r
+\r
+      Status = TransferAtaDevice (AtaDevice, &SubTask->Packet, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, SubEvent);\r
+    } else {\r
+      //\r
+      // Blocking Mode.\r
+      //\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
     }\r
 \r
-    Status = TransferAtaDevice (AtaDevice, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite);\r
     if (EFI_ERROR (Status)) {\r
-      return 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
+  @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