2 UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface
3 for upper layer application to execute UFS-supported SCSI cmds.
5 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "UfsPassThru.h"
19 Read 32bits data from specified UFS MMIO register.
21 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
22 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
24 @param[out] Value The data buffer to store.
26 @retval EFI_TIMEOUT The operation is time out.
27 @retval EFI_SUCCESS The operation succeeds.
28 @retval Others The operation fails.
33 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
38 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
41 UfsHc
= Private
->UfsHostController
;
43 Status
= UfsHc
->Read (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, Value
);
49 Write 32bits data to specified UFS MMIO register.
51 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
52 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
54 @param[in] Value The data to write.
56 @retval EFI_TIMEOUT The operation is time out.
57 @retval EFI_SUCCESS The operation succeeds.
58 @retval Others The operation fails.
63 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
68 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
71 UfsHc
= Private
->UfsHostController
;
73 Status
= UfsHc
->Write (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, &Value
);
79 Wait for the value of the specified system memory set to the test value.
81 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
82 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
84 @param[in] MaskValue The mask value of memory.
85 @param[in] TestValue The test value of memory.
86 @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.
88 @retval EFI_TIMEOUT The system memory setting is time out.
89 @retval EFI_SUCCESS The system memory is correct set.
90 @retval Others The operation fails.
95 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
104 BOOLEAN InfiniteWait
;
110 InfiniteWait
= FALSE
;
113 Delay
= DivU64x32 (Timeout
, 10) + 1;
117 // Access PCI MMIO space to see if the value is the tested one.
119 Status
= UfsMmioRead32 (Private
, Offset
, &Value
);
120 if (EFI_ERROR (Status
)) {
126 if (Value
== TestValue
) {
131 // Stall for 1 microseconds.
133 MicroSecondDelay (1);
137 } while (InfiniteWait
|| (Delay
> 0));
143 Dump UIC command execution result for debugging.
145 @param[in] UicOpcode The executed UIC opcode.
146 @param[in] Result The result to be parsed.
150 DumpUicCmdExecResult (
155 if (UicOpcode
<= UfsUicDmePeerSet
) {
160 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
163 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
166 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
169 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
172 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BAD_INDEX\n"));
175 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
178 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
181 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
184 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BUSY\n"));
187 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - DME_FAILURE\n"));
198 DEBUG ((DEBUG_VERBOSE
, "UIC control command fails - FAILURE\n"));
208 Dump QUERY RESPONSE UPIU result for debugging.
210 @param[in] Result The result to be parsed.
214 DumpQueryResponseResult (
220 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Not Readable\n"));
223 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Not Writeable\n"));
226 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Already Written\n"));
229 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Length\n"));
232 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Value\n"));
235 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Selector\n"));
238 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Index\n"));
241 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Idn\n"));
244 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Opcode\n"));
247 DEBUG ((DEBUG_VERBOSE
, "Query Response with General Failure\n"));
256 Swap little endian to big endian.
258 @param[in, out] Buffer The data buffer. In input, it contains little endian data.
259 In output, it will become big endian.
260 @param[in] BufferSize The length of converted data.
264 SwapLittleEndianToBigEndian (
265 IN OUT UINT8
*Buffer
,
273 SwapCount
= BufferSize
/ 2;
274 for (Index
= 0; Index
< SwapCount
; Index
++) {
275 Temp
= Buffer
[Index
];
276 Buffer
[Index
] = Buffer
[BufferSize
- 1 - Index
];
277 Buffer
[BufferSize
- 1 - Index
] = Temp
;
282 Fill TSF field of QUERY REQUEST UPIU.
284 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
285 @param[in] Opcode The opcode of request.
286 @param[in] DescId The descriptor ID of request.
287 @param[in] Index The index of request.
288 @param[in] Selector The selector of request.
289 @param[in] Length The length of transferred data. The maximum is 4.
290 @param[in] Value The value of transferred data.
294 UfsFillTsfOfQueryReqUpiu (
295 IN OUT UTP_UPIU_TSF
*TsfBase
,
297 IN UINT8 DescId OPTIONAL
,
298 IN UINT8 Index OPTIONAL
,
299 IN UINT8 Selector OPTIONAL
,
300 IN UINT16 Length OPTIONAL
,
301 IN UINT32 Value OPTIONAL
304 ASSERT (TsfBase
!= NULL
);
305 ASSERT (Opcode
<= UtpQueryFuncOpcodeTogFlag
);
307 TsfBase
->Opcode
= Opcode
;
308 if (Opcode
!= UtpQueryFuncOpcodeNop
) {
309 TsfBase
->DescId
= DescId
;
310 TsfBase
->Index
= Index
;
311 TsfBase
->Selector
= Selector
;
313 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
314 SwapLittleEndianToBigEndian ((UINT8
*)&Length
, sizeof (Length
));
315 TsfBase
->Length
= Length
;
318 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
319 SwapLittleEndianToBigEndian ((UINT8
*)&Value
, sizeof (Value
));
320 TsfBase
->Value
= Value
;
326 Initialize COMMAND UPIU.
328 @param[in, out] Command The base address of COMMAND UPIU.
329 @param[in] Lun The Lun on which the SCSI command is executed.
330 @param[in] TaskTag The task tag of request.
331 @param[in] Cdb The cdb buffer containing SCSI command.
332 @param[in] CdbLength The cdb length.
333 @param[in] DataDirection The direction of data transfer.
334 @param[in] ExpDataTranLen The expected transfer data length.
336 @retval EFI_SUCCESS The initialization succeed.
341 IN OUT UTP_COMMAND_UPIU
*Command
,
346 IN UFS_DATA_DIRECTION DataDirection
,
347 IN UINT32 ExpDataTranLen
352 ASSERT ((Command
!= NULL
) && (Cdb
!= NULL
));
355 // Task attribute is hard-coded to Ordered.
357 if (DataDirection
== UfsDataIn
) {
359 } else if (DataDirection
== UfsDataOut
) {
366 // Fill UTP COMMAND UPIU associated fields.
368 Command
->TransCode
= 0x01;
369 Command
->Flags
= Flags
;
371 Command
->TaskTag
= TaskTag
;
372 Command
->CmdSet
= 0x00;
373 SwapLittleEndianToBigEndian ((UINT8
*)&ExpDataTranLen
, sizeof (ExpDataTranLen
));
374 Command
->ExpDataTranLen
= ExpDataTranLen
;
376 CopyMem (Command
->Cdb
, Cdb
, CdbLength
);
382 Initialize UTP PRDT for data transfer.
384 @param[in] Prdt The base address of PRDT.
385 @param[in] Buffer The buffer to be read or written.
386 @param[in] BufferSize The data size to be read or written.
388 @retval EFI_SUCCESS The initialization succeed.
403 if ((BufferSize
& (BIT0
| BIT1
)) != 0) {
404 BufferSize
&= ~(BIT0
| BIT1
);
405 DEBUG ((DEBUG_WARN
, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize
));
408 if (BufferSize
== 0) {
412 ASSERT (((UINTN
)Buffer
& (BIT0
| BIT1
)) == 0);
414 RemainingLen
= BufferSize
;
416 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)BufferSize
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
418 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
419 if (RemainingLen
< UFS_MAX_DATA_LEN_PER_PRD
) {
420 Prdt
[PrdtIndex
].DbCount
= (UINT32
)RemainingLen
- 1;
422 Prdt
[PrdtIndex
].DbCount
= UFS_MAX_DATA_LEN_PER_PRD
- 1;
425 Prdt
[PrdtIndex
].DbAddr
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 2);
426 Prdt
[PrdtIndex
].DbAddrU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 32);
427 RemainingLen
-= UFS_MAX_DATA_LEN_PER_PRD
;
428 Remaining
+= UFS_MAX_DATA_LEN_PER_PRD
;
435 Initialize QUERY REQUEST UPIU.
437 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
438 @param[in] TaskTag The task tag of request.
439 @param[in] Opcode The opcode of request.
440 @param[in] DescId The descriptor ID of request.
441 @param[in] Index The index of request.
442 @param[in] Selector The selector of request.
443 @param[in] DataSize The data size to be read or written.
444 @param[in] Data The buffer to be read or written.
446 @retval EFI_SUCCESS The initialization succeed.
450 UfsInitQueryRequestUpiu (
451 IN OUT UTP_QUERY_REQ_UPIU
*QueryReq
,
457 IN UINTN DataSize OPTIONAL
,
458 IN UINT8
*Data OPTIONAL
461 ASSERT (QueryReq
!= NULL
);
463 QueryReq
->TransCode
= 0x16;
464 QueryReq
->TaskTag
= TaskTag
;
465 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeRdFlag
) || (Opcode
== UtpQueryFuncOpcodeRdAttr
)) {
466 QueryReq
->QueryFunc
= QUERY_FUNC_STD_READ_REQ
;
468 QueryReq
->QueryFunc
= QUERY_FUNC_STD_WRITE_REQ
;
471 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
472 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, *(UINT32
*)Data
);
473 } else if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
474 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, (UINT16
)DataSize
, 0);
476 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, 0);
479 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
480 CopyMem (QueryReq
+ 1, Data
, DataSize
);
482 SwapLittleEndianToBigEndian ((UINT8
*)&DataSize
, sizeof (UINT16
));
483 QueryReq
->DataSegLen
= (UINT16
)DataSize
;
490 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
492 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
493 @param[in] Lun The Lun on which the SCSI command is executed.
494 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
495 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
496 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
497 @param[out] CmdDescMapping A resulting value to pass to Unmap().
499 @retval EFI_SUCCESS The creation succeed.
500 @retval EFI_DEVICE_ERROR The creation failed.
501 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
505 UfsCreateScsiCommandDesc (
506 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
508 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
510 OUT VOID
**CmdDescHost
,
511 OUT VOID
**CmdDescMapping
516 UTP_COMMAND_UPIU
*CommandUpiu
;
517 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
520 UFS_DATA_DIRECTION DataDirection
;
522 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
524 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
525 DataLen
= Packet
->InTransferLength
;
526 DataDirection
= UfsDataIn
;
528 DataLen
= Packet
->OutTransferLength
;
529 DataDirection
= UfsDataOut
;
533 DataDirection
= UfsNoData
;
536 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)DataLen
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
538 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
540 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
541 if (EFI_ERROR (Status
)) {
545 CommandUpiu
= (UTP_COMMAND_UPIU
*)*CmdDescHost
;
547 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, DataLen
);
550 // Fill UTP_TRD associated fields
551 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
552 // *MUST* be located at a 64-bit aligned boundary.
554 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
555 Trd
->Dd
= DataDirection
;
556 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
557 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
558 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
559 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
560 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
561 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
562 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
563 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
568 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
570 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
571 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
572 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
573 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
574 @param[out] CmdDescMapping A resulting value to pass to Unmap().
576 @retval EFI_SUCCESS The creation succeed.
577 @retval EFI_DEVICE_ERROR The creation failed.
578 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
579 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
583 UfsCreateDMCommandDesc (
584 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
585 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
587 OUT VOID
**CmdDescHost
,
588 OUT VOID
**CmdDescMapping
592 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
597 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
600 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
602 Opcode
= Packet
->Opcode
;
603 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
604 return EFI_INVALID_PARAMETER
;
607 DataDirection
= Packet
->DataDirection
;
608 DataSize
= Packet
->TransferLength
;
609 Data
= Packet
->DataBuffer
;
611 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
612 if (DataSize
== 0 || Data
== NULL
) {
613 return EFI_INVALID_PARAMETER
;
615 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
617 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
620 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
621 if (EFI_ERROR (Status
)) {
626 // Initialize UTP QUERY REQUEST UPIU
628 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)*CmdDescHost
;
629 ASSERT (QueryReqUpiu
!= NULL
);
630 UfsInitQueryRequestUpiu (
642 // Fill UTP_TRD associated fields
643 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
645 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
646 Trd
->Dd
= DataDirection
;
647 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
648 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
649 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
650 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
651 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
652 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
653 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
655 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
656 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
663 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
665 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
666 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
667 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
668 @param[out] CmdDescMapping A resulting value to pass to Unmap().
670 @retval EFI_SUCCESS The creation succeed.
671 @retval EFI_DEVICE_ERROR The creation failed.
672 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
676 UfsCreateNopCommandDesc (
677 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
679 OUT VOID
**CmdDescHost
,
680 OUT VOID
**CmdDescMapping
684 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
686 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
688 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
690 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
691 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
692 if (EFI_ERROR (Status
)) {
696 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)*CmdDescHost
;
697 ASSERT (NopOutUpiu
!= NULL
);
698 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
701 // Fill UTP_TRD associated fields
702 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
704 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
706 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
707 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
708 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
709 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
710 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
711 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
717 Find out available slot in transfer list of a UFS device.
719 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
720 @param[out] Slot The available slot.
722 @retval EFI_SUCCESS The available slot was found successfully.
723 @retval EFI_NOT_READY No slot is available at this moment.
727 UfsFindAvailableSlotInTrl (
728 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
737 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
739 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
740 if (EFI_ERROR (Status
)) {
744 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
746 for (Index
= 0; Index
< Nutrs
; Index
++) {
747 if ((Data
& (BIT0
<< Index
)) == 0) {
753 return EFI_NOT_READY
;
758 Start specified slot in transfer list of a UFS device.
760 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
761 @param[in] Slot The slot to be started.
766 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
773 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLRSR_OFFSET
, &Data
);
774 if (EFI_ERROR (Status
)) {
778 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
779 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
780 if (EFI_ERROR (Status
)) {
785 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
);
786 if (EFI_ERROR (Status
)) {
794 Stop specified slot in transfer list of a UFS device.
796 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
797 @param[in] Slot The slot to be stop.
802 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
809 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
810 if (EFI_ERROR (Status
)) {
814 if ((Data
& (BIT0
<< Slot
)) != 0) {
815 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLCLR_OFFSET
, &Data
);
816 if (EFI_ERROR (Status
)) {
820 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLCLR_OFFSET
, Data
& ~(BIT0
<< Slot
));
821 if (EFI_ERROR (Status
)) {
830 Extracts return data from query response upiu.
832 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
833 @param[in] QueryResp Pointer to the query response.
835 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.
836 @retval EFI_DEVICE_ERROR Data returned from device is invalid.
837 @retval EFI_SUCCESS Data extracted.
841 UfsGetReturnDataFromQueryResponse (
842 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
843 IN UTP_QUERY_RESP_UPIU
*QueryResp
846 UINT16 ReturnDataSize
;
849 if (Packet
== NULL
|| QueryResp
== NULL
) {
850 return EFI_INVALID_PARAMETER
;
853 switch (Packet
->Opcode
) {
854 case UtpQueryFuncOpcodeRdDesc
:
855 ReturnDataSize
= QueryResp
->Tsf
.Length
;
856 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
858 // Make sure the hardware device does not return more data than expected.
860 if (ReturnDataSize
> Packet
->TransferLength
) {
861 return EFI_DEVICE_ERROR
;
864 CopyMem (Packet
->DataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
865 Packet
->TransferLength
= ReturnDataSize
;
867 case UtpQueryFuncOpcodeWrDesc
:
868 ReturnDataSize
= QueryResp
->Tsf
.Length
;
869 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
870 Packet
->TransferLength
= ReturnDataSize
;
872 case UtpQueryFuncOpcodeRdFlag
:
873 case UtpQueryFuncOpcodeSetFlag
:
874 case UtpQueryFuncOpcodeClrFlag
:
875 case UtpQueryFuncOpcodeTogFlag
:
876 CopyMem (Packet
->DataBuffer
, &QueryResp
->Tsf
.Value
, sizeof (UINT8
));
878 case UtpQueryFuncOpcodeRdAttr
:
879 case UtpQueryFuncOpcodeWrAttr
:
880 ReturnData
= QueryResp
->Tsf
.Value
;
881 SwapLittleEndianToBigEndian ((UINT8
*) &ReturnData
, sizeof (UINT32
));
882 CopyMem (Packet
->DataBuffer
, &ReturnData
, sizeof (UINT32
));
885 return EFI_INVALID_PARAMETER
;
892 Creates Transfer Request descriptor and sends Query Request to the device.
894 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
895 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
897 @retval EFI_SUCCESS The device descriptor was read/written successfully.
898 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
899 combination to point to a type of UFS device descriptor.
900 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
901 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
905 UfsSendDmRequestRetry (
906 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
907 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
913 VOID
*CmdDescMapping
;
915 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
916 UTP_QUERY_RESP_UPIU
*QueryResp
;
920 // Find out which slot of transfer request list is available.
922 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
923 if (EFI_ERROR (Status
)) {
927 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
929 // Fill transfer request descriptor to this slot.
931 Status
= UfsCreateDMCommandDesc (Private
, Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
932 if (EFI_ERROR (Status
)) {
933 DEBUG ((DEBUG_ERROR
, "Failed to create DM command descriptor\n"));
937 UfsHc
= Private
->UfsHostController
;
938 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
939 ASSERT (QueryResp
!= NULL
);
940 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
943 // Start to execute the transfer request.
945 UfsStartExecCmd (Private
, Slot
);
948 // Wait for the completion of the transfer request.
950 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
, 0, Packet
->Timeout
);
951 if (EFI_ERROR (Status
)) {
955 if (Trd
->Ocs
!= 0 || QueryResp
->QueryResp
!= UfsUtpQueryResponseSuccess
) {
956 DEBUG ((DEBUG_ERROR
, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd
->Ocs
, QueryResp
->QueryResp
));
957 DumpQueryResponseResult (QueryResp
->QueryResp
);
959 if ((QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidSelector
) ||
960 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIndex
) ||
961 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIdn
)) {
962 Status
= EFI_INVALID_PARAMETER
;
964 Status
= EFI_DEVICE_ERROR
;
969 Status
= UfsGetReturnDataFromQueryResponse (Packet
, QueryResp
);
970 if (EFI_ERROR (Status
)) {
971 DEBUG ((DEBUG_ERROR
, "Failed to get return data from query response\n"));
976 UfsHc
->Flush (UfsHc
);
978 UfsStopExecCmd (Private
, Slot
);
980 if (CmdDescMapping
!= NULL
) {
981 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
983 if (CmdDescHost
!= NULL
) {
984 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
991 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
993 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
994 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.
996 @retval EFI_SUCCESS The device responded correctly to the Query request.
997 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
998 combination to point to a type of UFS device descriptor.
999 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
1000 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
1005 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1006 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
1012 Status
= EFI_SUCCESS
;
1014 for (Retry
= 0; Retry
< 5; Retry
++) {
1015 Status
= UfsSendDmRequestRetry (Private
, Packet
);
1016 if (!EFI_ERROR (Status
)) {
1021 DEBUG ((DEBUG_ERROR
, "Failed to get response from the device after %d retries\n", Retry
));
1026 Read or write specified device descriptor of a UFS device.
1028 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1029 @param[in] Read The boolean variable to show r/w direction.
1030 @param[in] DescId The ID of device descriptor.
1031 @param[in] Index The Index of device descriptor.
1032 @param[in] Selector The Selector of device descriptor.
1033 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
1034 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
1035 of the data buffer specified by Descriptor. On output, the number
1036 of bytes that were actually transferred.
1038 @retval EFI_SUCCESS The device descriptor was read/written successfully.
1039 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a
1040 type of UFS device descriptor.
1041 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
1042 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
1047 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1052 IN OUT VOID
*Descriptor
,
1053 IN OUT UINT32
*DescSize
1056 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1059 if (DescSize
== NULL
) {
1060 return EFI_INVALID_PARAMETER
;
1063 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1066 Packet
.DataDirection
= UfsDataIn
;
1067 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
1069 Packet
.DataDirection
= UfsDataOut
;
1070 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
1072 Packet
.DataBuffer
= Descriptor
;
1073 Packet
.TransferLength
= *DescSize
;
1074 Packet
.DescId
= DescId
;
1075 Packet
.Index
= Index
;
1076 Packet
.Selector
= Selector
;
1077 Packet
.Timeout
= UFS_TIMEOUT
;
1079 Status
= UfsSendDmRequest (Private
, &Packet
);
1080 if (EFI_ERROR (Status
)) {
1083 *DescSize
= Packet
.TransferLength
;
1090 Read or write specified attribute of a UFS device.
1092 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1093 @param[in] Read The boolean variable to show r/w direction.
1094 @param[in] AttrId The ID of Attribute.
1095 @param[in] Index The Index of Attribute.
1096 @param[in] Selector The Selector of Attribute.
1097 @param[in, out] Attributes The value of Attribute to be read or written.
1099 @retval EFI_SUCCESS The Attribute was read/written successfully.
1100 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a
1101 type of UFS device descriptor.
1102 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
1103 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
1108 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1113 IN OUT UINT32
*Attributes
1116 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1118 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1121 Packet
.DataDirection
= UfsDataIn
;
1122 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
1124 Packet
.DataDirection
= UfsDataOut
;
1125 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
1127 Packet
.DataBuffer
= Attributes
;
1128 Packet
.DescId
= AttrId
;
1129 Packet
.Index
= Index
;
1130 Packet
.Selector
= Selector
;
1131 Packet
.Timeout
= UFS_TIMEOUT
;
1133 return UfsSendDmRequest (Private
, &Packet
);
1137 Read or write specified flag of a UFS device.
1139 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1140 @param[in] Read The boolean variable to show r/w direction.
1141 @param[in] FlagId The ID of flag to be read or written.
1142 @param[in, out] Value The value to set or clear flag.
1144 @retval EFI_SUCCESS The flag was read/written successfully.
1145 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.
1146 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1147 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1152 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1158 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1160 if (Value
== NULL
) {
1161 return EFI_INVALID_PARAMETER
;
1164 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1167 ASSERT (Value
!= NULL
);
1168 Packet
.DataDirection
= UfsDataIn
;
1169 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1171 Packet
.DataDirection
= UfsDataOut
;
1173 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1174 } else if (*Value
== 0) {
1175 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1177 return EFI_INVALID_PARAMETER
;
1180 Packet
.DataBuffer
= Value
;
1181 Packet
.DescId
= FlagId
;
1183 Packet
.Selector
= 0;
1184 Packet
.Timeout
= UFS_TIMEOUT
;
1186 return UfsSendDmRequest (Private
, &Packet
);
1190 Set specified flag to 1 on a UFS device.
1192 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1193 @param[in] FlagId The ID of flag to be set.
1195 @retval EFI_SUCCESS The flag was set successfully.
1196 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1197 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1202 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1210 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1218 Read specified flag from a UFS device.
1220 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1221 @param[in] FlagId The ID of flag to be read.
1222 @param[out] Value The flag's value.
1224 @retval EFI_SUCCESS The flag was read successfully.
1225 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1226 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1231 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1238 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1244 Sends NOP IN cmd to a UFS device for initialization process request.
1245 For more details, please refer to UFS 2.0 spec Figure 13.3.
1247 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1249 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1250 received successfully.
1251 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1252 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1253 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1258 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1264 UTP_NOP_IN_UPIU
*NopInUpiu
;
1267 VOID
*CmdDescMapping
;
1268 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1271 // Find out which slot of transfer request list is available.
1273 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1274 if (EFI_ERROR (Status
)) {
1278 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1279 Status
= UfsCreateNopCommandDesc (Private
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1280 if (EFI_ERROR (Status
)) {
1285 // Check the transfer request result.
1287 UfsHc
= Private
->UfsHostController
;
1288 NopInUpiu
= (UTP_NOP_IN_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1289 ASSERT (NopInUpiu
!= NULL
);
1290 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1293 // Start to execute the transfer request.
1295 UfsStartExecCmd (Private
, Slot
);
1298 // Wait for the completion of the transfer request.
1300 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1301 if (EFI_ERROR (Status
)) {
1305 if (NopInUpiu
->Resp
!= 0) {
1306 Status
= EFI_DEVICE_ERROR
;
1308 Status
= EFI_SUCCESS
;
1312 UfsHc
->Flush (UfsHc
);
1314 UfsStopExecCmd (Private
, Slot
);
1316 if (CmdDescMapping
!= NULL
) {
1317 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1319 if (CmdDescHost
!= NULL
) {
1320 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1327 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1329 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1330 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1331 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1333 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1334 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1335 Event is not NULL and non blocking I/O is supported, then
1336 nonblocking I/O is performed, and Event will be signaled when the
1337 SCSI Request Packet completes.
1339 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1340 commands, InTransferLength bytes were transferred from
1341 InDataBuffer. For write and bi-directional commands,
1342 OutTransferLength bytes were transferred by
1344 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1346 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1347 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1352 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1354 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
1355 IN EFI_EVENT Event OPTIONAL
1359 UTP_RESPONSE_UPIU
*Response
;
1360 UINT16 SenseDataLen
;
1361 UINT32 ResTranCount
;
1363 EFI_PHYSICAL_ADDRESS DataBufPhyAddr
;
1366 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1367 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag
;
1368 UTP_TR_PRD
*PrdtBase
;
1370 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
1372 TransReq
= AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ
));
1373 if (TransReq
== NULL
) {
1374 return EFI_OUT_OF_RESOURCES
;
1377 TransReq
->Signature
= UFS_PASS_THRU_TRANS_REQ_SIG
;
1378 TransReq
->TimeoutRemain
= Packet
->Timeout
;
1380 UfsHc
= Private
->UfsHostController
;
1382 // Find out which slot of transfer request list is available.
1384 Status
= UfsFindAvailableSlotInTrl (Private
, &TransReq
->Slot
);
1385 if (EFI_ERROR (Status
)) {
1389 TransReq
->Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + TransReq
->Slot
;
1392 // Fill transfer request descriptor to this slot.
1394 Status
= UfsCreateScsiCommandDesc (
1399 &TransReq
->CmdDescHost
,
1400 &TransReq
->CmdDescMapping
1402 if (EFI_ERROR (Status
)) {
1406 TransReq
->CmdDescSize
= TransReq
->Trd
->PrdtO
* sizeof (UINT32
) + TransReq
->Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1408 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1409 DataBuf
= Packet
->InDataBuffer
;
1410 DataLen
= Packet
->InTransferLength
;
1411 Flag
= EdkiiUfsHcOperationBusMasterWrite
;
1413 DataBuf
= Packet
->OutDataBuffer
;
1414 DataLen
= Packet
->OutTransferLength
;
1415 Flag
= EdkiiUfsHcOperationBusMasterRead
;
1419 MapLength
= DataLen
;
1420 Status
= UfsHc
->Map (
1426 &TransReq
->DataBufMapping
1429 if (EFI_ERROR (Status
) || (DataLen
!= MapLength
)) {
1434 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1436 PrdtBase
= (UTP_TR_PRD
*)((UINT8
*)TransReq
->CmdDescHost
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
1437 ASSERT (PrdtBase
!= NULL
);
1438 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)DataBufPhyAddr
, DataLen
);
1441 // Insert the async SCSI cmd to the Async I/O list
1443 if (Event
!= NULL
) {
1444 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1445 TransReq
->Packet
= Packet
;
1446 TransReq
->CallerEvent
= Event
;
1447 InsertTailList (&Private
->Queue
, &TransReq
->TransferList
);
1448 gBS
->RestoreTPL (OldTpl
);
1452 // Start to execute the transfer request.
1454 UfsStartExecCmd (Private
, TransReq
->Slot
);
1457 // Immediately return for async I/O.
1459 if (Event
!= NULL
) {
1464 // Wait for the completion of the transfer request.
1466 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< TransReq
->Slot
, 0, Packet
->Timeout
);
1467 if (EFI_ERROR (Status
)) {
1472 // Get sense data if exists
1474 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
1475 ASSERT (Response
!= NULL
);
1476 SenseDataLen
= Response
->SenseDataLen
;
1477 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1479 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1481 // Make sure the hardware device does not return more data than expected.
1483 if (SenseDataLen
<= Packet
->SenseDataLength
) {
1484 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1485 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1487 Packet
->SenseDataLength
= 0;
1492 // Check the transfer request result.
1494 Packet
->TargetStatus
= Response
->Status
;
1495 if (Response
->Response
!= 0) {
1496 DEBUG ((DEBUG_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1497 Status
= EFI_DEVICE_ERROR
;
1501 if (TransReq
->Trd
->Ocs
== 0) {
1502 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1503 if ((Response
->Flags
& BIT5
) == BIT5
) {
1504 ResTranCount
= Response
->ResTranCount
;
1505 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1506 Packet
->InTransferLength
-= ResTranCount
;
1509 if ((Response
->Flags
& BIT5
) == BIT5
) {
1510 ResTranCount
= Response
->ResTranCount
;
1511 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1512 Packet
->OutTransferLength
-= ResTranCount
;
1516 Status
= EFI_DEVICE_ERROR
;
1520 UfsHc
->Flush (UfsHc
);
1522 UfsStopExecCmd (Private
, TransReq
->Slot
);
1524 if (TransReq
->DataBufMapping
!= NULL
) {
1525 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
1529 if (TransReq
->CmdDescMapping
!= NULL
) {
1530 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
1532 if (TransReq
->CmdDescHost
!= NULL
) {
1533 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
), TransReq
->CmdDescHost
);
1535 if (TransReq
!= NULL
) {
1536 FreePool (TransReq
);
1543 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1545 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1546 @param[in] UicOpcode The opcode of the UIC command.
1547 @param[in] Arg1 The value for 1st argument of the UIC command.
1548 @param[in] Arg2 The value for 2nd argument of the UIC command.
1549 @param[in] Arg3 The value for 3rd argument of the UIC command.
1551 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1552 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1553 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1557 UfsExecUicCommands (
1558 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1568 Status
= UfsMmioRead32 (Private
, UFS_HC_IS_OFFSET
, &Data
);
1569 if (EFI_ERROR (Status
)) {
1573 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1575 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1577 Status
= UfsMmioWrite32 (Private
, UFS_HC_IS_OFFSET
, Data
);
1578 if (EFI_ERROR (Status
)) {
1584 // When programming UIC command registers, host software shall set the register UICCMD
1585 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1588 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG1_OFFSET
, Arg1
);
1589 if (EFI_ERROR (Status
)) {
1593 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, Arg2
);
1594 if (EFI_ERROR (Status
)) {
1598 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, Arg3
);
1599 if (EFI_ERROR (Status
)) {
1604 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1606 Status
= UfsWaitMemSet (Private
, UFS_HC_STATUS_OFFSET
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1607 if (EFI_ERROR (Status
)) {
1611 Status
= UfsMmioWrite32 (Private
, UFS_HC_UIC_CMD_OFFSET
, (UINT32
)UicOpcode
);
1612 if (EFI_ERROR (Status
)) {
1617 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1618 // This bit is set to '1' by the host controller upon completion of a UIC command.
1620 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1621 if (EFI_ERROR (Status
)) {
1625 if (UicOpcode
!= UfsUicDmeReset
) {
1626 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, &Data
);
1627 if (EFI_ERROR (Status
)) {
1630 if ((Data
& 0xFF) != 0) {
1632 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1634 return EFI_DEVICE_ERROR
;
1639 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1641 Status
= UfsMmioRead32 (Private
, UFS_HC_STATUS_OFFSET
, &Data
);
1642 if (EFI_ERROR (Status
)) {
1646 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1647 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1648 if (EFI_ERROR (Status
)) {
1649 return EFI_DEVICE_ERROR
;
1651 return EFI_NOT_FOUND
;
1654 DEBUG ((DEBUG_INFO
, "UfsPassThruDxe: found a attached UFS device\n"));
1660 Allocate common buffer for host and UFS bus master access simultaneously.
1662 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1663 @param[in] Size The length of buffer to be allocated.
1664 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1665 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1666 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1668 @retval EFI_SUCCESS The common buffer was allocated successfully.
1669 @retval EFI_DEVICE_ERROR The allocation fails.
1670 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1674 UfsAllocateAlignCommonBuffer (
1675 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1677 OUT VOID
**CmdDescHost
,
1678 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1679 OUT VOID
**CmdDescMapping
1684 BOOLEAN Is32BitAddr
;
1685 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1687 if ((Private
->Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1688 Is32BitAddr
= FALSE
;
1693 UfsHc
= Private
->UfsHostController
;
1694 Status
= UfsHc
->AllocateBuffer (
1697 EfiBootServicesData
,
1698 EFI_SIZE_TO_PAGES (Size
),
1702 if (EFI_ERROR (Status
)) {
1703 *CmdDescMapping
= NULL
;
1704 *CmdDescHost
= NULL
;
1705 *CmdDescPhyAddr
= 0;
1706 return EFI_OUT_OF_RESOURCES
;
1709 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1710 Status
= UfsHc
->Map (
1712 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1719 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1722 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1725 *CmdDescHost
= NULL
;
1726 return EFI_OUT_OF_RESOURCES
;
1729 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1731 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1739 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1742 *CmdDescMapping
= NULL
;
1743 *CmdDescHost
= NULL
;
1744 return EFI_DEVICE_ERROR
;
1747 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1752 Enable the UFS host controller for accessing.
1754 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1756 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1757 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1761 UfsEnableHostController (
1762 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1769 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1771 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1773 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
1774 if (EFI_ERROR (Status
)) {
1778 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1780 // Write a 0 to the HCE register at first to disable the host controller.
1782 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
1783 if (EFI_ERROR (Status
)) {
1787 // Wait until HCE is read as '0' before continuing.
1789 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1790 if (EFI_ERROR (Status
)) {
1791 return EFI_DEVICE_ERROR
;
1796 // Write a 1 to the HCE register to enable the UFS host controller.
1798 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
);
1799 if (EFI_ERROR (Status
)) {
1804 // Wait until HCE is read as '1' before continuing.
1806 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1807 if (EFI_ERROR (Status
)) {
1808 return EFI_DEVICE_ERROR
;
1815 Detect if a UFS device attached.
1817 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1819 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1820 @retval EFI_NOT_FOUND Not found a UFS device attached.
1821 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1825 UfsDeviceDetection (
1826 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1833 // Start UFS device detection.
1834 // Try up to 3 times for establishing data link with device.
1836 for (Retry
= 0; Retry
< 3; Retry
++) {
1837 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1838 if (!EFI_ERROR (Status
)) {
1842 if (Status
== EFI_NOT_FOUND
) {
1846 return EFI_DEVICE_ERROR
;
1850 return EFI_NOT_FOUND
;
1857 Initialize UFS task management request list related h/w context.
1859 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1861 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1862 @retval EFI_DEVICE_ERROR The initialization fails.
1866 UfsInitTaskManagementRequestList (
1867 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1873 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1874 VOID
*CmdDescMapping
;
1878 // Initial h/w and s/w context for future operations.
1881 CmdDescMapping
= NULL
;
1884 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1885 if (EFI_ERROR (Status
)) {
1889 Private
->Capabilities
= Data
;
1892 // Allocate and initialize UTP Task Management Request List.
1894 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1895 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1896 if (EFI_ERROR (Status
)) {
1901 // Program the UTP Task Management Request List Base Address and UTP Task Management
1902 // Request List Base Address with a 64-bit address allocated at step 6.
1904 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1905 if (EFI_ERROR (Status
)) {
1909 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1910 if (EFI_ERROR (Status
)) {
1913 Private
->UtpTmrlBase
= CmdDescHost
;
1914 Private
->Nutmrs
= Nutmrs
;
1915 Private
->TmrlMapping
= CmdDescMapping
;
1918 // Enable the UTP Task Management Request List by setting the UTP Task Management
1919 // Request List RunStop Register (UTMRLRSR) to '1'.
1921 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
1922 if (EFI_ERROR (Status
)) {
1930 Initialize UFS transfer request list related h/w context.
1932 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1934 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1935 @retval EFI_DEVICE_ERROR The initialization fails.
1939 UfsInitTransferRequestList (
1940 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1946 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1947 VOID
*CmdDescMapping
;
1951 // Initial h/w and s/w context for future operations.
1954 CmdDescMapping
= NULL
;
1957 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1958 if (EFI_ERROR (Status
)) {
1962 Private
->Capabilities
= Data
;
1965 // Allocate and initialize UTP Transfer Request List.
1967 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1968 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1969 if (EFI_ERROR (Status
)) {
1974 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1975 // Base Address with a 64-bit address allocated at step 8.
1977 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1978 if (EFI_ERROR (Status
)) {
1982 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1983 if (EFI_ERROR (Status
)) {
1987 Private
->UtpTrlBase
= CmdDescHost
;
1988 Private
->Nutrs
= Nutrs
;
1989 Private
->TrlMapping
= CmdDescMapping
;
1992 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1993 // RunStop Register (UTRLRSR) to '1'.
1995 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
1996 if (EFI_ERROR (Status
)) {
2004 Initialize the UFS host controller.
2006 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2008 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2009 @retval Others A device error occurred while initializing the controller.
2014 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2019 Status
= UfsEnableHostController (Private
);
2020 if (EFI_ERROR (Status
)) {
2021 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2025 Status
= UfsDeviceDetection (Private
);
2026 if (EFI_ERROR (Status
)) {
2027 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2031 Status
= UfsInitTaskManagementRequestList (Private
);
2032 if (EFI_ERROR (Status
)) {
2033 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2037 Status
= UfsInitTransferRequestList (Private
);
2038 if (EFI_ERROR (Status
)) {
2039 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2043 DEBUG ((DEBUG_INFO
, "UfsControllerInit Finished\n"));
2048 Stop the UFS host controller.
2050 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2052 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2053 @retval Others A device error occurred while stopping the controller.
2058 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2065 // Enable the UTP Task Management Request List by setting the UTP Task Management
2066 // Request List RunStop Register (UTMRLRSR) to '1'.
2068 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2069 if (EFI_ERROR (Status
)) {
2074 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2075 // RunStop Register (UTRLRSR) to '1'.
2077 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2078 if (EFI_ERROR (Status
)) {
2083 // Write a 0 to the HCE register in order to disable the host controller.
2085 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2086 if (EFI_ERROR (Status
)) {
2089 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2091 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2092 if (EFI_ERROR (Status
)) {
2097 // Wait until HCE is read as '0' before continuing.
2099 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2100 if (EFI_ERROR (Status
)) {
2101 return EFI_DEVICE_ERROR
;
2104 DEBUG ((DEBUG_INFO
, "UfsController is stopped\n"));
2111 Internal helper function which will signal the caller event and clean up
2114 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2116 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2123 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
2124 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
2127 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
2128 EFI_EVENT CallerEvent
;
2130 ASSERT ((Private
!= NULL
) && (TransReq
!= NULL
));
2132 UfsHc
= Private
->UfsHostController
;
2133 CallerEvent
= TransReq
->CallerEvent
;
2135 RemoveEntryList (&TransReq
->TransferList
);
2137 UfsHc
->Flush (UfsHc
);
2139 UfsStopExecCmd (Private
, TransReq
->Slot
);
2141 if (TransReq
->DataBufMapping
!= NULL
) {
2142 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
2145 if (TransReq
->CmdDescMapping
!= NULL
) {
2146 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
2148 if (TransReq
->CmdDescHost
!= NULL
) {
2151 EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
),
2152 TransReq
->CmdDescHost
2156 FreePool (TransReq
);
2158 gBS
->SignalEvent (CallerEvent
);
2163 Call back function when the timer event is signaled.
2165 @param[in] Event The Event this notify function registered to.
2166 @param[in] Context Pointer to the context data registered to the Event.
2171 ProcessAsyncTaskList (
2176 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2178 LIST_ENTRY
*NextEntry
;
2179 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
2180 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
;
2181 UTP_RESPONSE_UPIU
*Response
;
2182 UINT16 SenseDataLen
;
2183 UINT32 ResTranCount
;
2188 Private
= (UFS_PASS_THRU_PRIVATE_DATA
*) Context
;
2192 // Check the entries in the async I/O queue are done or not.
2194 if (!IsListEmpty(&Private
->Queue
)) {
2195 EFI_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
2196 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
2197 Packet
= TransReq
->Packet
;
2199 if ((SlotsMap
& (BIT0
<< TransReq
->Slot
)) != 0) {
2202 SlotsMap
|= BIT0
<< TransReq
->Slot
;
2204 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Value
);
2205 if (EFI_ERROR (Status
)) {
2207 // TODO: Should find/add a proper host adapter return status for this
2210 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
2211 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq
->CallerEvent
));
2212 SignalCallerEvent (Private
, TransReq
);
2216 if ((Value
& (BIT0
<< TransReq
->Slot
)) != 0) {
2218 // Scsi cmd not finished yet.
2220 if (TransReq
->TimeoutRemain
> UFS_HC_ASYNC_TIMER
) {
2221 TransReq
->TimeoutRemain
-= UFS_HC_ASYNC_TIMER
;
2227 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
2228 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq
->CallerEvent
));
2229 SignalCallerEvent (Private
, TransReq
);
2234 // Scsi cmd finished.
2236 // Get sense data if exists
2238 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
2239 ASSERT (Response
!= NULL
);
2240 SenseDataLen
= Response
->SenseDataLen
;
2241 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
2243 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
2245 // Make sure the hardware device does not return more data than expected.
2247 if (SenseDataLen
<= Packet
->SenseDataLength
) {
2248 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
2249 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
2251 Packet
->SenseDataLength
= 0;
2256 // Check the transfer request result.
2258 Packet
->TargetStatus
= Response
->Status
;
2259 if (Response
->Response
!= 0) {
2260 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq
->CallerEvent
));
2261 SignalCallerEvent (Private
, TransReq
);
2265 if (TransReq
->Trd
->Ocs
== 0) {
2266 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2267 if ((Response
->Flags
& BIT5
) == BIT5
) {
2268 ResTranCount
= Response
->ResTranCount
;
2269 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2270 Packet
->InTransferLength
-= ResTranCount
;
2273 if ((Response
->Flags
& BIT5
) == BIT5
) {
2274 ResTranCount
= Response
->ResTranCount
;
2275 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2276 Packet
->OutTransferLength
-= ResTranCount
;
2280 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq
->CallerEvent
));
2281 SignalCallerEvent (Private
, TransReq
);
2285 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq
->CallerEvent
));
2286 SignalCallerEvent (Private
, TransReq
);