summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus
diff options
context:
space:
mode:
authorHao Wu <hao.a.wu@intel.com>2015-12-11 07:35:31 +0000
committervanjeff <vanjeff@Edk2>2015-12-11 07:35:31 +0000
commitc3a1d5980474c31dcdb0742a190f35fe7251aca3 (patch)
tree8b233baaef176c1c0b25f4ae82051cd2b423b0f1 /MdeModulePkg/Bus
parent6a14da57ac9737d268ee6abe156008b862146ef9 (diff)
downloadedk2-platforms-c3a1d5980474c31dcdb0742a190f35fe7251aca3.tar.xz
MdeModulePkg UfsPassThruDxe: Add Non-blocking I/O Support
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. (Sync patch r19216 from main trunk.) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Feng Tian <feng.tian@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/branches/UDK2015@19223 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Bus')
-rw-r--r--MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c70
-rw-r--r--MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h75
-rw-r--r--MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c288
3 files changed, 393 insertions, 40 deletions
diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.c
index 306fd37a29..aa40e27470 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);
}
@@ -953,6 +986,9 @@ UfsPassThruDriverBindingStop (
UFS_PASS_THRU_PRIVATE_DATA *Private;
EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
+ UFS_PASS_THRU_TRANS_REQ *TransReq;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
DEBUG ((EFI_D_INFO, "==UfsPassThru Stop== Controller Controller = %x\n", Controller));
@@ -972,6 +1008,24 @@ UfsPassThruDriverBindingStop (
Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (ExtScsiPassThru);
UfsHc = Private->UfsHostController;
+ //
+ // Cleanup the resources of I/O requests in the async I/O queue
+ //
+ if (!IsListEmpty(&Private->Queue)) {
+ EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {
+ TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);
+
+ //
+ // TODO: Should find/add a proper host adapter return status for this
+ // case.
+ //
+ TransReq->Packet->HostAdapterStatus =
+ EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;
+
+ SignalCallerEvent (Private, TransReq);
+ }
+ }
+
Status = gBS->UninstallProtocolInterface (
Controller,
&gEfiExtScsiPassThruProtocolGuid,
@@ -1002,6 +1056,10 @@ UfsPassThruDriverBindingStop (
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 ce8066f71e..4f7087f44f 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,37 @@ 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
+ );
+
+/**
+ 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
+ );
+
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 9f9abab40f..4fbe199390 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);
+ }
+ }
+ }
+}
+