+\r
+/**\r
+ Internal helper function which will signal the caller event and clean up\r
+ resources.\r
+\r
+ @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data\r
+ structure.\r
+ @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data\r
+ structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SignalCallerEvent (\r
+ IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
+ IN UFS_PASS_THRU_TRANS_REQ *TransReq\r
+ )\r
+{\r
+ EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
+ EFI_EVENT CallerEvent;\r
+\r
+ UfsHc = Private->UfsHostController;\r
+ CallerEvent = TransReq->CallerEvent;\r
+\r
+ RemoveEntryList (&TransReq->TransferList);\r
+\r
+ UfsHc->Flush (UfsHc);\r
+\r
+ UfsStopExecCmd (Private, TransReq->Slot);\r
+\r
+ if (TransReq->DataBufMapping != NULL) {\r
+ UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);\r
+ }\r
+\r
+ if (TransReq->CmdDescMapping != NULL) {\r
+ UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);\r
+ }\r
+ if (TransReq->CmdDescHost != NULL) {\r
+ UfsHc->FreeBuffer (\r
+ UfsHc,\r
+ EFI_SIZE_TO_PAGES (TransReq->CmdDescSize),\r
+ TransReq->CmdDescHost\r
+ );\r
+ }\r
+ if (TransReq != NULL) {\r
+ FreePool (TransReq);\r
+ }\r
+\r
+ gBS->SignalEvent (CallerEvent);\r
+ return;\r
+}\r
+\r
+/**\r
+ Call back function when the timer 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 Event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ProcessAsyncTaskList (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ UFS_PASS_THRU_PRIVATE_DATA *Private;\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *NextEntry;\r
+ UFS_PASS_THRU_TRANS_REQ *TransReq;\r
+ EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet;\r
+ UTP_RESPONSE_UPIU *Response;\r
+ UINT16 SenseDataLen;\r
+ UINT32 ResTranCount;\r
+ UINT32 SlotsMap;\r
+ UINT32 Value;\r
+ EFI_STATUS Status;\r
+\r
+ Private = (UFS_PASS_THRU_PRIVATE_DATA*) Context;\r
+ SlotsMap = 0;\r
+\r
+ //\r
+ // Check the entries in the async I/O queue are done or not.\r
+ //\r
+ if (!IsListEmpty(&Private->Queue)) {\r
+ EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {\r
+ TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);\r
+ Packet = TransReq->Packet;\r
+\r
+ if ((SlotsMap & (BIT0 << TransReq->Slot)) != 0) {\r
+ return;\r
+ }\r
+ SlotsMap |= BIT0 << TransReq->Slot;\r
+\r
+ Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Value);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // TODO: Should find/add a proper host adapter return status for this\r
+ // case.\r
+ //\r
+ Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;\r
+ DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq->CallerEvent));\r
+ SignalCallerEvent (Private, TransReq);\r
+ continue;\r
+ }\r
+\r
+ if ((Value & (BIT0 << TransReq->Slot)) != 0) {\r
+ //\r
+ // Scsi cmd not finished yet.\r
+ //\r
+ if (TransReq->TimeoutRemain > UFS_HC_ASYNC_TIMER) {\r
+ TransReq->TimeoutRemain -= UFS_HC_ASYNC_TIMER;\r
+ continue;\r
+ } else {\r
+ //\r
+ // Timeout occurs.\r
+ //\r
+ Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;\r
+ DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq->CallerEvent));\r
+ SignalCallerEvent (Private, TransReq);\r
+ continue;\r
+ }\r
+ } else {\r
+ //\r
+ // Scsi cmd finished.\r
+ //\r
+ // Get sense data if exists\r
+ //\r
+ Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));\r
+ ASSERT (Response != NULL);\r
+ SenseDataLen = Response->SenseDataLen;\r
+ SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));\r
+\r
+ if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
+ CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
+ Packet->SenseDataLength = (UINT8)SenseDataLen;\r
+ }\r
+\r
+ //\r
+ // Check the transfer request result.\r
+ //\r
+ Packet->TargetStatus = Response->Status;\r
+ if (Response->Response != 0) {\r
+ DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq->CallerEvent));\r
+ SignalCallerEvent (Private, TransReq);\r
+ continue;\r
+ }\r
+\r
+ if (TransReq->Trd->Ocs == 0) {\r
+ if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
+ if ((Response->Flags & BIT5) == BIT5) {\r
+ ResTranCount = Response->ResTranCount;\r
+ SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
+ Packet->InTransferLength -= ResTranCount;\r
+ }\r
+ } else {\r
+ if ((Response->Flags & BIT5) == BIT5) {\r
+ ResTranCount = Response->ResTranCount;\r
+ SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
+ Packet->OutTransferLength -= ResTranCount;\r
+ }\r
+ }\r
+ } else {\r
+ DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq->CallerEvent));\r
+ SignalCallerEvent (Private, TransReq);\r
+ continue;\r
+ }\r
+\r
+ DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq->CallerEvent));\r
+ SignalCallerEvent (Private, TransReq);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r