]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
MdeModulePkg/UfsPassThruDxe: Refactor private data to use UfsHcInfo
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsPassThruDxe / UfsPassThruHci.c
index 4b93821f38aa7abe54b73766ba6eceb5c4a62639..74be3efc411b05b28133a0f970be94b64f2ae7dd 100644 (file)
@@ -2,7 +2,7 @@
   UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface\r
   for upper layer application to execute UFS-supported SCSI cmds.\r
 \r
-  Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>\r
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
@@ -394,17 +394,13 @@ UfsInitUtpPrdt (
   UINT8      *Remaining;\r
   UINTN      PrdtNumber;\r
 \r
-  if ((BufferSize & (BIT0 | BIT1)) != 0) {\r
-    BufferSize &= ~(BIT0 | BIT1);\r
-    DEBUG ((DEBUG_WARN, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize));\r
-  }\r
+  ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);\r
+  ASSERT ((BufferSize & (BIT1 | BIT0)) == 0);\r
 \r
   if (BufferSize == 0) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
-  ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);\r
-\r
   RemainingLen = BufferSize;\r
   Remaining    = Buffer;\r
   PrdtNumber   = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
@@ -735,7 +731,7 @@ UfsFindAvailableSlotInTrl (
     return Status;\r
   }\r
 \r
-  Nutrs   = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
+  Nutrs   = (UINT8)((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
 \r
   for (Index = 0; Index < Nutrs; Index++) {\r
     if ((Data & (BIT0 << Index)) == 0) {\r
@@ -1317,6 +1313,143 @@ Exit:
   return Status;\r
 }\r
 \r
+/**\r
+  Cleanup data buffers after data transfer. This function\r
+  also takes care to copy all data to user memory pool for\r
+  unaligned data transfers.\r
+\r
+  @param[in] Private   Pointer to the UFS_PASS_THRU_PRIVATE_DATA\r
+  @param[in] TransReq  Pointer to the transfer request\r
+**/\r
+VOID\r
+UfsReconcileDataTransferBuffer (\r
+  IN UFS_PASS_THRU_PRIVATE_DATA  *Private,\r
+  IN UFS_PASS_THRU_TRANS_REQ     *TransReq\r
+  )\r
+{\r
+  if (TransReq->DataBufMapping != NULL) {\r
+    Private->UfsHostController->Unmap (\r
+                                  Private->UfsHostController,\r
+                                  TransReq->DataBufMapping\r
+                                  );\r
+  }\r
+\r
+  //\r
+  // Check if unaligned transfer was performed. If it was and we read\r
+  // data from device copy memory to user data buffers before cleanup.\r
+  // The assumption is if auxiliary aligned data buffer is not NULL then\r
+  // unaligned transfer has been performed.\r
+  //\r
+  if (TransReq->AlignedDataBuf != NULL) {\r
+    if (TransReq->Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
+      CopyMem (TransReq->Packet->InDataBuffer, TransReq->AlignedDataBuf, TransReq->Packet->InTransferLength);\r
+    }\r
+    //\r
+    // Wipe out the transfer buffer in case it contains sensitive data.\r
+    //\r
+    ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize);\r
+    FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES (TransReq->AlignedDataBufSize));\r
+    TransReq->AlignedDataBuf = NULL;\r
+  }\r
+}\r
+\r
+/**\r
+  Prepare data buffer for transfer.\r
+\r
+  @param[in]      Private   Pointer to the UFS_PASS_THRU_PRIVATE_DATA\r
+  @param[in, out] TransReq  Pointer to the transfer request\r
+\r
+  @retval EFI_DEVICE_ERROR  Failed to prepare buffer for transfer\r
+  @retval EFI_SUCCESS       Buffer ready for transfer\r
+**/\r
+EFI_STATUS\r
+UfsPrepareDataTransferBuffer (\r
+  IN     UFS_PASS_THRU_PRIVATE_DATA  *Private,\r
+  IN OUT UFS_PASS_THRU_TRANS_REQ     *TransReq\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  VOID                                 *DataBuf;\r
+  UINT32                               DataLen;\r
+  UINTN                                MapLength;\r
+  EFI_PHYSICAL_ADDRESS                 DataBufPhyAddr;\r
+  EDKII_UFS_HOST_CONTROLLER_OPERATION  Flag;\r
+  UTP_TR_PRD                           *PrdtBase;\r
+\r
+  DataBufPhyAddr = 0;\r
+  DataBuf        = NULL;\r
+\r
+  //\r
+  // For unaligned data transfers we allocate auxiliary DWORD aligned memory pool.\r
+  // When command is finished auxiliary memory pool is copied into actual user memory.\r
+  // This is requiered to assure data transfer safety(DWORD alignment required by UFS spec.)\r
+  //\r
+  if (TransReq->Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
+    if (((UINTN)TransReq->Packet->InDataBuffer % 4 != 0) || (TransReq->Packet->InTransferLength % 4 != 0)) {\r
+      DataLen = TransReq->Packet->InTransferLength + (4 - (TransReq->Packet->InTransferLength % 4));\r
+      DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4);\r
+      if (DataBuf == NULL) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      ZeroMem (DataBuf, DataLen);\r
+      TransReq->AlignedDataBuf = DataBuf;\r
+      TransReq->AlignedDataBufSize = DataLen;\r
+    } else {\r
+      DataLen       = TransReq->Packet->InTransferLength;\r
+      DataBuf       = TransReq->Packet->InDataBuffer;\r
+    }\r
+    Flag          = EdkiiUfsHcOperationBusMasterWrite;\r
+  } else {\r
+    if (((UINTN)TransReq->Packet->OutDataBuffer % 4 != 0) || (TransReq->Packet->OutTransferLength % 4 != 0)) {\r
+      DataLen = TransReq->Packet->OutTransferLength + (4 - (TransReq->Packet->OutTransferLength % 4));\r
+      DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4);\r
+      if (DataBuf == NULL) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      CopyMem (DataBuf, TransReq->Packet->OutDataBuffer, TransReq->Packet->OutTransferLength);\r
+      TransReq->AlignedDataBuf = DataBuf;\r
+      TransReq->AlignedDataBufSize = DataLen;\r
+    } else {\r
+      DataLen       = TransReq->Packet->OutTransferLength;\r
+      DataBuf       = TransReq->Packet->OutDataBuffer;\r
+    }\r
+    Flag          = EdkiiUfsHcOperationBusMasterRead;\r
+  }\r
+\r
+  if (DataLen != 0) {\r
+    MapLength = DataLen;\r
+    Status    = Private->UfsHostController->Map (\r
+                                              Private->UfsHostController,\r
+                                              Flag,\r
+                                              DataBuf,\r
+                                              &MapLength,\r
+                                              &DataBufPhyAddr,\r
+                                              &TransReq->DataBufMapping\r
+                                              );\r
+\r
+    if (EFI_ERROR (Status) || (DataLen != MapLength)) {\r
+      if (TransReq->AlignedDataBuf != NULL) {\r
+        //\r
+        // Wipe out the transfer buffer in case it contains sensitive data.\r
+        //\r
+        ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize);\r
+        FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES (TransReq->AlignedDataBufSize));\r
+        TransReq->AlignedDataBuf = NULL;\r
+      }\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Fill PRDT table of Command UPIU for executed SCSI cmd.\r
+  //\r
+  PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));\r
+  ASSERT (PrdtBase != NULL);\r
+  UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.\r
 \r
