mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-25 22:54:51 +02:00
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. 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/trunk/edk2@19216 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
d670bf5336
commit
0350b57cf7
@ -1,6 +1,6 @@
|
|||||||
/** @file
|
/** @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
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
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
|
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
|
NULL, // Handle
|
||||||
{ // ExtScsiPassThruMode
|
{ // ExtScsiPassThruMode
|
||||||
0xFFFFFFFF,
|
0xFFFFFFFF,
|
||||||
//
|
EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO,
|
||||||
// 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,
|
|
||||||
sizeof (UINTN)
|
sizeof (UINTN)
|
||||||
},
|
},
|
||||||
{ // ExtScsiPassThru
|
{ // ExtScsiPassThru
|
||||||
@ -64,6 +61,11 @@ UFS_PASS_THRU_PRIVATE_DATA gUfsPassThruTemplate = {
|
|||||||
},
|
},
|
||||||
0x0000, // By default don't expose any Luns.
|
0x0000, // By default don't expose any Luns.
|
||||||
0x0
|
0x0
|
||||||
|
},
|
||||||
|
NULL, // TimerEvent
|
||||||
|
{ // Queue
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -212,7 +214,7 @@ UfsPassThruPassThru (
|
|||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = UfsExecScsiCmds (Private, UfsLun, Packet);
|
Status = UfsExecScsiCmds (Private, UfsLun, Packet, Event);
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
@ -816,6 +818,7 @@ UfsPassThruDriverBindingStart (
|
|||||||
//
|
//
|
||||||
Private = AllocateCopyPool (sizeof (UFS_PASS_THRU_PRIVATE_DATA), &gUfsPassThruTemplate);
|
Private = AllocateCopyPool (sizeof (UFS_PASS_THRU_PRIVATE_DATA), &gUfsPassThruTemplate);
|
||||||
if (Private == NULL) {
|
if (Private == NULL) {
|
||||||
|
DEBUG ((EFI_D_ERROR, "Unable to allocate Ufs Pass Thru private data\n"));
|
||||||
Status = EFI_OUT_OF_RESOURCES;
|
Status = EFI_OUT_OF_RESOURCES;
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
@ -823,6 +826,7 @@ UfsPassThruDriverBindingStart (
|
|||||||
Private->ExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode;
|
Private->ExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode;
|
||||||
Private->UfsHostController = UfsHc;
|
Private->UfsHostController = UfsHc;
|
||||||
Private->UfsHcBase = UfsHcBase;
|
Private->UfsHcBase = UfsHcBase;
|
||||||
|
InitializeListHead (&Private->Queue);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Initialize UFS Host Controller H/W.
|
// 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 (
|
Status = gBS->InstallProtocolInterface (
|
||||||
&Controller,
|
&Controller,
|
||||||
&gEfiExtScsiPassThruProtocolGuid,
|
&gEfiExtScsiPassThruProtocolGuid,
|
||||||
@ -899,6 +928,10 @@ Error:
|
|||||||
UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TMRD)), Private->UtpTrlBase);
|
UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TMRD)), Private->UtpTrlBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Private->TimerEvent != NULL) {
|
||||||
|
gBS->CloseEvent (Private->TimerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
FreePool (Private);
|
FreePool (Private);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -953,6 +986,9 @@ UfsPassThruDriverBindingStop (
|
|||||||
UFS_PASS_THRU_PRIVATE_DATA *Private;
|
UFS_PASS_THRU_PRIVATE_DATA *Private;
|
||||||
EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
|
EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
|
||||||
EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;
|
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));
|
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);
|
Private = UFS_PASS_THRU_PRIVATE_DATA_FROM_THIS (ExtScsiPassThru);
|
||||||
UfsHc = Private->UfsHostController;
|
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 (
|
Status = gBS->UninstallProtocolInterface (
|
||||||
Controller,
|
Controller,
|
||||||
&gEfiExtScsiPassThruProtocolGuid,
|
&gEfiExtScsiPassThruProtocolGuid,
|
||||||
@ -1002,6 +1056,10 @@ UfsPassThruDriverBindingStop (
|
|||||||
UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TMRD)), Private->UtpTrlBase);
|
UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TMRD)), Private->UtpTrlBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Private->TimerEvent != NULL) {
|
||||||
|
gBS->CloseEvent (Private->TimerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
FreePool (Private);
|
FreePool (Private);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -50,6 +50,14 @@ typedef struct {
|
|||||||
UINT16 Rsvd:4;
|
UINT16 Rsvd:4;
|
||||||
} UFS_EXPOSED_LUNS;
|
} 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 {
|
typedef struct _UFS_PASS_THRU_PRIVATE_DATA {
|
||||||
UINT32 Signature;
|
UINT32 Signature;
|
||||||
EFI_HANDLE Handle;
|
EFI_HANDLE Handle;
|
||||||
@ -69,9 +77,37 @@ typedef struct _UFS_PASS_THRU_PRIVATE_DATA {
|
|||||||
VOID *TmrlMapping;
|
VOID *TmrlMapping;
|
||||||
|
|
||||||
UFS_EXPOSED_LUNS Luns;
|
UFS_EXPOSED_LUNS Luns;
|
||||||
|
|
||||||
|
//
|
||||||
|
// For Non-blocking operation.
|
||||||
|
//
|
||||||
|
EFI_EVENT TimerEvent;
|
||||||
|
LIST_ENTRY Queue;
|
||||||
} UFS_PASS_THRU_PRIVATE_DATA;
|
} 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_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)
|
#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] 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
|
@param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
|
||||||
UFS device.
|
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
|
@retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
|
||||||
commands, InTransferLength bytes were transferred from
|
commands, InTransferLength bytes were transferred from
|
||||||
@ -603,7 +644,8 @@ EFI_STATUS
|
|||||||
UfsExecScsiCmds (
|
UfsExecScsiCmds (
|
||||||
IN UFS_PASS_THRU_PRIVATE_DATA *Private,
|
IN UFS_PASS_THRU_PRIVATE_DATA *Private,
|
||||||
IN UINT8 Lun,
|
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
|
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_NAME_PROTOCOL gUfsPassThruComponentName;
|
||||||
extern EFI_COMPONENT_NAME2_PROTOCOL gUfsPassThruComponentName2;
|
extern EFI_COMPONENT_NAME2_PROTOCOL gUfsPassThruComponentName2;
|
||||||
extern EFI_DRIVER_BINDING_PROTOCOL gUfsPassThruDriverBinding;
|
extern EFI_DRIVER_BINDING_PROTOCOL gUfsPassThruDriverBinding;
|
||||||
|
@ -729,6 +729,7 @@ UfsCreateNopCommandDesc (
|
|||||||
@param[out] Slot The available slot.
|
@param[out] Slot The available slot.
|
||||||
|
|
||||||
@retval EFI_SUCCESS The available slot was found successfully.
|
@retval EFI_SUCCESS The available slot was found successfully.
|
||||||
|
@retval EFI_NOT_READY No slot is available at this moment.
|
||||||
|
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
@ -737,15 +738,28 @@ UfsFindAvailableSlotInTrl (
|
|||||||
OUT UINT8 *Slot
|
OUT UINT8 *Slot
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
UINT8 Nutrs;
|
||||||
|
UINT8 Index;
|
||||||
|
UINT32 Data;
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
ASSERT ((Private != NULL) && (Slot != NULL));
|
ASSERT ((Private != NULL) && (Slot != NULL));
|
||||||
|
|
||||||
//
|
Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);
|
||||||
// The simplest algo to always use slot 0.
|
if (EFI_ERROR (Status)) {
|
||||||
// TODO: enhance it to support async transfer with multiple slot.
|
return Status;
|
||||||
//
|
}
|
||||||
*Slot = 0;
|
|
||||||
|
|
||||||
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] 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
|
@param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
|
||||||
UFS device.
|
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
|
@retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
|
||||||
commands, InTransferLength bytes were transferred from
|
commands, InTransferLength bytes were transferred from
|
||||||
@ -1398,19 +1417,14 @@ EFI_STATUS
|
|||||||
UfsExecScsiCmds (
|
UfsExecScsiCmds (
|
||||||
IN UFS_PASS_THRU_PRIVATE_DATA *Private,
|
IN UFS_PASS_THRU_PRIVATE_DATA *Private,
|
||||||
IN UINT8 Lun,
|
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;
|
EFI_STATUS Status;
|
||||||
UINT8 Slot;
|
|
||||||
UTP_TRD *Trd;
|
|
||||||
UINT32 CmdDescSize;
|
|
||||||
UTP_RESPONSE_UPIU *Response;
|
UTP_RESPONSE_UPIU *Response;
|
||||||
UINT16 SenseDataLen;
|
UINT16 SenseDataLen;
|
||||||
UINT32 ResTranCount;
|
UINT32 ResTranCount;
|
||||||
VOID *CmdDescHost;
|
|
||||||
VOID *CmdDescMapping;
|
|
||||||
VOID *DataBufMapping;
|
|
||||||
VOID *DataBuf;
|
VOID *DataBuf;
|
||||||
EFI_PHYSICAL_ADDRESS DataBufPhyAddr;
|
EFI_PHYSICAL_ADDRESS DataBufPhyAddr;
|
||||||
UINT32 DataLen;
|
UINT32 DataLen;
|
||||||
@ -1419,32 +1433,44 @@ UfsExecScsiCmds (
|
|||||||
EDKII_UFS_HOST_CONTROLLER_OPERATION Flag;
|
EDKII_UFS_HOST_CONTROLLER_OPERATION Flag;
|
||||||
UFS_DATA_DIRECTION DataDirection;
|
UFS_DATA_DIRECTION DataDirection;
|
||||||
UTP_TR_PRD *PrdtBase;
|
UTP_TR_PRD *PrdtBase;
|
||||||
|
EFI_TPL OldTpl;
|
||||||
|
UFS_PASS_THRU_TRANS_REQ *TransReq;
|
||||||
|
|
||||||
Trd = NULL;
|
TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));
|
||||||
CmdDescHost = NULL;
|
if (TransReq == NULL) {
|
||||||
CmdDescMapping = NULL;
|
return EFI_OUT_OF_RESOURCES;
|
||||||
DataBufMapping = NULL;
|
}
|
||||||
|
|
||||||
|
TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG;
|
||||||
|
TransReq->TimeoutRemain = Packet->Timeout;
|
||||||
DataBufPhyAddr = 0;
|
DataBufPhyAddr = 0;
|
||||||
UfsHc = Private->UfsHostController;
|
UfsHc = Private->UfsHostController;
|
||||||
//
|
//
|
||||||
// Find out which slot of transfer request list is available.
|
// Find out which slot of transfer request list is available.
|
||||||
//
|
//
|
||||||
Status = UfsFindAvailableSlotInTrl (Private, &Slot);
|
Status = UfsFindAvailableSlotInTrl (Private, &TransReq->Slot);
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
|
TransReq->Trd = ((UTP_TRD*)Private->UtpTrlBase) + TransReq->Slot;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Fill transfer request descriptor to this 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)) {
|
if (EFI_ERROR (Status)) {
|
||||||
return 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) {
|
if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
|
||||||
DataBuf = Packet->InDataBuffer;
|
DataBuf = Packet->InDataBuffer;
|
||||||
@ -1468,7 +1494,7 @@ UfsExecScsiCmds (
|
|||||||
DataBuf,
|
DataBuf,
|
||||||
&MapLength,
|
&MapLength,
|
||||||
&DataBufPhyAddr,
|
&DataBufPhyAddr,
|
||||||
&DataBufMapping
|
&TransReq->DataBufMapping
|
||||||
);
|
);
|
||||||
|
|
||||||
if (EFI_ERROR (Status) || (DataLen != MapLength)) {
|
if (EFI_ERROR (Status) || (DataLen != MapLength)) {
|
||||||
@ -1478,14 +1504,32 @@ UfsExecScsiCmds (
|
|||||||
//
|
//
|
||||||
// Fill PRDT table of Command UPIU for executed SCSI cmd.
|
// 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);
|
ASSERT (PrdtBase != NULL);
|
||||||
UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);
|
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.
|
// 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.
|
// Wait for the completion of the transfer request.
|
||||||
@ -1498,7 +1542,7 @@ UfsExecScsiCmds (
|
|||||||
//
|
//
|
||||||
// Get sense data if exists
|
// 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);
|
ASSERT (Response != NULL);
|
||||||
SenseDataLen = Response->SenseDataLen;
|
SenseDataLen = Response->SenseDataLen;
|
||||||
SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
|
SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));
|
||||||
@ -1518,7 +1562,7 @@ UfsExecScsiCmds (
|
|||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Trd->Ocs == 0) {
|
if (TransReq->Trd->Ocs == 0) {
|
||||||
if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
|
if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
|
||||||
if ((Response->Flags & BIT5) == BIT5) {
|
if ((Response->Flags & BIT5) == BIT5) {
|
||||||
ResTranCount = Response->ResTranCount;
|
ResTranCount = Response->ResTranCount;
|
||||||
@ -1539,18 +1583,21 @@ UfsExecScsiCmds (
|
|||||||
Exit:
|
Exit:
|
||||||
UfsHc->Flush (UfsHc);
|
UfsHc->Flush (UfsHc);
|
||||||
|
|
||||||
UfsStopExecCmd (Private, Slot);
|
UfsStopExecCmd (Private, TransReq->Slot);
|
||||||
|
|
||||||
if (DataBufMapping != NULL) {
|
if (TransReq->DataBufMapping != NULL) {
|
||||||
UfsHc->Unmap (UfsHc, DataBufMapping);
|
UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
Exit1:
|
Exit1:
|
||||||
if (CmdDescMapping != NULL) {
|
if (TransReq->CmdDescMapping != NULL) {
|
||||||
UfsHc->Unmap (UfsHc, CmdDescMapping);
|
UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);
|
||||||
}
|
}
|
||||||
if (CmdDescHost != NULL) {
|
if (TransReq->CmdDescHost != NULL) {
|
||||||
UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);
|
UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), TransReq->CmdDescHost);
|
||||||
|
}
|
||||||
|
if (TransReq != NULL) {
|
||||||
|
FreePool (TransReq);
|
||||||
}
|
}
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
@ -2123,3 +2170,178 @@ UfsControllerStop (
|
|||||||
return EFI_SUCCESS;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user