]> 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 0045cc0d91658f84242a4734ec730e8102a5ed21..fd483cb9a465cf3f00a650697b1fd9473d064acd 100644 (file)
   for Security Protocol Specific layout. This implementation uses big endian for\r
   Cylinder register.\r
 \r
-  Copyright (c) 2009 - 2012, 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) 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
@@ -133,6 +128,10 @@ AtaDevicePassThru (
   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
@@ -181,6 +180,15 @@ ResetAtaDevice (
 \r
   AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;\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
@@ -400,7 +408,7 @@ DiscoverAtaDevice (
   //\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
@@ -420,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
@@ -483,7 +489,7 @@ TransferAtaDevice (
   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
@@ -513,7 +519,38 @@ 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
@@ -540,6 +577,62 @@ 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
@@ -575,6 +668,11 @@ AtaNonBlockingCallBack (
   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
@@ -610,7 +708,7 @@ AtaNonBlockingCallBack (
     //\r
     if (!IsListEmpty (&AtaDevice->AtaTaskList)) {\r
       Entry   = GetFirstNode (&AtaDevice->AtaTaskList);\r
-      AtaTask = ATA_AYNS_TASK_FROM_ENTRY (Entry);\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
@@ -695,7 +793,7 @@ AccessAtaDevice(
   SubTask    = NULL;\r
   SubEvent   = NULL;\r
   AtaTask    = NULL;\r
-  \r
+\r
   //\r
   // Ensure AtaDevice->Lba48Bit is a valid boolean value\r
   //\r
@@ -708,6 +806,7 @@ AccessAtaDevice(
   //\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
@@ -746,7 +845,7 @@ AccessAtaDevice(
     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
+  } else {\r
     while (!IsListEmpty (&AtaDevice->AtaTaskList) || !IsListEmpty (&AtaDevice->AtaSubTaskList)) {\r
       //\r
       // Stall for 100us.\r
@@ -922,7 +1021,7 @@ TrustTransferAtaDevice (
   //\r
   Acb->AtaCylinderHigh  = (UINT8) SecurityProtocolSpecificData;\r
   Acb->AtaCylinderLow   = (UINT8) (SecurityProtocolSpecificData >> 8);\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
@@ -939,6 +1038,10 @@ TrustTransferAtaDevice (
     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