@@ -1353,24 +1486,19 @@ UfsExecScsiCmds (
   UTP_RESPONSE_UPIU                    *Response;\r
   UINT16                               SenseDataLen;\r
   UINT32                               ResTranCount;\r
-  VOID                                 *DataBuf;\r
-  EFI_PHYSICAL_ADDRESS                 DataBufPhyAddr;\r
-  UINT32                               DataLen;\r
-  UINTN                                MapLength;\r
-  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *UfsHc;\r
-  EDKII_UFS_HOST_CONTROLLER_OPERATION  Flag;\r
-  UTP_TR_PRD                           *PrdtBase;\r
   EFI_TPL                              OldTpl;\r
   UFS_PASS_THRU_TRANS_REQ              *TransReq;\r
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *UfsHc;\r
 \r
-  TransReq       = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));\r
+  TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));\r
   if (TransReq == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
   TransReq->Signature     = UFS_PASS_THRU_TRANS_REQ_SIG;\r
   TransReq->TimeoutRemain = Packet->Timeout;\r
-  DataBufPhyAddr = 0;\r
+  TransReq->Packet        = Packet;\r
+\r
   UfsHc          = Private->UfsHostController;\r
   //\r
   // Find out which slot of transfer request list is available.\r
@@ -1399,44 +1527,16 @@ UfsExecScsiCmds (
 \r
   TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD);\r
 \r
-  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
-    DataBuf       = Packet->InDataBuffer;\r
-    DataLen       = Packet->InTransferLength;\r
-    Flag          = EdkiiUfsHcOperationBusMasterWrite;\r
-  } else {\r
-    DataBuf       = Packet->OutDataBuffer;\r
-    DataLen       = Packet->OutTransferLength;\r
-    Flag          = EdkiiUfsHcOperationBusMasterRead;\r
-  }\r
-\r
-  if (DataLen != 0) {\r
-    MapLength = DataLen;\r
-    Status    = UfsHc->Map (\r
-                         UfsHc,\r
-                         Flag,\r
-                         DataBuf,\r
-                         &MapLength,\r
-                         &DataBufPhyAddr,\r
-                         &TransReq->DataBufMapping\r
-                         );\r
-\r
-    if (EFI_ERROR (Status) || (DataLen != MapLength)) {\r
-      goto Exit1;\r
-    }\r
+  Status = UfsPrepareDataTransferBuffer (Private, TransReq);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit1;\r
   }\r
