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 - 2019, Intel Corporation. All rights reserved.<BR>
6 Copyright (c) Microsoft Corporation.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "UfsPassThru.h"
14 Read 32bits data from specified UFS MMIO register.
16 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
17 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
19 @param[out] Value The data buffer to store.
21 @retval EFI_TIMEOUT The operation is time out.
22 @retval EFI_SUCCESS The operation succeeds.
23 @retval Others The operation fails.
28 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
33 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
36 UfsHc
= Private
->UfsHostController
;
38 Status
= UfsHc
->Read (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, Value
);
44 Write 32bits data to specified UFS MMIO register.
46 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
47 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
49 @param[in] Value The data to write.
51 @retval EFI_TIMEOUT The operation is time out.
52 @retval EFI_SUCCESS The operation succeeds.
53 @retval Others The operation fails.
58 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
63 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
66 UfsHc
= Private
->UfsHostController
;
68 Status
= UfsHc
->Write (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, &Value
);
74 Wait for the value of the specified system memory set to the test value.
76 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
77 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
79 @param[in] MaskValue The mask value of memory.
80 @param[in] TestValue The test value of memory.
81 @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.
83 @retval EFI_TIMEOUT The system memory setting is time out.
84 @retval EFI_SUCCESS The system memory is correct set.
85 @retval Others The operation fails.
90 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
105 InfiniteWait
= FALSE
;
108 Delay
= DivU64x32 (Timeout
, 10) + 1;
112 // Access PCI MMIO space to see if the value is the tested one.
114 Status
= UfsMmioRead32 (Private
, Offset
, &Value
);
115 if (EFI_ERROR (Status
)) {
121 if (Value
== TestValue
) {
126 // Stall for 1 microseconds.
128 MicroSecondDelay (1);
131 } while (InfiniteWait
|| (Delay
> 0));
137 Dump UIC command execution result for debugging.
139 @param[in] UicOpcode The executed UIC opcode.
140 @param[in] Result The result to be parsed.
144 DumpUicCmdExecResult (
149 if (UicOpcode
<= UfsUicDmePeerSet
) {
154 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
157 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
160 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
163 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
166 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BAD_INDEX\n"));
169 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
172 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
175 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
178 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BUSY\n"));
181 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - DME_FAILURE\n"));
192 DEBUG ((DEBUG_VERBOSE
, "UIC control command fails - FAILURE\n"));
202 Dump QUERY RESPONSE UPIU result for debugging.
204 @param[in] Result The result to be parsed.
208 DumpQueryResponseResult (
214 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Not Readable\n"));
217 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Not Writeable\n"));
220 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Already Written\n"));
223 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Length\n"));
226 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Value\n"));
229 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Selector\n"));
232 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Index\n"));
235 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Idn\n"));
238 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Opcode\n"));
241 DEBUG ((DEBUG_VERBOSE
, "Query Response with General Failure\n"));
250 Swap little endian to big endian.
252 @param[in, out] Buffer The data buffer. In input, it contains little endian data.
253 In output, it will become big endian.
254 @param[in] BufferSize The length of converted data.
258 SwapLittleEndianToBigEndian (
259 IN OUT UINT8
*Buffer
,
267 SwapCount
= BufferSize
/ 2;
268 for (Index
= 0; Index
< SwapCount
; Index
++) {
269 Temp
= Buffer
[Index
];
270 Buffer
[Index
] = Buffer
[BufferSize
- 1 - Index
];
271 Buffer
[BufferSize
- 1 - Index
] = Temp
;
276 Fill TSF field of QUERY REQUEST UPIU.
278 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
279 @param[in] Opcode The opcode of request.
280 @param[in] DescId The descriptor ID of request.
281 @param[in] Index The index of request.
282 @param[in] Selector The selector of request.
283 @param[in] Length The length of transferred data. The maximum is 4.
284 @param[in] Value The value of transferred data.
288 UfsFillTsfOfQueryReqUpiu (
289 IN OUT UTP_UPIU_TSF
*TsfBase
,
291 IN UINT8 DescId OPTIONAL
,
292 IN UINT8 Index OPTIONAL
,
293 IN UINT8 Selector OPTIONAL
,
294 IN UINT16 Length OPTIONAL
,
295 IN UINT32 Value OPTIONAL
298 ASSERT (TsfBase
!= NULL
);
299 ASSERT (Opcode
<= UtpQueryFuncOpcodeTogFlag
);
301 TsfBase
->Opcode
= Opcode
;
302 if (Opcode
!= UtpQueryFuncOpcodeNop
) {
303 TsfBase
->DescId
= DescId
;
304 TsfBase
->Index
= Index
;
305 TsfBase
->Selector
= Selector
;
307 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
308 SwapLittleEndianToBigEndian ((UINT8
*)&Length
, sizeof (Length
));
309 TsfBase
->Length
= Length
;
312 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
313 SwapLittleEndianToBigEndian ((UINT8
*)&Value
, sizeof (Value
));
314 TsfBase
->Value
= Value
;
320 Initialize COMMAND UPIU.
322 @param[in, out] Command The base address of COMMAND UPIU.
323 @param[in] Lun The Lun on which the SCSI command is executed.
324 @param[in] TaskTag The task tag of request.
325 @param[in] Cdb The cdb buffer containing SCSI command.
326 @param[in] CdbLength The cdb length.
327 @param[in] DataDirection The direction of data transfer.
328 @param[in] ExpDataTranLen The expected transfer data length.
330 @retval EFI_SUCCESS The initialization succeed.
335 IN OUT UTP_COMMAND_UPIU
*Command
,
340 IN UFS_DATA_DIRECTION DataDirection
,
341 IN UINT32 ExpDataTranLen
346 ASSERT ((Command
!= NULL
) && (Cdb
!= NULL
));
349 // Task attribute is hard-coded to Ordered.
351 if (DataDirection
== UfsDataIn
) {
353 } else if (DataDirection
== UfsDataOut
) {
360 // Fill UTP COMMAND UPIU associated fields.
362 Command
->TransCode
= 0x01;
363 Command
->Flags
= Flags
;
365 Command
->TaskTag
= TaskTag
;
366 Command
->CmdSet
= 0x00;
367 SwapLittleEndianToBigEndian ((UINT8
*)&ExpDataTranLen
, sizeof (ExpDataTranLen
));
368 Command
->ExpDataTranLen
= ExpDataTranLen
;
370 CopyMem (Command
->Cdb
, Cdb
, CdbLength
);
376 Initialize UTP PRDT for data transfer.
378 @param[in] Prdt The base address of PRDT.
379 @param[in] Buffer The buffer to be read or written.
380 @param[in] BufferSize The data size to be read or written.
382 @retval EFI_SUCCESS The initialization succeed.
397 ASSERT (((UINTN
)Buffer
& (BIT0
| BIT1
)) == 0);
398 ASSERT ((BufferSize
& (BIT1
| BIT0
)) == 0);
400 if (BufferSize
== 0) {
404 RemainingLen
= BufferSize
;
406 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)BufferSize
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
408 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
409 if (RemainingLen
< UFS_MAX_DATA_LEN_PER_PRD
) {
410 Prdt
[PrdtIndex
].DbCount
= (UINT32
)RemainingLen
- 1;
412 Prdt
[PrdtIndex
].DbCount
= UFS_MAX_DATA_LEN_PER_PRD
- 1;
415 Prdt
[PrdtIndex
].DbAddr
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 2);
416 Prdt
[PrdtIndex
].DbAddrU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 32);
417 RemainingLen
-= UFS_MAX_DATA_LEN_PER_PRD
;
418 Remaining
+= UFS_MAX_DATA_LEN_PER_PRD
;
425 Initialize QUERY REQUEST UPIU.
427 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
428 @param[in] TaskTag The task tag of request.
429 @param[in] Opcode The opcode of request.
430 @param[in] DescId The descriptor ID of request.
431 @param[in] Index The index of request.
432 @param[in] Selector The selector of request.
433 @param[in] DataSize The data size to be read or written.
434 @param[in] Data The buffer to be read or written.
436 @retval EFI_SUCCESS The initialization succeed.
440 UfsInitQueryRequestUpiu (
441 IN OUT UTP_QUERY_REQ_UPIU
*QueryReq
,
447 IN UINTN DataSize OPTIONAL
,
448 IN UINT8
*Data OPTIONAL
451 ASSERT (QueryReq
!= NULL
);
453 QueryReq
->TransCode
= 0x16;
454 QueryReq
->TaskTag
= TaskTag
;
455 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeRdFlag
) || (Opcode
== UtpQueryFuncOpcodeRdAttr
)) {
456 QueryReq
->QueryFunc
= QUERY_FUNC_STD_READ_REQ
;
458 QueryReq
->QueryFunc
= QUERY_FUNC_STD_WRITE_REQ
;
461 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
462 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, *(UINT32
*)Data
);
463 } else if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
464 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, (UINT16
)DataSize
, 0);
466 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, 0);
469 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
470 CopyMem (QueryReq
+ 1, Data
, DataSize
);
472 SwapLittleEndianToBigEndian ((UINT8
*)&DataSize
, sizeof (UINT16
));
473 QueryReq
->DataSegLen
= (UINT16
)DataSize
;
480 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
482 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
483 @param[in] Lun The Lun on which the SCSI command is executed.
484 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
485 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
486 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
487 @param[out] CmdDescMapping A resulting value to pass to Unmap().
489 @retval EFI_SUCCESS The creation succeed.
490 @retval EFI_DEVICE_ERROR The creation failed.
491 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
495 UfsCreateScsiCommandDesc (
496 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
498 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
500 OUT VOID
**CmdDescHost
,
501 OUT VOID
**CmdDescMapping
506 UTP_COMMAND_UPIU
*CommandUpiu
;
507 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
510 UFS_DATA_DIRECTION DataDirection
;
512 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
514 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
515 DataLen
= Packet
->InTransferLength
;
516 DataDirection
= UfsDataIn
;
518 DataLen
= Packet
->OutTransferLength
;
519 DataDirection
= UfsDataOut
;
523 DataDirection
= UfsNoData
;
526 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)DataLen
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
528 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
530 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
531 if (EFI_ERROR (Status
)) {
535 CommandUpiu
= (UTP_COMMAND_UPIU
*)*CmdDescHost
;
537 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, DataLen
);
540 // Fill UTP_TRD associated fields
541 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
542 // *MUST* be located at a 64-bit aligned boundary.
544 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
545 Trd
->Dd
= DataDirection
;
546 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
547 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
548 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
549 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
550 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
551 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
552 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
553 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
558 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
560 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
561 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
562 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
563 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
564 @param[out] CmdDescMapping A resulting value to pass to Unmap().
566 @retval EFI_SUCCESS The creation succeed.
567 @retval EFI_DEVICE_ERROR The creation failed.
568 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
569 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
573 UfsCreateDMCommandDesc (
574 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
575 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
577 OUT VOID
**CmdDescHost
,
578 OUT VOID
**CmdDescMapping
582 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
587 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
590 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
592 Opcode
= Packet
->Opcode
;
593 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
594 return EFI_INVALID_PARAMETER
;
597 DataDirection
= Packet
->DataDirection
;
598 DataSize
= Packet
->TransferLength
;
599 Data
= Packet
->DataBuffer
;
601 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
602 if ((DataSize
== 0) || (Data
== NULL
)) {
603 return EFI_INVALID_PARAMETER
;
606 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
608 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
611 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
612 if (EFI_ERROR (Status
)) {
617 // Initialize UTP QUERY REQUEST UPIU
619 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)*CmdDescHost
;
620 ASSERT (QueryReqUpiu
!= NULL
);
621 UfsInitQueryRequestUpiu (
633 // Fill UTP_TRD associated fields
634 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
636 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
637 Trd
->Dd
= DataDirection
;
638 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
639 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
640 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
641 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
642 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
643 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
644 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
646 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
647 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
654 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
656 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
657 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
658 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
659 @param[out] CmdDescMapping A resulting value to pass to Unmap().
661 @retval EFI_SUCCESS The creation succeed.
662 @retval EFI_DEVICE_ERROR The creation failed.
663 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
667 UfsCreateNopCommandDesc (
668 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
670 OUT VOID
**CmdDescHost
,
671 OUT VOID
**CmdDescMapping
675 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
677 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
679 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
681 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
682 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
683 if (EFI_ERROR (Status
)) {
687 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)*CmdDescHost
;
688 ASSERT (NopOutUpiu
!= NULL
);
689 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
692 // Fill UTP_TRD associated fields
693 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
695 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
697 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
698 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
699 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
700 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
701 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
702 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
708 Find out available slot in transfer list of a UFS device.
710 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
711 @param[out] Slot The available slot.
713 @retval EFI_SUCCESS The available slot was found successfully.
714 @retval EFI_NOT_READY No slot is available at this moment.
718 UfsFindAvailableSlotInTrl (
719 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
728 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
730 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
731 if (EFI_ERROR (Status
)) {
735 Nutrs
= (UINT8
)((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
737 for (Index
= 0; Index
< Nutrs
; Index
++) {
738 if ((Data
& (BIT0
<< Index
)) == 0) {
744 return EFI_NOT_READY
;
748 Start specified slot in transfer list of a UFS device.
750 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
751 @param[in] Slot The slot to be started.
756 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
763 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLRSR_OFFSET
, &Data
);
764 if (EFI_ERROR (Status
)) {
768 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
769 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
770 if (EFI_ERROR (Status
)) {
775 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
);
776 if (EFI_ERROR (Status
)) {
784 Stop specified slot in transfer list of a UFS device.
786 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
787 @param[in] Slot The slot to be stop.
792 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
799 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
800 if (EFI_ERROR (Status
)) {
804 if ((Data
& (BIT0
<< Slot
)) != 0) {
805 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLCLR_OFFSET
, &Data
);
806 if (EFI_ERROR (Status
)) {
810 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLCLR_OFFSET
, Data
& ~(BIT0
<< Slot
));
811 if (EFI_ERROR (Status
)) {
820 Extracts return data from query response upiu.
822 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
823 @param[in] QueryResp Pointer to the query response.
825 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.
826 @retval EFI_DEVICE_ERROR Data returned from device is invalid.
827 @retval EFI_SUCCESS Data extracted.
831 UfsGetReturnDataFromQueryResponse (
832 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
833 IN UTP_QUERY_RESP_UPIU
*QueryResp
836 UINT16 ReturnDataSize
;
839 if ((Packet
== NULL
) || (QueryResp
== NULL
)) {
840 return EFI_INVALID_PARAMETER
;
843 switch (Packet
->Opcode
) {
844 case UtpQueryFuncOpcodeRdDesc
:
845 ReturnDataSize
= QueryResp
->Tsf
.Length
;
846 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
848 // Make sure the hardware device does not return more data than expected.
850 if (ReturnDataSize
> Packet
->TransferLength
) {
851 return EFI_DEVICE_ERROR
;
854 CopyMem (Packet
->DataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
855 Packet
->TransferLength
= ReturnDataSize
;
857 case UtpQueryFuncOpcodeWrDesc
:
858 ReturnDataSize
= QueryResp
->Tsf
.Length
;
859 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
860 Packet
->TransferLength
= ReturnDataSize
;
862 case UtpQueryFuncOpcodeRdFlag
:
863 case UtpQueryFuncOpcodeSetFlag
:
864 case UtpQueryFuncOpcodeClrFlag
:
865 case UtpQueryFuncOpcodeTogFlag
:
867 // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value
869 *((UINT8
*)(Packet
->DataBuffer
)) = *((UINT8
*)&(QueryResp
->Tsf
.Value
) + 3);
871 case UtpQueryFuncOpcodeRdAttr
:
872 case UtpQueryFuncOpcodeWrAttr
:
873 ReturnData
= QueryResp
->Tsf
.Value
;
874 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnData
, sizeof (UINT32
));
875 CopyMem (Packet
->DataBuffer
, &ReturnData
, sizeof (UINT32
));
878 return EFI_INVALID_PARAMETER
;
885 Creates Transfer Request descriptor and sends Query Request to the device.
887 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
888 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
890 @retval EFI_SUCCESS The device descriptor was read/written successfully.
891 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
892 combination to point to a type of UFS device descriptor.
893 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
894 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
898 UfsSendDmRequestRetry (
899 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
900 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
906 VOID
*CmdDescMapping
;
908 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
909 UTP_QUERY_RESP_UPIU
*QueryResp
;
913 // Find out which slot of transfer request list is available.
915 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
916 if (EFI_ERROR (Status
)) {
920 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
922 // Fill transfer request descriptor to this slot.
924 Status
= UfsCreateDMCommandDesc (Private
, Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
925 if (EFI_ERROR (Status
)) {
926 DEBUG ((DEBUG_ERROR
, "Failed to create DM command descriptor\n"));
930 UfsHc
= Private
->UfsHostController
;
931 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
932 ASSERT (QueryResp
!= NULL
);
933 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
936 // Start to execute the transfer request.
938 UfsStartExecCmd (Private
, Slot
);
941 // Wait for the completion of the transfer request.
943 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
, 0, Packet
->Timeout
);
944 if (EFI_ERROR (Status
)) {
948 if ((Trd
->Ocs
!= 0) || (QueryResp
->QueryResp
!= UfsUtpQueryResponseSuccess
)) {
949 DEBUG ((DEBUG_ERROR
, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd
->Ocs
, QueryResp
->QueryResp
));
950 DumpQueryResponseResult (QueryResp
->QueryResp
);
952 if ((QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidSelector
) ||
953 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIndex
) ||
954 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIdn
))
956 Status
= EFI_INVALID_PARAMETER
;
958 Status
= EFI_DEVICE_ERROR
;
964 Status
= UfsGetReturnDataFromQueryResponse (Packet
, QueryResp
);
965 if (EFI_ERROR (Status
)) {
966 DEBUG ((DEBUG_ERROR
, "Failed to get return data from query response\n"));
971 UfsHc
->Flush (UfsHc
);
973 UfsStopExecCmd (Private
, Slot
);
975 if (CmdDescMapping
!= NULL
) {
976 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
979 if (CmdDescHost
!= NULL
) {
980 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
987 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
989 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
990 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.
992 @retval EFI_SUCCESS The device responded correctly to the Query request.
993 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
994 combination to point to a type of UFS device descriptor.
995 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
996 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
1001 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1002 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
1008 Status
= EFI_SUCCESS
;
1010 for (Retry
= 0; Retry
< 5; Retry
++) {
1011 Status
= UfsSendDmRequestRetry (Private
, Packet
);
1012 if (!EFI_ERROR (Status
)) {
1017 DEBUG ((DEBUG_ERROR
, "Failed to get response from the device after %d retries\n", Retry
));
1022 Read or write specified device descriptor of a UFS device.
1024 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1025 @param[in] Read The boolean variable to show r/w direction.
1026 @param[in] DescId The ID of device descriptor.
1027 @param[in] Index The Index of device descriptor.
1028 @param[in] Selector The Selector of device descriptor.
1029 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
1030 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
1031 of the data buffer specified by Descriptor. On output, the number
1032 of bytes that were actually transferred.
1034 @retval EFI_SUCCESS The device descriptor was read/written successfully.
1035 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a
1036 type of UFS device descriptor.
1037 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
1038 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
1043 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1048 IN OUT VOID
*Descriptor
,
1049 IN OUT UINT32
*DescSize
1052 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1055 if (DescSize
== NULL
) {
1056 return EFI_INVALID_PARAMETER
;
1059 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1062 Packet
.DataDirection
= UfsDataIn
;
1063 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
1065 Packet
.DataDirection
= UfsDataOut
;
1066 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
1069 Packet
.DataBuffer
= Descriptor
;
1070 Packet
.TransferLength
= *DescSize
;
1071 Packet
.DescId
= DescId
;
1072 Packet
.Index
= Index
;
1073 Packet
.Selector
= Selector
;
1074 Packet
.Timeout
= UFS_TIMEOUT
;
1076 Status
= UfsSendDmRequest (Private
, &Packet
);
1077 if (EFI_ERROR (Status
)) {
1080 *DescSize
= Packet
.TransferLength
;
1087 Read or write specified attribute of a UFS device.
1089 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1090 @param[in] Read The boolean variable to show r/w direction.
1091 @param[in] AttrId The ID of Attribute.
1092 @param[in] Index The Index of Attribute.
1093 @param[in] Selector The Selector of Attribute.
1094 @param[in, out] Attributes The value of Attribute to be read or written.
1096 @retval EFI_SUCCESS The Attribute was read/written successfully.
1097 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a
1098 type of UFS device descriptor.
1099 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
1100 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
1105 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1110 IN OUT UINT32
*Attributes
1113 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1115 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1118 Packet
.DataDirection
= UfsDataIn
;
1119 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
1121 Packet
.DataDirection
= UfsDataOut
;
1122 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
1125 Packet
.DataBuffer
= Attributes
;
1126 Packet
.DescId
= AttrId
;
1127 Packet
.Index
= Index
;
1128 Packet
.Selector
= Selector
;
1129 Packet
.Timeout
= UFS_TIMEOUT
;
1131 return UfsSendDmRequest (Private
, &Packet
);
1135 Read or write specified flag of a UFS device.
1137 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1138 @param[in] Read The boolean variable to show r/w direction.
1139 @param[in] FlagId The ID of flag to be read or written.
1140 @param[in, out] Value The value to set or clear flag.
1142 @retval EFI_SUCCESS The flag was read/written successfully.
1143 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.
1144 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1145 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1150 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1156 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1158 if (Value
== NULL
) {
1159 return EFI_INVALID_PARAMETER
;
1162 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1165 ASSERT (Value
!= NULL
);
1166 Packet
.DataDirection
= UfsDataIn
;
1167 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1169 Packet
.DataDirection
= UfsDataOut
;
1171 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1172 } else if (*Value
== 0) {
1173 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1175 return EFI_INVALID_PARAMETER
;
1179 Packet
.DataBuffer
= Value
;
1180 Packet
.DescId
= FlagId
;
1182 Packet
.Selector
= 0;
1183 Packet
.Timeout
= UFS_TIMEOUT
;
1185 return UfsSendDmRequest (Private
, &Packet
);
1189 Set specified flag to 1 on a UFS device.
1191 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1192 @param[in] FlagId The ID of flag to be set.
1194 @retval EFI_SUCCESS The flag was set successfully.
1195 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1196 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1201 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1209 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1215 Read specified flag from a UFS device.
1217 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1218 @param[in] FlagId The ID of flag to be read.
1219 @param[out] Value The flag's value.
1221 @retval EFI_SUCCESS The flag was read successfully.
1222 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1223 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1228 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1235 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1241 Sends NOP IN cmd to a UFS device for initialization process request.
1242 For more details, please refer to UFS 2.0 spec Figure 13.3.
1244 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1246 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1247 received successfully.
1248 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1249 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1250 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1255 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1261 UTP_NOP_IN_UPIU
*NopInUpiu
;
1264 VOID
*CmdDescMapping
;
1265 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1268 // Find out which slot of transfer request list is available.
1270 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1271 if (EFI_ERROR (Status
)) {
1275 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1276 Status
= UfsCreateNopCommandDesc (Private
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1277 if (EFI_ERROR (Status
)) {
1282 // Check the transfer request result.
1284 UfsHc
= Private
->UfsHostController
;
1285 NopInUpiu
= (UTP_NOP_IN_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1286 ASSERT (NopInUpiu
!= NULL
);
1287 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1290 // Start to execute the transfer request.
1292 UfsStartExecCmd (Private
, Slot
);
1295 // Wait for the completion of the transfer request.
1297 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1298 if (EFI_ERROR (Status
)) {
1302 if (NopInUpiu
->Resp
!= 0) {
1303 Status
= EFI_DEVICE_ERROR
;
1305 Status
= EFI_SUCCESS
;
1309 UfsHc
->Flush (UfsHc
);
1311 UfsStopExecCmd (Private
, Slot
);
1313 if (CmdDescMapping
!= NULL
) {
1314 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1317 if (CmdDescHost
!= NULL
) {
1318 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1325 Cleanup data buffers after data transfer. This function
1326 also takes care to copy all data to user memory pool for
1327 unaligned data transfers.
1329 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA
1330 @param[in] TransReq Pointer to the transfer request
1333 UfsReconcileDataTransferBuffer (
1334 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1335 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
1338 if (TransReq
->DataBufMapping
!= NULL
) {
1339 Private
->UfsHostController
->Unmap (
1340 Private
->UfsHostController
,
1341 TransReq
->DataBufMapping
1346 // Check if unaligned transfer was performed. If it was and we read
1347 // data from device copy memory to user data buffers before cleanup.
1348 // The assumption is if auxiliary aligned data buffer is not NULL then
1349 // unaligned transfer has been performed.
1351 if (TransReq
->AlignedDataBuf
!= NULL
) {
1352 if (TransReq
->Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1353 CopyMem (TransReq
->Packet
->InDataBuffer
, TransReq
->AlignedDataBuf
, TransReq
->Packet
->InTransferLength
);
1357 // Wipe out the transfer buffer in case it contains sensitive data.
1359 ZeroMem (TransReq
->AlignedDataBuf
, TransReq
->AlignedDataBufSize
);
1360 FreeAlignedPages (TransReq
->AlignedDataBuf
, EFI_SIZE_TO_PAGES (TransReq
->AlignedDataBufSize
));
1361 TransReq
->AlignedDataBuf
= NULL
;
1366 Prepare data buffer for transfer.
1368 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA
1369 @param[in, out] TransReq Pointer to the transfer request
1371 @retval EFI_DEVICE_ERROR Failed to prepare buffer for transfer
1372 @retval EFI_SUCCESS Buffer ready for transfer
1375 UfsPrepareDataTransferBuffer (
1376 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1377 IN OUT UFS_PASS_THRU_TRANS_REQ
*TransReq
1384 EFI_PHYSICAL_ADDRESS DataBufPhyAddr
;
1385 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag
;
1386 UTP_TR_PRD
*PrdtBase
;
1392 // For unaligned data transfers we allocate auxiliary DWORD aligned memory pool.
1393 // When command is finished auxiliary memory pool is copied into actual user memory.
1394 // This is requiered to assure data transfer safety(DWORD alignment required by UFS spec.)
1396 if (TransReq
->Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1397 if (((UINTN
)TransReq
->Packet
->InDataBuffer
% 4 != 0) || (TransReq
->Packet
->InTransferLength
% 4 != 0)) {
1398 DataLen
= TransReq
->Packet
->InTransferLength
+ (4 - (TransReq
->Packet
->InTransferLength
% 4));
1399 DataBuf
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen
), 4);
1400 if (DataBuf
== NULL
) {
1401 return EFI_DEVICE_ERROR
;
1404 ZeroMem (DataBuf
, DataLen
);
1405 TransReq
->AlignedDataBuf
= DataBuf
;
1406 TransReq
->AlignedDataBufSize
= DataLen
;
1408 DataLen
= TransReq
->Packet
->InTransferLength
;
1409 DataBuf
= TransReq
->Packet
->InDataBuffer
;
1412 Flag
= EdkiiUfsHcOperationBusMasterWrite
;
1414 if (((UINTN
)TransReq
->Packet
->OutDataBuffer
% 4 != 0) || (TransReq
->Packet
->OutTransferLength
% 4 != 0)) {
1415 DataLen
= TransReq
->Packet
->OutTransferLength
+ (4 - (TransReq
->Packet
->OutTransferLength
% 4));
1416 DataBuf
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen
), 4);
1417 if (DataBuf
== NULL
) {
1418 return EFI_DEVICE_ERROR
;
1421 CopyMem (DataBuf
, TransReq
->Packet
->OutDataBuffer
, TransReq
->Packet
->OutTransferLength
);
1422 TransReq
->AlignedDataBuf
= DataBuf
;
1423 TransReq
->AlignedDataBufSize
= DataLen
;
1425 DataLen
= TransReq
->Packet
->OutTransferLength
;
1426 DataBuf
= TransReq
->Packet
->OutDataBuffer
;
1429 Flag
= EdkiiUfsHcOperationBusMasterRead
;
1433 MapLength
= DataLen
;
1434 Status
= Private
->UfsHostController
->Map (
1435 Private
->UfsHostController
,
1440 &TransReq
->DataBufMapping
1443 if (EFI_ERROR (Status
) || (DataLen
!= MapLength
)) {
1444 if (TransReq
->AlignedDataBuf
!= NULL
) {
1446 // Wipe out the transfer buffer in case it contains sensitive data.
1448 ZeroMem (TransReq
->AlignedDataBuf
, TransReq
->AlignedDataBufSize
);
1449 FreeAlignedPages (TransReq
->AlignedDataBuf
, EFI_SIZE_TO_PAGES (TransReq
->AlignedDataBufSize
));
1450 TransReq
->AlignedDataBuf
= NULL
;
1453 return EFI_DEVICE_ERROR
;
1458 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1460 PrdtBase
= (UTP_TR_PRD
*)((UINT8
*)TransReq
->CmdDescHost
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
1461 ASSERT (PrdtBase
!= NULL
);
1462 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)DataBufPhyAddr
, DataLen
);
1468 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1470 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1471 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1472 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1474 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1475 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1476 Event is not NULL and non blocking I/O is supported, then
1477 nonblocking I/O is performed, and Event will be signaled when the
1478 SCSI Request Packet completes.
1480 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1481 commands, InTransferLength bytes were transferred from
1482 InDataBuffer. For write and bi-directional commands,
1483 OutTransferLength bytes were transferred by
1485 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1487 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1488 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1493 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1495 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
1496 IN EFI_EVENT Event OPTIONAL
1500 UTP_RESPONSE_UPIU
*Response
;
1501 UINT16 SenseDataLen
;
1502 UINT32 ResTranCount
;
1504 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
1505 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1507 TransReq
= AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ
));
1508 if (TransReq
== NULL
) {
1509 return EFI_OUT_OF_RESOURCES
;
1512 TransReq
->Signature
= UFS_PASS_THRU_TRANS_REQ_SIG
;
1513 TransReq
->TimeoutRemain
= Packet
->Timeout
;
1514 TransReq
->Packet
= Packet
;
1516 UfsHc
= Private
->UfsHostController
;
1518 // Find out which slot of transfer request list is available.
1520 Status
= UfsFindAvailableSlotInTrl (Private
, &TransReq
->Slot
);
1521 if (EFI_ERROR (Status
)) {
1525 TransReq
->Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + TransReq
->Slot
;
1528 // Fill transfer request descriptor to this slot.
1530 Status
= UfsCreateScsiCommandDesc (
1535 &TransReq
->CmdDescHost
,
1536 &TransReq
->CmdDescMapping
1538 if (EFI_ERROR (Status
)) {
1542 TransReq
->CmdDescSize
= TransReq
->Trd
->PrdtO
* sizeof (UINT32
) + TransReq
->Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1544 Status
= UfsPrepareDataTransferBuffer (Private
, TransReq
);
1545 if (EFI_ERROR (Status
)) {
1550 // Insert the async SCSI cmd to the Async I/O list
1552 if (Event
!= NULL
) {
1553 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1554 TransReq
->CallerEvent
= Event
;
1555 InsertTailList (&Private
->Queue
, &TransReq
->TransferList
);
1556 gBS
->RestoreTPL (OldTpl
);
1560 // Start to execute the transfer request.
1562 UfsStartExecCmd (Private
, TransReq
->Slot
);
1565 // Immediately return for async I/O.
1567 if (Event
!= NULL
) {
1572 // Wait for the completion of the transfer request.
1574 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< TransReq
->Slot
, 0, Packet
->Timeout
);
1575 if (EFI_ERROR (Status
)) {
1580 // Get sense data if exists
1582 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
1583 ASSERT (Response
!= NULL
);
1584 SenseDataLen
= Response
->SenseDataLen
;
1585 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1587 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1589 // Make sure the hardware device does not return more data than expected.
1591 if (SenseDataLen
<= Packet
->SenseDataLength
) {
1592 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1593 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1595 Packet
->SenseDataLength
= 0;
1600 // Check the transfer request result.
1602 Packet
->TargetStatus
= Response
->Status
;
1603 if (Response
->Response
!= 0) {
1604 DEBUG ((DEBUG_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1605 Status
= EFI_DEVICE_ERROR
;
1609 if (TransReq
->Trd
->Ocs
== 0) {
1610 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1611 if ((Response
->Flags
& BIT5
) == BIT5
) {
1612 ResTranCount
= Response
->ResTranCount
;
1613 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1614 Packet
->InTransferLength
-= ResTranCount
;
1617 if ((Response
->Flags
& BIT5
) == BIT5
) {
1618 ResTranCount
= Response
->ResTranCount
;
1619 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1620 Packet
->OutTransferLength
-= ResTranCount
;
1624 Status
= EFI_DEVICE_ERROR
;
1628 UfsHc
->Flush (UfsHc
);
1630 UfsStopExecCmd (Private
, TransReq
->Slot
);
1632 UfsReconcileDataTransferBuffer (Private
, TransReq
);
1635 if (TransReq
->CmdDescMapping
!= NULL
) {
1636 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
1639 if (TransReq
->CmdDescHost
!= NULL
) {
1640 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
), TransReq
->CmdDescHost
);
1643 if (TransReq
!= NULL
) {
1644 FreePool (TransReq
);
1653 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1654 @param[in, out] UicCommand UIC command descriptor. On exit contains UIC command results.
1656 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1657 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1661 UfsExecUicCommands (
1662 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1663 IN OUT EDKII_UIC_COMMAND
*UicCommand
1669 Status
= UfsMmioRead32 (Private
, UFS_HC_IS_OFFSET
, &Data
);
1670 if (EFI_ERROR (Status
)) {
1674 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1676 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1678 Status
= UfsMmioWrite32 (Private
, UFS_HC_IS_OFFSET
, Data
);
1679 if (EFI_ERROR (Status
)) {
1685 // When programming UIC command registers, host software shall set the register UICCMD
1686 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1689 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG1_OFFSET
, UicCommand
->Arg1
);
1690 if (EFI_ERROR (Status
)) {
1694 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, UicCommand
->Arg2
);
1695 if (EFI_ERROR (Status
)) {
1699 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, UicCommand
->Arg3
);
1700 if (EFI_ERROR (Status
)) {
1705 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1707 Status
= UfsWaitMemSet (Private
, UFS_HC_STATUS_OFFSET
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1708 if (EFI_ERROR (Status
)) {
1712 Status
= UfsMmioWrite32 (Private
, UFS_HC_UIC_CMD_OFFSET
, UicCommand
->Opcode
);
1713 if (EFI_ERROR (Status
)) {
1718 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1719 // This bit is set to '1' by the host controller upon completion of a UIC command.
1721 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1722 if (EFI_ERROR (Status
)) {
1726 if (UicCommand
->Opcode
!= UfsUicDmeReset
) {
1727 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, &UicCommand
->Arg2
);
1728 if (EFI_ERROR (Status
)) {
1732 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, &UicCommand
->Arg3
);
1733 if (EFI_ERROR (Status
)) {
1737 if ((UicCommand
->Arg2
& 0xFF) != 0) {
1738 DEBUG_CODE_BEGIN ();
1739 DumpUicCmdExecResult ((UINT8
)UicCommand
->Opcode
, (UINT8
)(UicCommand
->Arg2
& 0xFF));
1741 return EFI_DEVICE_ERROR
;
1749 Allocate common buffer for host and UFS bus master access simultaneously.
1751 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1752 @param[in] Size The length of buffer to be allocated.
1753 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1754 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1755 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1757 @retval EFI_SUCCESS The common buffer was allocated successfully.
1758 @retval EFI_DEVICE_ERROR The allocation fails.
1759 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1763 UfsAllocateAlignCommonBuffer (
1764 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1766 OUT VOID
**CmdDescHost
,
1767 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1768 OUT VOID
**CmdDescMapping
1773 BOOLEAN Is32BitAddr
;
1774 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1776 if ((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1777 Is32BitAddr
= FALSE
;
1782 UfsHc
= Private
->UfsHostController
;
1783 Status
= UfsHc
->AllocateBuffer (
1786 EfiBootServicesData
,
1787 EFI_SIZE_TO_PAGES (Size
),
1791 if (EFI_ERROR (Status
)) {
1792 *CmdDescMapping
= NULL
;
1793 *CmdDescHost
= NULL
;
1794 *CmdDescPhyAddr
= 0;
1795 return EFI_OUT_OF_RESOURCES
;
1798 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1799 Status
= UfsHc
->Map (
1801 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1808 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1811 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1814 *CmdDescHost
= NULL
;
1815 return EFI_OUT_OF_RESOURCES
;
1818 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1820 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1828 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1831 *CmdDescMapping
= NULL
;
1832 *CmdDescHost
= NULL
;
1833 return EFI_DEVICE_ERROR
;
1836 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1841 Enable the UFS host controller for accessing.
1843 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1845 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1846 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1850 UfsEnableHostController (
1851 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1857 if ((mUfsHcPlatform
!= NULL
) && (mUfsHcPlatform
->Callback
!= NULL
)) {
1858 Status
= mUfsHcPlatform
->Callback (Private
->Handle
, EdkiiUfsHcPreHce
, &Private
->UfsHcDriverInterface
);
1859 if (EFI_ERROR (Status
)) {
1860 DEBUG ((DEBUG_ERROR
, "Failure from platform driver during EdkiiUfsHcPreHce, Status = %r\n", Status
));
1866 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1868 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1870 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
1871 if (EFI_ERROR (Status
)) {
1875 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1877 // Write a 0 to the HCE register at first to disable the host controller.
1879 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
1880 if (EFI_ERROR (Status
)) {
1885 // Wait until HCE is read as '0' before continuing.
1887 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1888 if (EFI_ERROR (Status
)) {
1889 return EFI_DEVICE_ERROR
;
1894 // Write a 1 to the HCE register to enable the UFS host controller.
1896 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
);
1897 if (EFI_ERROR (Status
)) {
1902 // Wait until HCE is read as '1' before continuing.
1904 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1905 if (EFI_ERROR (Status
)) {
1906 return EFI_DEVICE_ERROR
;
1909 if ((mUfsHcPlatform
!= NULL
) && (mUfsHcPlatform
->Callback
!= NULL
)) {
1910 Status
= mUfsHcPlatform
->Callback (Private
->Handle
, EdkiiUfsHcPostHce
, &Private
->UfsHcDriverInterface
);
1911 if (EFI_ERROR (Status
)) {
1912 DEBUG ((DEBUG_ERROR
, "Failure from platform driver during EdkiiUfsHcPostHce, Status = %r\n", Status
));
1921 Detect if a UFS device attached.
1923 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1925 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1926 @retval EFI_NOT_FOUND Not found a UFS device attached.
1927 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1931 UfsDeviceDetection (
1932 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1938 EDKII_UIC_COMMAND LinkStartupCommand
;
1940 if ((mUfsHcPlatform
!= NULL
) && (mUfsHcPlatform
->Callback
!= NULL
)) {
1941 Status
= mUfsHcPlatform
->Callback (Private
->Handle
, EdkiiUfsHcPreLinkStartup
, &Private
->UfsHcDriverInterface
);
1942 if (EFI_ERROR (Status
)) {
1943 DEBUG ((DEBUG_ERROR
, "Failure from platform driver during EdkiiUfsHcPreLinkStartup, Status = %r\n", Status
));
1949 // Start UFS device detection.
1950 // Try up to 3 times for establishing data link with device.
1952 for (Retry
= 0; Retry
< 3; Retry
++) {
1953 LinkStartupCommand
.Opcode
= UfsUicDmeLinkStartup
;
1954 LinkStartupCommand
.Arg1
= 0;
1955 LinkStartupCommand
.Arg2
= 0;
1956 LinkStartupCommand
.Arg3
= 0;
1957 Status
= UfsExecUicCommands (Private
, &LinkStartupCommand
);
1958 if (EFI_ERROR (Status
)) {
1959 return EFI_DEVICE_ERROR
;
1962 Status
= UfsMmioRead32 (Private
, UFS_HC_STATUS_OFFSET
, &Data
);
1963 if (EFI_ERROR (Status
)) {
1964 return EFI_DEVICE_ERROR
;
1967 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1968 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1969 if (EFI_ERROR (Status
)) {
1970 return EFI_DEVICE_ERROR
;
1973 if ((mUfsHcPlatform
!= NULL
) && (mUfsHcPlatform
->Callback
!= NULL
)) {
1974 Status
= mUfsHcPlatform
->Callback (Private
->Handle
, EdkiiUfsHcPostLinkStartup
, &Private
->UfsHcDriverInterface
);
1975 if (EFI_ERROR (Status
)) {
1976 DEBUG ((DEBUG_ERROR
, "Failure from platform driver during EdkiiUfsHcPostLinkStartup, Status = %r\n", Status
));
1985 return EFI_NOT_FOUND
;
1989 Initialize UFS task management request list related h/w context.
1991 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1993 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1994 @retval EFI_DEVICE_ERROR The initialization fails.
1998 UfsInitTaskManagementRequestList (
1999 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2004 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
2005 VOID
*CmdDescMapping
;
2009 // Initial h/w and s/w context for future operations.
2012 CmdDescMapping
= NULL
;
2016 // Allocate and initialize UTP Task Management Request List.
2018 Nutmrs
= (UINT8
)(RShiftU64 ((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
2019 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
2020 if (EFI_ERROR (Status
)) {
2025 // Program the UTP Task Management Request List Base Address and UTP Task Management
2026 // Request List Base Address with a 64-bit address allocated at step 6.
2028 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
2029 if (EFI_ERROR (Status
)) {
2033 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
2034 if (EFI_ERROR (Status
)) {
2038 Private
->UtpTmrlBase
= CmdDescHost
;
2039 Private
->Nutmrs
= Nutmrs
;
2040 Private
->TmrlMapping
= CmdDescMapping
;
2043 // Enable the UTP Task Management Request List by setting the UTP Task Management
2044 // Request List RunStop Register (UTMRLRSR) to '1'.
2046 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
2047 if (EFI_ERROR (Status
)) {
2055 Initialize UFS transfer request list related h/w context.
2057 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2059 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
2060 @retval EFI_DEVICE_ERROR The initialization fails.
2064 UfsInitTransferRequestList (
2065 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2070 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
2071 VOID
*CmdDescMapping
;
2075 // Initial h/w and s/w context for future operations.
2078 CmdDescMapping
= NULL
;
2082 // Allocate and initialize UTP Transfer Request List.
2084 Nutrs
= (UINT8
)((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
2085 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
2086 if (EFI_ERROR (Status
)) {
2091 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
2092 // Base Address with a 64-bit address allocated at step 8.
2094 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
2095 if (EFI_ERROR (Status
)) {
2099 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
2100 if (EFI_ERROR (Status
)) {
2104 Private
->UtpTrlBase
= CmdDescHost
;
2105 Private
->Nutrs
= Nutrs
;
2106 Private
->TrlMapping
= CmdDescMapping
;
2109 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2110 // RunStop Register (UTRLRSR) to '1'.
2112 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
2113 if (EFI_ERROR (Status
)) {
2121 Initialize the UFS host controller.
2123 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2125 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2126 @retval Others A device error occurred while initializing the controller.
2131 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2136 Status
= UfsEnableHostController (Private
);
2137 if (EFI_ERROR (Status
)) {
2138 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2142 Status
= UfsDeviceDetection (Private
);
2143 if (EFI_ERROR (Status
)) {
2144 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2148 Status
= UfsInitTaskManagementRequestList (Private
);
2149 if (EFI_ERROR (Status
)) {
2150 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2154 Status
= UfsInitTransferRequestList (Private
);
2155 if (EFI_ERROR (Status
)) {
2156 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2160 DEBUG ((DEBUG_INFO
, "UfsControllerInit Finished\n"));
2165 Stop the UFS host controller.
2167 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2169 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2170 @retval Others A device error occurred while stopping the controller.
2175 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2182 // Enable the UTP Task Management Request List by setting the UTP Task Management
2183 // Request List RunStop Register (UTMRLRSR) to '1'.
2185 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2186 if (EFI_ERROR (Status
)) {
2191 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2192 // RunStop Register (UTRLRSR) to '1'.
2194 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2195 if (EFI_ERROR (Status
)) {
2200 // Write a 0 to the HCE register in order to disable the host controller.
2202 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2203 if (EFI_ERROR (Status
)) {
2207 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2209 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2210 if (EFI_ERROR (Status
)) {
2215 // Wait until HCE is read as '0' before continuing.
2217 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2218 if (EFI_ERROR (Status
)) {
2219 return EFI_DEVICE_ERROR
;
2222 DEBUG ((DEBUG_INFO
, "UfsController is stopped\n"));
2228 Internal helper function which will signal the caller event and clean up
2231 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2233 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2240 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
2241 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
2244 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
2245 EFI_EVENT CallerEvent
;
2247 ASSERT ((Private
!= NULL
) && (TransReq
!= NULL
));
2249 UfsHc
= Private
->UfsHostController
;
2250 CallerEvent
= TransReq
->CallerEvent
;
2252 RemoveEntryList (&TransReq
->TransferList
);
2254 UfsHc
->Flush (UfsHc
);
2256 UfsStopExecCmd (Private
, TransReq
->Slot
);
2258 UfsReconcileDataTransferBuffer (Private
, TransReq
);
2260 if (TransReq
->CmdDescMapping
!= NULL
) {
2261 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
2264 if (TransReq
->CmdDescHost
!= NULL
) {
2267 EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
),
2268 TransReq
->CmdDescHost
2272 FreePool (TransReq
);
2274 gBS
->SignalEvent (CallerEvent
);
2279 Call back function when the timer event is signaled.
2281 @param[in] Event The Event this notify function registered to.
2282 @param[in] Context Pointer to the context data registered to the Event.
2287 ProcessAsyncTaskList (
2292 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2294 LIST_ENTRY
*NextEntry
;
2295 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
2296 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
;
2297 UTP_RESPONSE_UPIU
*Response
;
2298 UINT16 SenseDataLen
;
2299 UINT32 ResTranCount
;
2304 Private
= (UFS_PASS_THRU_PRIVATE_DATA
*)Context
;
2308 // Check the entries in the async I/O queue are done or not.
2310 if (!IsListEmpty (&Private
->Queue
)) {
2311 BASE_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
2312 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
2313 Packet
= TransReq
->Packet
;
2315 if ((SlotsMap
& (BIT0
<< TransReq
->Slot
)) != 0) {
2319 SlotsMap
|= BIT0
<< TransReq
->Slot
;
2321 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Value
);
2322 if (EFI_ERROR (Status
)) {
2324 // TODO: Should find/add a proper host adapter return status for this
2327 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
2328 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq
->CallerEvent
));
2329 SignalCallerEvent (Private
, TransReq
);
2333 if ((Value
& (BIT0
<< TransReq
->Slot
)) != 0) {
2335 // Scsi cmd not finished yet.
2337 if (TransReq
->TimeoutRemain
> UFS_HC_ASYNC_TIMER
) {
2338 TransReq
->TimeoutRemain
-= UFS_HC_ASYNC_TIMER
;
2344 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
2345 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq
->CallerEvent
));
2346 SignalCallerEvent (Private
, TransReq
);
2351 // Scsi cmd finished.
2353 // Get sense data if exists
2355 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
2356 ASSERT (Response
!= NULL
);
2357 SenseDataLen
= Response
->SenseDataLen
;
2358 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
2360 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
2362 // Make sure the hardware device does not return more data than expected.
2364 if (SenseDataLen
<= Packet
->SenseDataLength
) {
2365 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
2366 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
2368 Packet
->SenseDataLength
= 0;
2373 // Check the transfer request result.
2375 Packet
->TargetStatus
= Response
->Status
;
2376 if (Response
->Response
!= 0) {
2377 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq
->CallerEvent
));
2378 SignalCallerEvent (Private
, TransReq
);
2382 if (TransReq
->Trd
->Ocs
== 0) {
2383 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2384 if ((Response
->Flags
& BIT5
) == BIT5
) {
2385 ResTranCount
= Response
->ResTranCount
;
2386 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2387 Packet
->InTransferLength
-= ResTranCount
;
2390 if ((Response
->Flags
& BIT5
) == BIT5
) {
2391 ResTranCount
= Response
->ResTranCount
;
2392 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2393 Packet
->OutTransferLength
-= ResTranCount
;
2397 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq
->CallerEvent
));
2398 SignalCallerEvent (Private
, TransReq
);
2402 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq
->CallerEvent
));
2403 SignalCallerEvent (Private
, TransReq
);
2410 Execute UIC command.
2412 @param[in] This Pointer to driver interface produced by the UFS controller.
2413 @param[in, out] UicCommand Descriptor of the command that will be executed.
2415 @retval EFI_SUCCESS Command executed successfully.
2416 @retval EFI_INVALID_PARAMETER This or UicCommand is NULL.
2417 @retval Others Command failed to execute.
2421 UfsHcDriverInterfaceExecUicCommand (
2422 IN EDKII_UFS_HC_DRIVER_INTERFACE
*This
,
2423 IN OUT EDKII_UIC_COMMAND
*UicCommand
2426 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2428 if ((This
== NULL
) || (UicCommand
== NULL
)) {
2429 return EFI_INVALID_PARAMETER
;
2432 Private
= UFS_PASS_THRU_PRIVATE_DATA_FROM_DRIVER_INTF (This
);
2434 return UfsExecUicCommands (Private
, UicCommand
);
2438 Initializes UfsHcInfo field in private data.
2440 @param[in] Private Pointer to host controller private data.
2442 @retval EFI_SUCCESS UfsHcInfo initialized successfully.
2443 @retval Others Failed to initalize UfsHcInfo.
2447 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2453 Status
= UfsMmioRead32 (Private
, UFS_HC_VER_OFFSET
, &Data
);
2454 if (EFI_ERROR (Status
)) {
2458 Private
->UfsHcInfo
.Version
= Data
;
2460 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
2461 if (EFI_ERROR (Status
)) {
2465 Private
->UfsHcInfo
.Capabilities
= Data
;
2467 if ((mUfsHcPlatform
!= NULL
) && (mUfsHcPlatform
->OverrideHcInfo
!= NULL
)) {
2468 Status
= mUfsHcPlatform
->OverrideHcInfo (Private
->Handle
, &Private
->UfsHcInfo
);
2469 if (EFI_ERROR (Status
)) {
2470 DEBUG ((DEBUG_ERROR
, "Failure from platform on OverrideHcInfo, Status = %r\n", Status
));