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 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "UfsPassThru.h"
13 Read 32bits data from specified UFS MMIO register.
15 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
16 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
18 @param[out] Value The data buffer to store.
20 @retval EFI_TIMEOUT The operation is time out.
21 @retval EFI_SUCCESS The operation succeeds.
22 @retval Others The operation fails.
27 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
32 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
35 UfsHc
= Private
->UfsHostController
;
37 Status
= UfsHc
->Read (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, Value
);
43 Write 32bits data to specified UFS MMIO register.
45 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
46 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
48 @param[in] Value The data to write.
50 @retval EFI_TIMEOUT The operation is time out.
51 @retval EFI_SUCCESS The operation succeeds.
52 @retval Others The operation fails.
57 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
62 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
65 UfsHc
= Private
->UfsHostController
;
67 Status
= UfsHc
->Write (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, &Value
);
73 Wait for the value of the specified system memory set to the test value.
75 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
76 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
78 @param[in] MaskValue The mask value of memory.
79 @param[in] TestValue The test value of memory.
80 @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.
82 @retval EFI_TIMEOUT The system memory setting is time out.
83 @retval EFI_SUCCESS The system memory is correct set.
84 @retval Others The operation fails.
89 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
104 InfiniteWait
= FALSE
;
107 Delay
= DivU64x32 (Timeout
, 10) + 1;
111 // Access PCI MMIO space to see if the value is the tested one.
113 Status
= UfsMmioRead32 (Private
, Offset
, &Value
);
114 if (EFI_ERROR (Status
)) {
120 if (Value
== TestValue
) {
125 // Stall for 1 microseconds.
127 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
;
605 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
607 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
610 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
611 if (EFI_ERROR (Status
)) {
616 // Initialize UTP QUERY REQUEST UPIU
618 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)*CmdDescHost
;
619 ASSERT (QueryReqUpiu
!= NULL
);
620 UfsInitQueryRequestUpiu (
632 // Fill UTP_TRD associated fields
633 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
635 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
636 Trd
->Dd
= DataDirection
;
637 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
638 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
639 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
640 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
641 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
642 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
643 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
645 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
646 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
653 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
655 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
656 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
657 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
658 @param[out] CmdDescMapping A resulting value to pass to Unmap().
660 @retval EFI_SUCCESS The creation succeed.
661 @retval EFI_DEVICE_ERROR The creation failed.
662 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
666 UfsCreateNopCommandDesc (
667 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
669 OUT VOID
**CmdDescHost
,
670 OUT VOID
**CmdDescMapping
674 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
676 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
678 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
680 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
681 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
682 if (EFI_ERROR (Status
)) {
686 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)*CmdDescHost
;
687 ASSERT (NopOutUpiu
!= NULL
);
688 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
691 // Fill UTP_TRD associated fields
692 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
694 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
696 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
697 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
698 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
699 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
700 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
701 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
707 Find out available slot in transfer list of a UFS device.
709 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
710 @param[out] Slot The available slot.
712 @retval EFI_SUCCESS The available slot was found successfully.
713 @retval EFI_NOT_READY No slot is available at this moment.
717 UfsFindAvailableSlotInTrl (
718 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
727 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
729 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
730 if (EFI_ERROR (Status
)) {
734 Nutrs
= (UINT8
)((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
736 for (Index
= 0; Index
< Nutrs
; Index
++) {
737 if ((Data
& (BIT0
<< Index
)) == 0) {
743 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
:
866 CopyMem (Packet
->DataBuffer
, &QueryResp
->Tsf
.Value
, sizeof (UINT8
));
868 case UtpQueryFuncOpcodeRdAttr
:
869 case UtpQueryFuncOpcodeWrAttr
:
870 ReturnData
= QueryResp
->Tsf
.Value
;
871 SwapLittleEndianToBigEndian ((UINT8
*) &ReturnData
, sizeof (UINT32
));
872 CopyMem (Packet
->DataBuffer
, &ReturnData
, sizeof (UINT32
));
875 return EFI_INVALID_PARAMETER
;
882 Creates Transfer Request descriptor and sends Query Request to the device.
884 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
885 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
887 @retval EFI_SUCCESS The device descriptor was read/written successfully.
888 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
889 combination to point to a type of UFS device descriptor.
890 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
891 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
895 UfsSendDmRequestRetry (
896 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
897 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
903 VOID
*CmdDescMapping
;
905 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
906 UTP_QUERY_RESP_UPIU
*QueryResp
;
910 // Find out which slot of transfer request list is available.
912 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
913 if (EFI_ERROR (Status
)) {
917 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
919 // Fill transfer request descriptor to this slot.
921 Status
= UfsCreateDMCommandDesc (Private
, Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
922 if (EFI_ERROR (Status
)) {
923 DEBUG ((DEBUG_ERROR
, "Failed to create DM command descriptor\n"));
927 UfsHc
= Private
->UfsHostController
;
928 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
929 ASSERT (QueryResp
!= NULL
);
930 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
933 // Start to execute the transfer request.
935 UfsStartExecCmd (Private
, Slot
);
938 // Wait for the completion of the transfer request.
940 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
, 0, Packet
->Timeout
);
941 if (EFI_ERROR (Status
)) {
945 if (Trd
->Ocs
!= 0 || QueryResp
->QueryResp
!= UfsUtpQueryResponseSuccess
) {
946 DEBUG ((DEBUG_ERROR
, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd
->Ocs
, QueryResp
->QueryResp
));
947 DumpQueryResponseResult (QueryResp
->QueryResp
);
949 if ((QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidSelector
) ||
950 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIndex
) ||
951 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIdn
)) {
952 Status
= EFI_INVALID_PARAMETER
;
954 Status
= EFI_DEVICE_ERROR
;
959 Status
= UfsGetReturnDataFromQueryResponse (Packet
, QueryResp
);
960 if (EFI_ERROR (Status
)) {
961 DEBUG ((DEBUG_ERROR
, "Failed to get return data from query response\n"));
966 UfsHc
->Flush (UfsHc
);
968 UfsStopExecCmd (Private
, Slot
);
970 if (CmdDescMapping
!= NULL
) {
971 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
973 if (CmdDescHost
!= NULL
) {
974 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
981 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
983 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
984 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.
986 @retval EFI_SUCCESS The device responded correctly to the Query request.
987 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
988 combination to point to a type of UFS device descriptor.
989 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
990 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
995 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
996 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
1002 Status
= EFI_SUCCESS
;
1004 for (Retry
= 0; Retry
< 5; Retry
++) {
1005 Status
= UfsSendDmRequestRetry (Private
, Packet
);
1006 if (!EFI_ERROR (Status
)) {
1011 DEBUG ((DEBUG_ERROR
, "Failed to get response from the device after %d retries\n", Retry
));
1016 Read or write specified device descriptor of a UFS device.
1018 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1019 @param[in] Read The boolean variable to show r/w direction.
1020 @param[in] DescId The ID of device descriptor.
1021 @param[in] Index The Index of device descriptor.
1022 @param[in] Selector The Selector of device descriptor.
1023 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
1024 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
1025 of the data buffer specified by Descriptor. On output, the number
1026 of bytes that were actually transferred.
1028 @retval EFI_SUCCESS The device descriptor was read/written successfully.
1029 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a
1030 type of UFS device descriptor.
1031 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
1032 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
1037 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1042 IN OUT VOID
*Descriptor
,
1043 IN OUT UINT32
*DescSize
1046 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1049 if (DescSize
== NULL
) {
1050 return EFI_INVALID_PARAMETER
;
1053 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1056 Packet
.DataDirection
= UfsDataIn
;
1057 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
1059 Packet
.DataDirection
= UfsDataOut
;
1060 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
1062 Packet
.DataBuffer
= Descriptor
;
1063 Packet
.TransferLength
= *DescSize
;
1064 Packet
.DescId
= DescId
;
1065 Packet
.Index
= Index
;
1066 Packet
.Selector
= Selector
;
1067 Packet
.Timeout
= UFS_TIMEOUT
;
1069 Status
= UfsSendDmRequest (Private
, &Packet
);
1070 if (EFI_ERROR (Status
)) {
1073 *DescSize
= Packet
.TransferLength
;
1080 Read or write specified attribute of a UFS device.
1082 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1083 @param[in] Read The boolean variable to show r/w direction.
1084 @param[in] AttrId The ID of Attribute.
1085 @param[in] Index The Index of Attribute.
1086 @param[in] Selector The Selector of Attribute.
1087 @param[in, out] Attributes The value of Attribute to be read or written.
1089 @retval EFI_SUCCESS The Attribute was read/written successfully.
1090 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a
1091 type of UFS device descriptor.
1092 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
1093 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
1098 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1103 IN OUT UINT32
*Attributes
1106 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1108 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1111 Packet
.DataDirection
= UfsDataIn
;
1112 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
1114 Packet
.DataDirection
= UfsDataOut
;
1115 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
1117 Packet
.DataBuffer
= Attributes
;
1118 Packet
.DescId
= AttrId
;
1119 Packet
.Index
= Index
;
1120 Packet
.Selector
= Selector
;
1121 Packet
.Timeout
= UFS_TIMEOUT
;
1123 return UfsSendDmRequest (Private
, &Packet
);
1127 Read or write specified flag of a UFS device.
1129 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1130 @param[in] Read The boolean variable to show r/w direction.
1131 @param[in] FlagId The ID of flag to be read or written.
1132 @param[in, out] Value The value to set or clear flag.
1134 @retval EFI_SUCCESS The flag was read/written successfully.
1135 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.
1136 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1137 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1142 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1148 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1150 if (Value
== NULL
) {
1151 return EFI_INVALID_PARAMETER
;
1154 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1157 ASSERT (Value
!= NULL
);
1158 Packet
.DataDirection
= UfsDataIn
;
1159 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1161 Packet
.DataDirection
= UfsDataOut
;
1163 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1164 } else if (*Value
== 0) {
1165 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1167 return EFI_INVALID_PARAMETER
;
1170 Packet
.DataBuffer
= Value
;
1171 Packet
.DescId
= FlagId
;
1173 Packet
.Selector
= 0;
1174 Packet
.Timeout
= UFS_TIMEOUT
;
1176 return UfsSendDmRequest (Private
, &Packet
);
1180 Set specified flag to 1 on a UFS device.
1182 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1183 @param[in] FlagId The ID of flag to be set.
1185 @retval EFI_SUCCESS The flag was set successfully.
1186 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1187 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1192 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1200 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1206 Read specified flag from a UFS device.
1208 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1209 @param[in] FlagId The ID of flag to be read.
1210 @param[out] Value The flag's value.
1212 @retval EFI_SUCCESS The flag was read successfully.
1213 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1214 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1219 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1226 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1232 Sends NOP IN cmd to a UFS device for initialization process request.
1233 For more details, please refer to UFS 2.0 spec Figure 13.3.
1235 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1237 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1238 received successfully.
1239 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1240 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1241 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1246 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1252 UTP_NOP_IN_UPIU
*NopInUpiu
;
1255 VOID
*CmdDescMapping
;
1256 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1259 // Find out which slot of transfer request list is available.
1261 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1262 if (EFI_ERROR (Status
)) {
1266 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1267 Status
= UfsCreateNopCommandDesc (Private
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1268 if (EFI_ERROR (Status
)) {
1273 // Check the transfer request result.
1275 UfsHc
= Private
->UfsHostController
;
1276 NopInUpiu
= (UTP_NOP_IN_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1277 ASSERT (NopInUpiu
!= NULL
);
1278 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1281 // Start to execute the transfer request.
1283 UfsStartExecCmd (Private
, Slot
);
1286 // Wait for the completion of the transfer request.
1288 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1289 if (EFI_ERROR (Status
)) {
1293 if (NopInUpiu
->Resp
!= 0) {
1294 Status
= EFI_DEVICE_ERROR
;
1296 Status
= EFI_SUCCESS
;
1300 UfsHc
->Flush (UfsHc
);
1302 UfsStopExecCmd (Private
, Slot
);
1304 if (CmdDescMapping
!= NULL
) {
1305 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1307 if (CmdDescHost
!= NULL
) {
1308 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1315 Cleanup data buffers after data transfer. This function
1316 also takes care to copy all data to user memory pool for
1317 unaligned data transfers.
1319 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA
1320 @param[in] TransReq Pointer to the transfer request
1323 UfsReconcileDataTransferBuffer (
1324 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1325 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
1328 if (TransReq
->DataBufMapping
!= NULL
) {
1329 Private
->UfsHostController
->Unmap (
1330 Private
->UfsHostController
,
1331 TransReq
->DataBufMapping
1336 // Check if unaligned transfer was performed. If it was and we read
1337 // data from device copy memory to user data buffers before cleanup.
1338 // The assumption is if auxiliary aligned data buffer is not NULL then
1339 // unaligned transfer has been performed.
1341 if (TransReq
->AlignedDataBuf
!= NULL
) {
1342 if (TransReq
->Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1343 CopyMem (TransReq
->Packet
->InDataBuffer
, TransReq
->AlignedDataBuf
, TransReq
->Packet
->InTransferLength
);
1346 // Wipe out the transfer buffer in case it contains sensitive data.
1348 ZeroMem (TransReq
->AlignedDataBuf
, TransReq
->AlignedDataBufSize
);
1349 FreeAlignedPages (TransReq
->AlignedDataBuf
, EFI_SIZE_TO_PAGES (TransReq
->AlignedDataBufSize
));
1350 TransReq
->AlignedDataBuf
= NULL
;
1355 Prepare data buffer for transfer.
1357 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA
1358 @param[in, out] TransReq Pointer to the transfer request
1360 @retval EFI_DEVICE_ERROR Failed to prepare buffer for transfer
1361 @retval EFI_SUCCESS Buffer ready for transfer
1364 UfsPrepareDataTransferBuffer (
1365 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1366 IN OUT UFS_PASS_THRU_TRANS_REQ
*TransReq
1373 EFI_PHYSICAL_ADDRESS DataBufPhyAddr
;
1374 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag
;
1375 UTP_TR_PRD
*PrdtBase
;
1381 // For unaligned data transfers we allocate auxiliary DWORD aligned memory pool.
1382 // When command is finished auxiliary memory pool is copied into actual user memory.
1383 // This is requiered to assure data transfer safety(DWORD alignment required by UFS spec.)
1385 if (TransReq
->Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1386 if (((UINTN
)TransReq
->Packet
->InDataBuffer
% 4 != 0) || (TransReq
->Packet
->InTransferLength
% 4 != 0)) {
1387 DataLen
= TransReq
->Packet
->InTransferLength
+ (4 - (TransReq
->Packet
->InTransferLength
% 4));
1388 DataBuf
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen
), 4);
1389 if (DataBuf
== NULL
) {
1390 return EFI_DEVICE_ERROR
;
1392 ZeroMem (DataBuf
, DataLen
);
1393 TransReq
->AlignedDataBuf
= DataBuf
;
1394 TransReq
->AlignedDataBufSize
= DataLen
;
1396 DataLen
= TransReq
->Packet
->InTransferLength
;
1397 DataBuf
= TransReq
->Packet
->InDataBuffer
;
1399 Flag
= EdkiiUfsHcOperationBusMasterWrite
;
1401 if (((UINTN
)TransReq
->Packet
->OutDataBuffer
% 4 != 0) || (TransReq
->Packet
->OutTransferLength
% 4 != 0)) {
1402 DataLen
= TransReq
->Packet
->OutTransferLength
+ (4 - (TransReq
->Packet
->OutTransferLength
% 4));
1403 DataBuf
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen
), 4);
1404 if (DataBuf
== NULL
) {
1405 return EFI_DEVICE_ERROR
;
1407 CopyMem (DataBuf
, TransReq
->Packet
->OutDataBuffer
, TransReq
->Packet
->OutTransferLength
);
1408 TransReq
->AlignedDataBuf
= DataBuf
;
1409 TransReq
->AlignedDataBufSize
= DataLen
;
1411 DataLen
= TransReq
->Packet
->OutTransferLength
;
1412 DataBuf
= TransReq
->Packet
->OutDataBuffer
;
1414 Flag
= EdkiiUfsHcOperationBusMasterRead
;
1418 MapLength
= DataLen
;
1419 Status
= Private
->UfsHostController
->Map (
1420 Private
->UfsHostController
,
1425 &TransReq
->DataBufMapping
1428 if (EFI_ERROR (Status
) || (DataLen
!= MapLength
)) {
1429 if (TransReq
->AlignedDataBuf
!= NULL
) {
1431 // Wipe out the transfer buffer in case it contains sensitive data.
1433 ZeroMem (TransReq
->AlignedDataBuf
, TransReq
->AlignedDataBufSize
);
1434 FreeAlignedPages (TransReq
->AlignedDataBuf
, EFI_SIZE_TO_PAGES (TransReq
->AlignedDataBufSize
));
1435 TransReq
->AlignedDataBuf
= NULL
;
1437 return EFI_DEVICE_ERROR
;
1442 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1444 PrdtBase
= (UTP_TR_PRD
*)((UINT8
*)TransReq
->CmdDescHost
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
1445 ASSERT (PrdtBase
!= NULL
);
1446 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)DataBufPhyAddr
, DataLen
);
1452 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1454 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1455 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1456 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1458 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1459 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1460 Event is not NULL and non blocking I/O is supported, then
1461 nonblocking I/O is performed, and Event will be signaled when the
1462 SCSI Request Packet completes.
1464 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1465 commands, InTransferLength bytes were transferred from
1466 InDataBuffer. For write and bi-directional commands,
1467 OutTransferLength bytes were transferred by
1469 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1471 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1472 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1477 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1479 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
1480 IN EFI_EVENT Event OPTIONAL
1484 UTP_RESPONSE_UPIU
*Response
;
1485 UINT16 SenseDataLen
;
1486 UINT32 ResTranCount
;
1488 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
1489 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1491 TransReq
= AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ
));
1492 if (TransReq
== NULL
) {
1493 return EFI_OUT_OF_RESOURCES
;
1496 TransReq
->Signature
= UFS_PASS_THRU_TRANS_REQ_SIG
;
1497 TransReq
->TimeoutRemain
= Packet
->Timeout
;
1498 TransReq
->Packet
= Packet
;
1500 UfsHc
= Private
->UfsHostController
;
1502 // Find out which slot of transfer request list is available.
1504 Status
= UfsFindAvailableSlotInTrl (Private
, &TransReq
->Slot
);
1505 if (EFI_ERROR (Status
)) {
1509 TransReq
->Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + TransReq
->Slot
;
1512 // Fill transfer request descriptor to this slot.
1514 Status
= UfsCreateScsiCommandDesc (
1519 &TransReq
->CmdDescHost
,
1520 &TransReq
->CmdDescMapping
1522 if (EFI_ERROR (Status
)) {
1526 TransReq
->CmdDescSize
= TransReq
->Trd
->PrdtO
* sizeof (UINT32
) + TransReq
->Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1528 Status
= UfsPrepareDataTransferBuffer (Private
, TransReq
);
1529 if (EFI_ERROR (Status
)) {
1534 // Insert the async SCSI cmd to the Async I/O list
1536 if (Event
!= NULL
) {
1537 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1538 TransReq
->CallerEvent
= Event
;
1539 InsertTailList (&Private
->Queue
, &TransReq
->TransferList
);
1540 gBS
->RestoreTPL (OldTpl
);
1544 // Start to execute the transfer request.
1546 UfsStartExecCmd (Private
, TransReq
->Slot
);
1549 // Immediately return for async I/O.
1551 if (Event
!= NULL
) {
1556 // Wait for the completion of the transfer request.
1558 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< TransReq
->Slot
, 0, Packet
->Timeout
);
1559 if (EFI_ERROR (Status
)) {
1564 // Get sense data if exists
1566 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
1567 ASSERT (Response
!= NULL
);
1568 SenseDataLen
= Response
->SenseDataLen
;
1569 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1571 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1573 // Make sure the hardware device does not return more data than expected.
1575 if (SenseDataLen
<= Packet
->SenseDataLength
) {
1576 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1577 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1579 Packet
->SenseDataLength
= 0;
1584 // Check the transfer request result.
1586 Packet
->TargetStatus
= Response
->Status
;
1587 if (Response
->Response
!= 0) {
1588 DEBUG ((DEBUG_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1589 Status
= EFI_DEVICE_ERROR
;
1593 if (TransReq
->Trd
->Ocs
== 0) {
1594 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1595 if ((Response
->Flags
& BIT5
) == BIT5
) {
1596 ResTranCount
= Response
->ResTranCount
;
1597 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1598 Packet
->InTransferLength
-= ResTranCount
;
1601 if ((Response
->Flags
& BIT5
) == BIT5
) {
1602 ResTranCount
= Response
->ResTranCount
;
1603 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1604 Packet
->OutTransferLength
-= ResTranCount
;
1608 Status
= EFI_DEVICE_ERROR
;
1612 UfsHc
->Flush (UfsHc
);
1614 UfsStopExecCmd (Private
, TransReq
->Slot
);
1616 UfsReconcileDataTransferBuffer (Private
, TransReq
);
1619 if (TransReq
->CmdDescMapping
!= NULL
) {
1620 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
1622 if (TransReq
->CmdDescHost
!= NULL
) {
1623 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
), TransReq
->CmdDescHost
);
1625 if (TransReq
!= NULL
) {
1626 FreePool (TransReq
);
1634 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1635 @param[in, out] UicCommand UIC command descriptor. On exit contains UIC command results.
1637 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1638 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1642 UfsExecUicCommands (
1643 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1644 IN OUT EDKII_UIC_COMMAND
*UicCommand
1650 Status
= UfsMmioRead32 (Private
, UFS_HC_IS_OFFSET
, &Data
);
1651 if (EFI_ERROR (Status
)) {
1655 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1657 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1659 Status
= UfsMmioWrite32 (Private
, UFS_HC_IS_OFFSET
, Data
);
1660 if (EFI_ERROR (Status
)) {
1666 // When programming UIC command registers, host software shall set the register UICCMD
1667 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1670 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG1_OFFSET
, UicCommand
->Arg1
);
1671 if (EFI_ERROR (Status
)) {
1675 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, UicCommand
->Arg2
);
1676 if (EFI_ERROR (Status
)) {
1680 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, UicCommand
->Arg3
);
1681 if (EFI_ERROR (Status
)) {
1686 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1688 Status
= UfsWaitMemSet (Private
, UFS_HC_STATUS_OFFSET
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1689 if (EFI_ERROR (Status
)) {
1693 Status
= UfsMmioWrite32 (Private
, UFS_HC_UIC_CMD_OFFSET
, UicCommand
->Opcode
);
1694 if (EFI_ERROR (Status
)) {
1699 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1700 // This bit is set to '1' by the host controller upon completion of a UIC command.
1702 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1703 if (EFI_ERROR (Status
)) {
1707 if (UicCommand
->Opcode
!= UfsUicDmeReset
) {
1708 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, &UicCommand
->Arg2
);
1709 if (EFI_ERROR (Status
)) {
1712 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, &UicCommand
->Arg3
);
1713 if (EFI_ERROR (Status
)) {
1716 if ((UicCommand
->Arg2
& 0xFF) != 0) {
1718 DumpUicCmdExecResult ((UINT8
)UicCommand
->Opcode
, (UINT8
)(UicCommand
->Arg2
& 0xFF));
1720 return EFI_DEVICE_ERROR
;
1728 Allocate common buffer for host and UFS bus master access simultaneously.
1730 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1731 @param[in] Size The length of buffer to be allocated.
1732 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1733 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1734 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1736 @retval EFI_SUCCESS The common buffer was allocated successfully.
1737 @retval EFI_DEVICE_ERROR The allocation fails.
1738 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1742 UfsAllocateAlignCommonBuffer (
1743 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1745 OUT VOID
**CmdDescHost
,
1746 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1747 OUT VOID
**CmdDescMapping
1752 BOOLEAN Is32BitAddr
;
1753 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1755 if ((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1756 Is32BitAddr
= FALSE
;
1761 UfsHc
= Private
->UfsHostController
;
1762 Status
= UfsHc
->AllocateBuffer (
1765 EfiBootServicesData
,
1766 EFI_SIZE_TO_PAGES (Size
),
1770 if (EFI_ERROR (Status
)) {
1771 *CmdDescMapping
= NULL
;
1772 *CmdDescHost
= NULL
;
1773 *CmdDescPhyAddr
= 0;
1774 return EFI_OUT_OF_RESOURCES
;
1777 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1778 Status
= UfsHc
->Map (
1780 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1787 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1790 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1793 *CmdDescHost
= NULL
;
1794 return EFI_OUT_OF_RESOURCES
;
1797 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1799 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1807 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1810 *CmdDescMapping
= NULL
;
1811 *CmdDescHost
= NULL
;
1812 return EFI_DEVICE_ERROR
;
1815 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1820 Enable the UFS host controller for accessing.
1822 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1824 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1825 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1829 UfsEnableHostController (
1830 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1836 if (mUfsHcPlatform
!= NULL
&& mUfsHcPlatform
->Callback
!= NULL
) {
1837 Status
= mUfsHcPlatform
->Callback (Private
->Handle
, EdkiiUfsHcPreHce
, &Private
->UfsHcDriverInterface
);
1838 if (EFI_ERROR (Status
)) {
1839 DEBUG ((DEBUG_ERROR
, "Failure from platform driver during EdkiiUfsHcPreHce, Status = %r\n", Status
));
1845 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1847 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1849 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
1850 if (EFI_ERROR (Status
)) {
1854 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1856 // Write a 0 to the HCE register at first to disable the host controller.
1858 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
1859 if (EFI_ERROR (Status
)) {
1863 // Wait until HCE is read as '0' before continuing.
1865 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1866 if (EFI_ERROR (Status
)) {
1867 return EFI_DEVICE_ERROR
;
1872 // Write a 1 to the HCE register to enable the UFS host controller.
1874 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
);
1875 if (EFI_ERROR (Status
)) {
1880 // Wait until HCE is read as '1' before continuing.
1882 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1883 if (EFI_ERROR (Status
)) {
1884 return EFI_DEVICE_ERROR
;
1887 if (mUfsHcPlatform
!= NULL
&& mUfsHcPlatform
->Callback
!= NULL
) {
1888 Status
= mUfsHcPlatform
->Callback (Private
->Handle
, EdkiiUfsHcPostHce
, &Private
->UfsHcDriverInterface
);
1889 if (EFI_ERROR (Status
)) {
1890 DEBUG ((DEBUG_ERROR
, "Failure from platform driver during EdkiiUfsHcPostHce, Status = %r\n", Status
));
1899 Detect if a UFS device attached.
1901 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1903 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1904 @retval EFI_NOT_FOUND Not found a UFS device attached.
1905 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1909 UfsDeviceDetection (
1910 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1916 EDKII_UIC_COMMAND LinkStartupCommand
;
1918 if (mUfsHcPlatform
!= NULL
&& mUfsHcPlatform
->Callback
!= NULL
) {
1919 Status
= mUfsHcPlatform
->Callback (Private
->Handle
, EdkiiUfsHcPreLinkStartup
, &Private
->UfsHcDriverInterface
);
1920 if (EFI_ERROR (Status
)) {
1921 DEBUG ((DEBUG_ERROR
, "Failure from platform driver during EdkiiUfsHcPreLinkStartup, Status = %r\n", Status
));
1927 // Start UFS device detection.
1928 // Try up to 3 times for establishing data link with device.
1930 for (Retry
= 0; Retry
< 3; Retry
++) {
1931 LinkStartupCommand
.Opcode
= UfsUicDmeLinkStartup
;
1932 LinkStartupCommand
.Arg1
= 0;
1933 LinkStartupCommand
.Arg2
= 0;
1934 LinkStartupCommand
.Arg3
= 0;
1935 Status
= UfsExecUicCommands (Private
, &LinkStartupCommand
);
1936 if (EFI_ERROR (Status
)) {
1937 return EFI_DEVICE_ERROR
;
1940 Status
= UfsMmioRead32 (Private
, UFS_HC_STATUS_OFFSET
, &Data
);
1941 if (EFI_ERROR (Status
)) {
1942 return EFI_DEVICE_ERROR
;
1945 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1946 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1947 if (EFI_ERROR (Status
)) {
1948 return EFI_DEVICE_ERROR
;
1951 if (mUfsHcPlatform
!= NULL
&& mUfsHcPlatform
->Callback
!= NULL
) {
1952 Status
= mUfsHcPlatform
->Callback (Private
->Handle
, EdkiiUfsHcPostLinkStartup
, &Private
->UfsHcDriverInterface
);
1953 if (EFI_ERROR (Status
)) {
1954 DEBUG ((DEBUG_ERROR
, "Failure from platform driver during EdkiiUfsHcPostLinkStartup, Status = %r\n", Status
));
1962 return EFI_NOT_FOUND
;
1966 Initialize UFS task management request list related h/w context.
1968 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1970 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1971 @retval EFI_DEVICE_ERROR The initialization fails.
1975 UfsInitTaskManagementRequestList (
1976 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1981 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1982 VOID
*CmdDescMapping
;
1986 // Initial h/w and s/w context for future operations.
1989 CmdDescMapping
= NULL
;
1993 // Allocate and initialize UTP Task Management Request List.
1995 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1996 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1997 if (EFI_ERROR (Status
)) {
2002 // Program the UTP Task Management Request List Base Address and UTP Task Management
2003 // Request List Base Address with a 64-bit address allocated at step 6.
2005 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
2006 if (EFI_ERROR (Status
)) {
2010 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
2011 if (EFI_ERROR (Status
)) {
2014 Private
->UtpTmrlBase
= CmdDescHost
;
2015 Private
->Nutmrs
= Nutmrs
;
2016 Private
->TmrlMapping
= CmdDescMapping
;
2019 // Enable the UTP Task Management Request List by setting the UTP Task Management
2020 // Request List RunStop Register (UTMRLRSR) to '1'.
2022 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
2023 if (EFI_ERROR (Status
)) {
2031 Initialize UFS transfer request list related h/w context.
2033 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2035 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
2036 @retval EFI_DEVICE_ERROR The initialization fails.
2040 UfsInitTransferRequestList (
2041 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2046 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
2047 VOID
*CmdDescMapping
;
2051 // Initial h/w and s/w context for future operations.
2054 CmdDescMapping
= NULL
;
2058 // Allocate and initialize UTP Transfer Request List.
2060 Nutrs
= (UINT8
)((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
2061 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
2062 if (EFI_ERROR (Status
)) {
2067 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
2068 // Base Address with a 64-bit address allocated at step 8.
2070 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
2071 if (EFI_ERROR (Status
)) {
2075 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
2076 if (EFI_ERROR (Status
)) {
2080 Private
->UtpTrlBase
= CmdDescHost
;
2081 Private
->Nutrs
= Nutrs
;
2082 Private
->TrlMapping
= CmdDescMapping
;
2085 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2086 // RunStop Register (UTRLRSR) to '1'.
2088 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
2089 if (EFI_ERROR (Status
)) {
2097 Initialize the UFS host controller.
2099 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2101 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2102 @retval Others A device error occurred while initializing the controller.
2107 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2112 Status
= UfsEnableHostController (Private
);
2113 if (EFI_ERROR (Status
)) {
2114 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2118 Status
= UfsDeviceDetection (Private
);
2119 if (EFI_ERROR (Status
)) {
2120 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2124 Status
= UfsInitTaskManagementRequestList (Private
);
2125 if (EFI_ERROR (Status
)) {
2126 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2130 Status
= UfsInitTransferRequestList (Private
);
2131 if (EFI_ERROR (Status
)) {
2132 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2136 DEBUG ((DEBUG_INFO
, "UfsControllerInit Finished\n"));
2141 Stop the UFS host controller.
2143 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2145 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2146 @retval Others A device error occurred while stopping the controller.
2151 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2158 // Enable the UTP Task Management Request List by setting the UTP Task Management
2159 // Request List RunStop Register (UTMRLRSR) to '1'.
2161 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2162 if (EFI_ERROR (Status
)) {
2167 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2168 // RunStop Register (UTRLRSR) to '1'.
2170 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2171 if (EFI_ERROR (Status
)) {
2176 // Write a 0 to the HCE register in order to disable the host controller.
2178 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2179 if (EFI_ERROR (Status
)) {
2182 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2184 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2185 if (EFI_ERROR (Status
)) {
2190 // Wait until HCE is read as '0' before continuing.
2192 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2193 if (EFI_ERROR (Status
)) {
2194 return EFI_DEVICE_ERROR
;
2197 DEBUG ((DEBUG_INFO
, "UfsController is stopped\n"));
2203 Internal helper function which will signal the caller event and clean up
2206 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2208 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2215 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
2216 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
2219 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
2220 EFI_EVENT CallerEvent
;
2222 ASSERT ((Private
!= NULL
) && (TransReq
!= NULL
));
2224 UfsHc
= Private
->UfsHostController
;
2225 CallerEvent
= TransReq
->CallerEvent
;
2227 RemoveEntryList (&TransReq
->TransferList
);
2229 UfsHc
->Flush (UfsHc
);
2231 UfsStopExecCmd (Private
, TransReq
->Slot
);
2233 UfsReconcileDataTransferBuffer (Private
, TransReq
);
2235 if (TransReq
->CmdDescMapping
!= NULL
) {
2236 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
2238 if (TransReq
->CmdDescHost
!= NULL
) {
2241 EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
),
2242 TransReq
->CmdDescHost
2246 FreePool (TransReq
);
2248 gBS
->SignalEvent (CallerEvent
);
2253 Call back function when the timer event is signaled.
2255 @param[in] Event The Event this notify function registered to.
2256 @param[in] Context Pointer to the context data registered to the Event.
2261 ProcessAsyncTaskList (
2266 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2268 LIST_ENTRY
*NextEntry
;
2269 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
2270 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
;
2271 UTP_RESPONSE_UPIU
*Response
;
2272 UINT16 SenseDataLen
;
2273 UINT32 ResTranCount
;
2278 Private
= (UFS_PASS_THRU_PRIVATE_DATA
*) Context
;
2282 // Check the entries in the async I/O queue are done or not.
2284 if (!IsListEmpty(&Private
->Queue
)) {
2285 EFI_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
2286 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
2287 Packet
= TransReq
->Packet
;
2289 if ((SlotsMap
& (BIT0
<< TransReq
->Slot
)) != 0) {
2292 SlotsMap
|= BIT0
<< TransReq
->Slot
;
2294 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Value
);
2295 if (EFI_ERROR (Status
)) {
2297 // TODO: Should find/add a proper host adapter return status for this
2300 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
2301 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq
->CallerEvent
));
2302 SignalCallerEvent (Private
, TransReq
);
2306 if ((Value
& (BIT0
<< TransReq
->Slot
)) != 0) {
2308 // Scsi cmd not finished yet.
2310 if (TransReq
->TimeoutRemain
> UFS_HC_ASYNC_TIMER
) {
2311 TransReq
->TimeoutRemain
-= UFS_HC_ASYNC_TIMER
;
2317 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
2318 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq
->CallerEvent
));
2319 SignalCallerEvent (Private
, TransReq
);
2324 // Scsi cmd finished.
2326 // Get sense data if exists
2328 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
2329 ASSERT (Response
!= NULL
);
2330 SenseDataLen
= Response
->SenseDataLen
;
2331 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
2333 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
2335 // Make sure the hardware device does not return more data than expected.
2337 if (SenseDataLen
<= Packet
->SenseDataLength
) {
2338 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
2339 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
2341 Packet
->SenseDataLength
= 0;
2346 // Check the transfer request result.
2348 Packet
->TargetStatus
= Response
->Status
;
2349 if (Response
->Response
!= 0) {
2350 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq
->CallerEvent
));
2351 SignalCallerEvent (Private
, TransReq
);
2355 if (TransReq
->Trd
->Ocs
== 0) {
2356 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2357 if ((Response
->Flags
& BIT5
) == BIT5
) {
2358 ResTranCount
= Response
->ResTranCount
;
2359 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2360 Packet
->InTransferLength
-= ResTranCount
;
2363 if ((Response
->Flags
& BIT5
) == BIT5
) {
2364 ResTranCount
= Response
->ResTranCount
;
2365 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2366 Packet
->OutTransferLength
-= ResTranCount
;
2370 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq
->CallerEvent
));
2371 SignalCallerEvent (Private
, TransReq
);
2375 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq
->CallerEvent
));
2376 SignalCallerEvent (Private
, TransReq
);
2383 Execute UIC command.
2385 @param[in] This Pointer to driver interface produced by the UFS controller.
2386 @param[in, out] UicCommand Descriptor of the command that will be executed.
2388 @retval EFI_SUCCESS Command executed successfully.
2389 @retval EFI_INVALID_PARAMETER This or UicCommand is NULL.
2390 @retval Others Command failed to execute.
2394 UfsHcDriverInterfaceExecUicCommand (
2395 IN EDKII_UFS_HC_DRIVER_INTERFACE
*This
,
2396 IN OUT EDKII_UIC_COMMAND
*UicCommand
2399 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2401 if (This
== NULL
|| UicCommand
== NULL
) {
2402 return EFI_INVALID_PARAMETER
;
2405 Private
= UFS_PASS_THRU_PRIVATE_DATA_FROM_DRIVER_INTF (This
);
2407 return UfsExecUicCommands (Private
, UicCommand
);
2411 Initializes UfsHcInfo field in private data.
2413 @param[in] Private Pointer to host controller private data.
2415 @retval EFI_SUCCESS UfsHcInfo initialized successfully.
2416 @retval Others Failed to initalize UfsHcInfo.
2420 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2426 Status
= UfsMmioRead32 (Private
, UFS_HC_VER_OFFSET
, &Data
);
2427 if (EFI_ERROR (Status
)) {
2431 Private
->UfsHcInfo
.Version
= Data
;
2433 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
2434 if (EFI_ERROR (Status
)) {
2438 Private
->UfsHcInfo
.Capabilities
= Data
;
2440 if (mUfsHcPlatform
!= NULL
&& mUfsHcPlatform
->OverrideHcInfo
!= NULL
) {
2441 Status
= mUfsHcPlatform
->OverrideHcInfo (Private
->Handle
, &Private
->UfsHcInfo
);
2442 if (EFI_ERROR (Status
)) {
2443 DEBUG ((DEBUG_ERROR
, "Failure from platform on OverrideHcInfo, Status = %r\n", Status
));