-  //\r
-  // Fill PRDT table of Command UPIU for executed SCSI cmd.\r
-  //\r
-  PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));\r
-  ASSERT (PrdtBase != NULL);\r
-  UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);\r
 \r
   //\r
   // Insert the async SCSI cmd to the Async I/O list\r
   //\r
   if (Event != NULL) {\r
     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
-    TransReq->Packet      = Packet;\r
     TransReq->CallerEvent = Event;\r
     InsertTailList (&Private->Queue, &TransReq->TransferList);\r
     gBS->RestoreTPL (OldTpl);\r
@@ -1515,9 +1615,7 @@ Exit:
 \r
   UfsStopExecCmd (Private, TransReq->Slot);\r
 \r
-  if (TransReq->DataBufMapping != NULL) {\r
-    UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);\r
-  }\r
+  UfsReconcileDataTransferBuffer (Private, TransReq);\r
 \r
 Exit1:\r
   if (TransReq->CmdDescMapping != NULL) {\r
@@ -1532,28 +1630,20 @@ Exit1:
   return Status;\r
 }\r
 \r
-\r
 /**\r
-  Sent UIC DME_LINKSTARTUP command to start the link startup procedure.\r
+  Send UIC command.\r
 \r
-  @param[in] Private          The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
-  @param[in] UicOpcode        The opcode of the UIC command.\r
-  @param[in] Arg1             The value for 1st argument of the UIC command.\r
-  @param[in] Arg2             The value for 2nd argument of the UIC command.\r
-  @param[in] Arg3             The value for 3rd argument of the UIC command.\r
+  @param[in]      Private     The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
+  @param[in, out] UicCommand  UIC command descriptor. On exit contains UIC command results.\r
 \r
   @return EFI_SUCCESS      Successfully execute this UIC command and detect attached UFS device.\r
   @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.\r
-  @return EFI_NOT_FOUND    The presence of the UFS device isn't detected.\r
 \r
 **/\r
 EFI_STATUS\r
 UfsExecUicCommands (\r
   IN  UFS_PASS_THRU_PRIVATE_DATA    *Private,\r
-  IN  UINT8                         UicOpcode,\r
-  IN  UINT32                        Arg1,\r
-  IN  UINT32                        Arg2,\r
-  IN  UINT32                        Arg3\r
+  IN OUT EDKII_UIC_COMMAND          *UicCommand\r
   )\r
 {\r
   EFI_STATUS  Status;\r
@@ -1579,17 +1669,17 @@ UfsExecUicCommands (
   // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)\r
   // are set.\r
   //\r
-  Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, Arg1);\r
+  Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, UicCommand->Arg1);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, Arg2);\r
+  Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, UicCommand->Arg2);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, Arg3);\r
+  Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, UicCommand->Arg3);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -1602,7 +1692,7 @@ UfsExecUicCommands (
     return Status;\r
   }\r
 \r
