Previously, UfsPassThruPassThru function does not handle the 'Event'
parameter and blocking read/write operations are always executed.

This commit enables non-blocking read/write feature for UFS devices.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Hao Wu <hao.a...@intel.com>
---
 MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c  |  45 +++-
 MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h  |  58 ++++-
 .../Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c        | 288 ++++++++++++++++++---
 3 files changed, 351 insertions(+), 40 deletions(-)

diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c 
b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
index 306fd37..c5f7724 100644
--- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
+++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
@@ -1,6 +1,6 @@
 /** @file
 
-  Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
   which accompanies this distribution.  The full text of the license may be 
found at
@@ -21,10 +21,7 @@ UFS_PASS_THRU_PRIVATE_DATA gUfsPassThruTemplate = {
   NULL,                           // Handle  
   {                               // ExtScsiPassThruMode
     0xFFFFFFFF,
-    //
-    // Note that the driver doesn't support ExtScsiPassThru non blocking I/O.
-    //
-    EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | 
EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,
+    EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | 
EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL | 
EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO,
     sizeof (UINTN)
   },
   {                               // ExtScsiPassThru
@@ -64,6 +61,11 @@ UFS_PASS_THRU_PRIVATE_DATA gUfsPassThruTemplate = {
     },
     0x0000,                           // By default don't expose any Luns.
     0x0
+  },
+  NULL,                           // TimerEvent
+  {                               // Queue
+    NULL,
+    NULL
   }
 };
 
@@ -212,7 +214,7 @@ UfsPassThruPassThru (
     return EFI_INVALID_PARAMETER;
   }
 
-  Status = UfsExecScsiCmds (Private, UfsLun, Packet);
+  Status = UfsExecScsiCmds (Private, UfsLun, Packet, Event);
 
   return Status;
 }
@@ -816,6 +818,7 @@ UfsPassThruDriverBindingStart (
   //
   Private = AllocateCopyPool (sizeof (UFS_PASS_THRU_PRIVATE_DATA), 
&gUfsPassThruTemplate);
   if (Private == NULL) {
+    DEBUG ((EFI_D_ERROR, "Unable to allocate Ufs Pass Thru private data\n"));
     Status = EFI_OUT_OF_RESOURCES;
     goto Error;
   }
@@ -823,6 +826,7 @@ UfsPassThruDriverBindingStart (
   Private->ExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode;
   Private->UfsHostController    = UfsHc;
   Private->UfsHcBase            = UfsHcBase;
+  InitializeListHead (&Private->Queue);
 
   //
   // Initialize UFS Host Controller H/W.
@@ -873,6 +877,31 @@ UfsPassThruDriverBindingStart (
     }
   }
 
+  //
+  // Start the asynchronous interrupt monitor
+  //
+  Status = gBS->CreateEvent (
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  ProcessAsyncTaskList,
+                  Private,
+                  &Private->TimerEvent
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Ufs Create Async Tasks Event Error, Status = %r\n", 
Status));
+    goto Error;
+  }
+
+  Status = gBS->SetTimer (
+                  Private->TimerEvent,
+                  TimerPeriodic,
+                  UFS_HC_ASYNC_TIMER
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Ufs Set Periodic Timer Error, Status = %r\n", 
Status));
+    goto Error;
+  }
+
   Status = gBS->InstallProtocolInterface (
                   &Controller,
                   &gEfiExtScsiPassThruProtocolGuid,
@@ -899,6 +928,10 @@ Error:
       UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof 
(UTP_TMRD)), Private->UtpTrlBase);
     }
 
+    if (Private->TimerEvent != NULL) {
+      gBS->CloseEvent (Private->TimerEvent);
+    }
+
     FreePool (Private);
   }
 
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h 
b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
index ce8066f..afcf7f6 100644
--- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
+++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h
@@ -50,6 +50,14 @@ typedef struct {
   UINT16   Rsvd:4;
 } UFS_EXPOSED_LUNS;
 
+//
+// Iterate through the doule linked list. This is delete-safe.
+// Do not touch NextEntry
+//
+#define EFI_LIST_FOR_EACH_SAFE(Entry, NextEntry, ListHead)            \
+  for(Entry = (ListHead)->ForwardLink, NextEntry = Entry->ForwardLink;\
+      Entry != (ListHead); Entry = NextEntry, NextEntry = Entry->ForwardLink)
+
 typedef struct _UFS_PASS_THRU_PRIVATE_DATA {  
   UINT32                              Signature;
   EFI_HANDLE                          Handle;
@@ -69,9 +77,37 @@ typedef struct _UFS_PASS_THRU_PRIVATE_DATA {
   VOID                                *TmrlMapping;
 
   UFS_EXPOSED_LUNS                    Luns;
+
+  //
+  // For Non-blocking operation.
+  //
+  EFI_EVENT                           TimerEvent;
+  LIST_ENTRY                          Queue;
 } UFS_PASS_THRU_PRIVATE_DATA;
 
+#define UFS_PASS_THRU_TRANS_REQ_SIG   SIGNATURE_32 ('U', 'F', 'S', 'T')
+
+typedef struct {
+  UINT32                                        Signature;
+  LIST_ENTRY                                    TransferList;
+
+  UINT8                                         Slot;
+  UTP_TRD                                       *Trd;
+  UINT32                                        CmdDescSize;
+  VOID                                          *CmdDescHost;
+  VOID                                          *CmdDescMapping;
+  VOID                                          *DataBufMapping;
+
+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet;
+  UINT64                                        TimeoutRemain;
+  EFI_EVENT                                     CallerEvent;
+} UFS_PASS_THRU_TRANS_REQ;
+
+#define UFS_PASS_THRU_TRANS_REQ_FROM_THIS(a) \
+    CR(a, UFS_PASS_THRU_TRANS_REQ, TransferList, UFS_PASS_THRU_TRANS_REQ_SIG)
+
 #define UFS_TIMEOUT                   EFI_TIMER_PERIOD_SECONDS(3)
+#define UFS_HC_ASYNC_TIMER            EFI_TIMER_PERIOD_MILLISECONDS(1)
 
 #define ROUNDUP8(x) (((x) % 8 == 0) ? (x) : ((x) / 8 + 1) * 8)
 
@@ -587,6 +623,11 @@ UfsPassThruGetNextTarget (
   @param[in]      Lun           The LUN of the UFS device to send the SCSI 
Request Packet.
   @param[in, out] Packet        A pointer to the SCSI Request Packet to send 
to a specified Lun of the
                                 UFS device.
+  @param[in]      Event         If nonblocking I/O is not supported then Event 
is ignored, and blocking
+                                I/O is performed. If Event is NULL, then 
blocking I/O is performed. If
+                                Event is not NULL and non blocking I/O is 
supported, then
+                                nonblocking I/O is performed, and Event will 
be signaled when the
+                                SCSI Request Packet completes.
 
   @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. 
For bi-directional
                                 commands, InTransferLength bytes were 
transferred from
@@ -603,7 +644,8 @@ EFI_STATUS
 UfsExecScsiCmds (
   IN     UFS_PASS_THRU_PRIVATE_DATA                  *Private,
   IN     UINT8                                       Lun,
-  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet,
+  IN     EFI_EVENT                                   Event    OPTIONAL
   );
 
 /**
@@ -719,6 +761,20 @@ UfsExecNopCmds (
   IN  UFS_PASS_THRU_PRIVATE_DATA       *Private
   );
 
+/**
+  Call back function when the timer event is signaled.
+
+  @param[in]  Event     The Event this notify function registered to.
+  @param[in]  Context   Pointer to the context data registered to the Event.
+
+**/
+VOID
+EFIAPI
+ProcessAsyncTaskList (
+  IN EFI_EVENT          Event,
+  IN VOID               *Context
+  );
+
 extern EFI_COMPONENT_NAME_PROTOCOL  gUfsPassThruComponentName;
 extern EFI_COMPONENT_NAME2_PROTOCOL gUfsPassThruComponentName2;
 extern EFI_DRIVER_BINDING_PROTOCOL  gUfsPassThruDriverBinding;
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c 
b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
index 9f9abab..4fbe199 100644
--- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
+++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
@@ -729,6 +729,7 @@ UfsCreateNopCommandDesc (
   @param[out] Slot          The available slot.
 
   @retval EFI_SUCCESS       The available slot was found successfully.
+  @retval EFI_NOT_READY     No slot is available at this moment.
 
 **/
 EFI_STATUS
@@ -737,15 +738,28 @@ UfsFindAvailableSlotInTrl (
      OUT UINT8                        *Slot
   )
 {
+  UINT8            Nutrs;
+  UINT8            Index;
+  UINT32           Data;
+  EFI_STATUS       Status;
+
   ASSERT ((Private != NULL) && (Slot != NULL));
 
-  //
-  // The simplest algo to always use slot 0.
-  // TODO: enhance it to support async transfer with multiple slot.
-  //
-  *Slot = 0;
+  Status  = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
 
-  return EFI_SUCCESS;
+  Nutrs   = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
+
+  for (Index = 0; Index < Nutrs; Index++) {
+    if ((Data & (BIT0 << Index)) == 0) {
+      *Slot = Index;
+      return EFI_SUCCESS;
+    }
+  }
+
+  return EFI_NOT_READY;
 }
 
 /**
@@ -1382,6 +1396,11 @@ Exit:
   @param[in]      Lun           The LUN of the UFS device to send the SCSI 
Request Packet.
   @param[in, out] Packet        A pointer to the SCSI Request Packet to send 
to a specified Lun of the
                                 UFS device.
+  @param[in]      Event         If nonblocking I/O is not supported then Event 
is ignored, and blocking
+                                I/O is performed. If Event is NULL, then 
blocking I/O is performed. If
+                                Event is not NULL and non blocking I/O is 
supported, then
+                                nonblocking I/O is performed, and Event will 
be signaled when the
+                                SCSI Request Packet completes.
 
   @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. 
For bi-directional
                                 commands, InTransferLength bytes were 
transferred from
@@ -1398,19 +1417,14 @@ EFI_STATUS
 UfsExecScsiCmds (
   IN     UFS_PASS_THRU_PRIVATE_DATA                  *Private,
   IN     UINT8                                       Lun,
-  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet,
+  IN     EFI_EVENT                                   Event    OPTIONAL
   )
 {
   EFI_STATUS                           Status;
-  UINT8                                Slot;
-  UTP_TRD                              *Trd;
-  UINT32                               CmdDescSize;
   UTP_RESPONSE_UPIU                    *Response;
   UINT16                               SenseDataLen;
   UINT32                               ResTranCount;
-  VOID                                 *CmdDescHost;
-  VOID                                 *CmdDescMapping;
-  VOID                                 *DataBufMapping;
   VOID                                 *DataBuf;
   EFI_PHYSICAL_ADDRESS                 DataBufPhyAddr;
   UINT32                               DataLen;
@@ -1419,32 +1433,44 @@ UfsExecScsiCmds (
   EDKII_UFS_HOST_CONTROLLER_OPERATION  Flag;
   UFS_DATA_DIRECTION                   DataDirection;
   UTP_TR_PRD                           *PrdtBase;
+  EFI_TPL                              OldTpl;
+  UFS_PASS_THRU_TRANS_REQ              *TransReq;
 
-  Trd            = NULL;
-  CmdDescHost    = NULL;
-  CmdDescMapping = NULL;
-  DataBufMapping = NULL;
+  TransReq       = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));
+  if (TransReq == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  TransReq->Signature     = UFS_PASS_THRU_TRANS_REQ_SIG;
+  TransReq->TimeoutRemain = Packet->Timeout;
   DataBufPhyAddr = 0;
   UfsHc          = Private->UfsHostController;
   //
   // Find out which slot of transfer request list is available.
   //
-  Status = UfsFindAvailableSlotInTrl (Private, &Slot);
+  Status = UfsFindAvailableSlotInTrl (Private, &TransReq->Slot);
   if (EFI_ERROR (Status)) {
     return Status;
   }
 
-  Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
+  TransReq->Trd = ((UTP_TRD*)Private->UtpTrlBase) + TransReq->Slot;
 
   //
   // Fill transfer request descriptor to this slot.
   //
-  Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd, &CmdDescHost, 
&CmdDescMapping);
+  Status = UfsCreateScsiCommandDesc (
+             Private,
+             Lun,
+             Packet,
+             TransReq->Trd,
+             &TransReq->CmdDescHost,
+             &TransReq->CmdDescMapping
+             );
   if (EFI_ERROR (Status)) {
     return Status;
   }
 
-  CmdDescSize = Trd->PrdtO * sizeof (UINT32) + Trd->PrdtL * sizeof 
(UTP_TR_PRD);
+  TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + 
TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD);
 
   if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
     DataBuf       = Packet->InDataBuffer;
@@ -1468,7 +1494,7 @@ UfsExecScsiCmds (
                          DataBuf,
                          &MapLength,
                          &DataBufPhyAddr,
-                         &DataBufMapping
+                         &TransReq->DataBufMapping
                          );
 
     if (EFI_ERROR (Status) || (DataLen != MapLength)) {
@@ -1478,14 +1504,32 @@ UfsExecScsiCmds (
   //
   // Fill PRDT table of Command UPIU for executed SCSI cmd.
   //
-  PrdtBase = (UTP_TR_PRD*)((UINT8*)CmdDescHost + ROUNDUP8 (sizeof 
(UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
+  PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof 
(UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
   ASSERT (PrdtBase != NULL);
   UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);
 
   //
+  // Insert the async SCSI cmd to the Async I/O list
+  //
+  if (Event != NULL) {
+    OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+    TransReq->Packet      = Packet;
+    TransReq->CallerEvent = Event;
+    InsertTailList (&Private->Queue, &TransReq->TransferList);
+    gBS->RestoreTPL (OldTpl);
+  }
+
+  //
   // Start to execute the transfer request.
   //
-  UfsStartExecCmd (Private, Slot);
+  UfsStartExecCmd (Private, TransReq->Slot);
+
+  //
+  // Immediately return for async I/O.
+  //
+  if (Event != NULL) {
+    return EFI_SUCCESS;
+  }
 
   //
   // Wait for the completion of the transfer request.
@@ -1498,7 +1542,7 @@ UfsExecScsiCmds (
   //
   // Get sense data if exists
   //
-  Response     = (UTP_RESPONSE_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof 
(UINT32));
+  Response     = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + 
TransReq->Trd->RuO * sizeof (UINT32));
   ASSERT (Response != NULL);
   SenseDataLen = Response->SenseDataLen;
   SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
@@ -1518,7 +1562,7 @@ UfsExecScsiCmds (
     goto Exit;
   }
 
-  if (Trd->Ocs == 0) {
+  if (TransReq->Trd->Ocs == 0) {
     if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
       if ((Response->Flags & BIT5) == BIT5) {
         ResTranCount = Response->ResTranCount;
@@ -1539,18 +1583,21 @@ UfsExecScsiCmds (
 Exit:
   UfsHc->Flush (UfsHc);
 
-  UfsStopExecCmd (Private, Slot);
+  UfsStopExecCmd (Private, TransReq->Slot);
 
-  if (DataBufMapping != NULL) {
-    UfsHc->Unmap (UfsHc, DataBufMapping);
+  if (TransReq->DataBufMapping != NULL) {
+    UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);
   }
 
 Exit1:
-  if (CmdDescMapping != NULL) {
-    UfsHc->Unmap (UfsHc, CmdDescMapping);
+  if (TransReq->CmdDescMapping != NULL) {
+    UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
   }
-  if (CmdDescHost != NULL) {
-    UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);
+  if (TransReq->CmdDescHost != NULL) {
+    UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), 
TransReq->CmdDescHost);
+  }
+  if (TransReq != NULL) {
+    FreePool (TransReq);
   }
   return Status;
 }
@@ -2123,3 +2170,178 @@ UfsControllerStop (
   return EFI_SUCCESS;
 }
 
+
+/**
+  Internal helper function which will signal the caller event and clean up
+  resources.
+
+  @param[in] Private   The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
+                       structure.
+  @param[in] TransReq  The pointer to the UFS_PASS_THRU_TRANS_REQ data
+                       structure.
+
+**/
+VOID
+EFIAPI
+SignalCallerEvent (
+  IN UFS_PASS_THRU_PRIVATE_DATA      *Private,
+  IN UFS_PASS_THRU_TRANS_REQ         *TransReq
+  )
+{
+  EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
+  EFI_EVENT                          CallerEvent;
+
+  UfsHc        = Private->UfsHostController;
+  CallerEvent  = TransReq->CallerEvent;
+
+  RemoveEntryList (&TransReq->TransferList);
+
+  UfsHc->Flush (UfsHc);
+
+  UfsStopExecCmd (Private, TransReq->Slot);
+
+  if (TransReq->DataBufMapping != NULL) {
+    UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);
+  }
+
+  if (TransReq->CmdDescMapping != NULL) {
+    UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
+  }
+  if (TransReq->CmdDescHost != NULL) {
+    UfsHc->FreeBuffer (
+             UfsHc,
+             EFI_SIZE_TO_PAGES (TransReq->CmdDescSize),
+             TransReq->CmdDescHost
+             );
+  }
+  if (TransReq != NULL) {
+    FreePool (TransReq);
+  }
+
+  gBS->SignalEvent (CallerEvent);
+  return;
+}
+
+/**
+  Call back function when the timer event is signaled.
+
+  @param[in]  Event     The Event this notify function registered to.
+  @param[in]  Context   Pointer to the context data registered to the Event.
+
+**/
+VOID
+EFIAPI
+ProcessAsyncTaskList (
+  IN EFI_EVENT          Event,
+  IN VOID               *Context
+  )
+{
+  UFS_PASS_THRU_PRIVATE_DATA                    *Private;
+  LIST_ENTRY                                    *Entry;
+  LIST_ENTRY                                    *NextEntry;
+  UFS_PASS_THRU_TRANS_REQ                       *TransReq;
+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet;
+  UTP_RESPONSE_UPIU                             *Response;
+  UINT16                                        SenseDataLen;
+  UINT32                                        ResTranCount;
+  UINT32                                        SlotsMap;
+  UINT32                                        Value;
+  EFI_STATUS                                    Status;
+
+  Private   = (UFS_PASS_THRU_PRIVATE_DATA*) Context;
+  SlotsMap  = 0;
+
+  //
+  // Check the entries in the async I/O queue are done or not.
+  //
+  if (!IsListEmpty(&Private->Queue)) {
+    EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {
+      TransReq  = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);
+      Packet    = TransReq->Packet;
+
+      if ((SlotsMap & (BIT0 << TransReq->Slot)) != 0) {
+        return;
+      }
+      SlotsMap |= BIT0 << TransReq->Slot;
+
+      Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Value);
+      if (EFI_ERROR (Status)) {
+        //
+        // TODO: Should find/add a proper host adapter return status for this
+        // case.
+        //
+        Packet->HostAdapterStatus = 
EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;
+        DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p 
UfsMmioRead32() Error.\n", TransReq->CallerEvent));
+        SignalCallerEvent (Private, TransReq);
+        continue;
+      }
+
+      if ((Value & (BIT0 << TransReq->Slot)) != 0) {
+        //
+        // Scsi cmd not finished yet.
+        //
+        if (TransReq->TimeoutRemain > UFS_HC_ASYNC_TIMER) {
+          TransReq->TimeoutRemain -= UFS_HC_ASYNC_TIMER;
+          continue;
+        } else {
+          //
+          // Timeout occurs.
+          //
+          Packet->HostAdapterStatus = 
EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;
+          DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p 
EFI_TIMEOUT.\n", TransReq->CallerEvent));
+          SignalCallerEvent (Private, TransReq);
+          continue;
+        }
+      } else {
+        //
+        // Scsi cmd finished.
+        //
+        // Get sense data if exists
+        //
+        Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + 
TransReq->Trd->RuO * sizeof (UINT32));
+        ASSERT (Response != NULL);
+        SenseDataLen = Response->SenseDataLen;
+        SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
+
+        if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {
+          CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);
+          Packet->SenseDataLength = (UINT8)SenseDataLen;
+        }
+
+        //
+        // Check the transfer request result.
+        //
+        Packet->TargetStatus = Response->Status;
+        if (Response->Response != 0) {
+          DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p 
Target Failure.\n", TransReq->CallerEvent));
+          SignalCallerEvent (Private, TransReq);
+          continue;
+        }
+
+        if (TransReq->Trd->Ocs == 0) {
+          if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+            if ((Response->Flags & BIT5) == BIT5) {
+              ResTranCount = Response->ResTranCount;
+              SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof 
(UINT32));
+              Packet->InTransferLength -= ResTranCount;
+            }
+          } else {
+            if ((Response->Flags & BIT5) == BIT5) {
+              ResTranCount = Response->ResTranCount;
+              SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof 
(UINT32));
+              Packet->OutTransferLength -= ResTranCount;
+            }
+          }
+        } else {
+          DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p 
Target Device Error.\n", TransReq->CallerEvent));
+          SignalCallerEvent (Private, TransReq);
+          continue;
+        }
+
+        DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p 
Success.\n", TransReq->CallerEvent));
+        SignalCallerEvent (Private, TransReq);
+      }
+    }
+  }
+}
+
-- 
1.9.5.msysgit.0

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to