-  Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, (UINT32)UicOpcode);\r
+  Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, UicCommand->Opcode);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -1616,37 +1706,23 @@ UfsExecUicCommands (
     return Status;\r
   }\r
 \r
-  if (UicOpcode != UfsUicDmeReset) {\r
-    Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &Data);\r
+  if (UicCommand->Opcode != UfsUicDmeReset) {\r
+    Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &UicCommand->Arg2);\r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
-    if ((Data & 0xFF) != 0) {\r
+    Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG3_OFFSET, &UicCommand->Arg3);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    if ((UicCommand->Arg2 & 0xFF) != 0) {\r
       DEBUG_CODE_BEGIN();\r
-        DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));\r
+        DumpUicCmdExecResult ((UINT8)UicCommand->Opcode, (UINT8)(UicCommand->Arg2 & 0xFF));\r
       DEBUG_CODE_END();\r
       return EFI_DEVICE_ERROR;\r
     }\r
   }\r
 \r
-  //\r
-  // Check value of HCS.DP and make sure that there is a device attached to the Link.\r
-  //\r
-  Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
-  if ((Data & UFS_HC_HCS_DP) == 0) {\r
-    Status  = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);\r
-    if (EFI_ERROR (Status)) {\r
-      return EFI_DEVICE_ERROR;\r
-    }\r
-    return EFI_NOT_FOUND;\r
-  }\r
-\r
-  DEBUG ((DEBUG_INFO, "UfsPassThruDxe: found a attached UFS device\n"));\r
-\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -1678,7 +1754,7 @@ UfsAllocateAlignCommonBuffer (
   BOOLEAN                              Is32BitAddr;\r
   EDKII_UFS_HOST_CONTROLLER_PROTOCOL   *UfsHc;\r
 \r
-  if ((Private->Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {\r
+  if ((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {\r
     Is32BitAddr = FALSE;\r
   } else {\r
     Is32BitAddr = TRUE;\r
@@ -1820,31 +1896,41 @@ UfsDeviceDetection (
   IN  UFS_PASS_THRU_PRIVATE_DATA     *Private\r
   )\r
 {\r
-  UINTN                  Retry;\r
-  EFI_STATUS             Status;\r
+  UINTN              Retry;\r
+  EFI_STATUS         Status;\r
+  UINT32             Data;\r
+  EDKII_UIC_COMMAND  LinkStartupCommand;\r
 \r
   //\r
   // Start UFS device detection.\r
   // Try up to 3 times for establishing data link with device.\r
   //\r
   for (Retry = 0; Retry < 3; Retry++) {\r
-    Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);\r
-    if (!EFI_ERROR (Status)) {\r
-      break;\r
+    LinkStartupCommand.Opcode = UfsUicDmeLinkStartup;\r
+    LinkStartupCommand.Arg1 = 0;\r
+    LinkStartupCommand.Arg2 = 0;\r
+    LinkStartupCommand.Arg3 = 0;\r
+    Status = UfsExecUicCommands (Private, &LinkStartupCommand);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
     }\r
 \r
-    if (Status == EFI_NOT_FOUND) {\r
-      continue;\r
+    Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
     }\r
 \r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-\r
-  if (Retry == 3) {\r
-    return EFI_NOT_FOUND;\r
+    if ((Data & UFS_HC_HCS_DP) == 0) {\r
+      Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);\r
+      if (EFI_ERROR (Status)) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+    } else {\r
+      return EFI_SUCCESS;\r
+    }\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  return EFI_NOT_FOUND;\r
 }\r
 \r
 /**\r
@@ -1861,7 +1947,6 @@ UfsInitTaskManagementRequestList (
   IN  UFS_PASS_THRU_PRIVATE_DATA     *Private\r
   )\r
 {\r
-  UINT32                 Data;\r
   UINT8                  Nutmrs;\r
   VOID                   *CmdDescHost;\r
   EFI_PHYSICAL_ADDRESS   CmdDescPhyAddr;\r
@@ -1875,17 +1960,10 @@ UfsInitTaskManagementRequestList (
   CmdDescMapping = NULL;\r
   CmdDescPhyAddr = 0;\r
 \r
-  Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
-  Private->Capabilities = Data;\r
-\r
   //\r
   // Allocate and initialize UTP Task Management Request List.\r
   //\r
-  Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);\r
+  Nutmrs = (UINT8) (RShiftU64 ((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);\r
   Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
@@ -1934,7 +2012,6 @@ UfsInitTransferRequestList (
   IN  UFS_PASS_THRU_PRIVATE_DATA     *Private\r
   )\r
 {\r
-  UINT32                 Data;\r
   UINT8                  Nutrs;\r
   VOID                   *CmdDescHost;\r
   EFI_PHYSICAL_ADDRESS   CmdDescPhyAddr;\r
@@ -1948,17 +2025,10 @@ UfsInitTransferRequestList (
   CmdDescMapping = NULL;\r
   CmdDescPhyAddr = 0;\r
 \r
-  Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
-  Private->Capabilities = Data;\r
-\r
   //\r
   // Allocate and initialize UTP Transfer Request List.\r
   //\r
-  Nutrs  = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
+  Nutrs  = (UINT8)((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
   Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
@@ -2100,7 +2170,6 @@ UfsControllerStop (
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
 /**\r
   Internal helper function which will signal the caller event and clean up\r
   resources.\r
@@ -2132,9 +2201,7 @@ SignalCallerEvent (
 \r
   UfsStopExecCmd (Private, TransReq->Slot);\r
 \r
-  if (TransReq->DataBufMapping != NULL) {\r
-    UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);\r
-  }\r
+  UfsReconcileDataTransferBuffer (Private, TransReq);\r
 \r
   if (TransReq->CmdDescMapping != NULL) {\r
     UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);\r
@@ -2283,3 +2350,36 @@ ProcessAsyncTaskList (
   }\r
 }\r
 \r
+/**\r
+  Initializes UfsHcInfo field in private data.\r
+\r
+  @param[in] Private  Pointer to host controller private data.\r
+\r
+  @retval EFI_SUCCESS  UfsHcInfo initialized successfully.\r
+  @retval Others       Failed to initalize UfsHcInfo.\r
+**/\r
+EFI_STATUS\r
+GetUfsHcInfo (\r
+  IN UFS_PASS_THRU_PRIVATE_DATA  *Private\r
+  )\r
+{\r
+  UINT32      Data;\r
+  EFI_STATUS  Status;\r
+\r
+  Status = UfsMmioRead32 (Private, UFS_HC_VER_OFFSET, &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Private->UfsHcInfo.Version = Data;\r
+\r
+  Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Private->UfsHcInfo.Capabilities = Data;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r