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
);
1208 Read specified flag from a UFS device.
1210 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1211 @param[in] FlagId The ID of flag to be read.
1212 @param[out] Value The flag's value.
1214 @retval EFI_SUCCESS The flag was read successfully.
1215 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1216 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1221 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1228 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1234 Sends NOP IN cmd to a UFS device for initialization process request.
1235 For more details, please refer to UFS 2.0 spec Figure 13.3.
1237 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1239 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1240 received successfully.
1241 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1242 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1243 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1248 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1254 UTP_NOP_IN_UPIU
*NopInUpiu
;
1257 VOID
*CmdDescMapping
;
1258 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1261 // Find out which slot of transfer request list is available.
1263 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1264 if (EFI_ERROR (Status
)) {
1268 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1269 Status
= UfsCreateNopCommandDesc (Private
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1270 if (EFI_ERROR (Status
)) {
1275 // Check the transfer request result.
1277 UfsHc
= Private
->UfsHostController
;
1278 NopInUpiu
= (UTP_NOP_IN_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1279 ASSERT (NopInUpiu
!= NULL
);
1280 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1283 // Start to execute the transfer request.
1285 UfsStartExecCmd (Private
, Slot
);
1288 // Wait for the completion of the transfer request.
1290 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1291 if (EFI_ERROR (Status
)) {
1295 if (NopInUpiu
->Resp
!= 0) {
1296 Status
= EFI_DEVICE_ERROR
;
1298 Status
= EFI_SUCCESS
;
1302 UfsHc
->Flush (UfsHc
);
1304 UfsStopExecCmd (Private
, Slot
);
1306 if (CmdDescMapping
!= NULL
) {
1307 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1309 if (CmdDescHost
!= NULL
) {
1310 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1317 Cleanup data buffers after data transfer. This function
1318 also takes care to copy all data to user memory pool for
1319 unaligned data transfers.
1321 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA
1322 @param[in] TransReq Pointer to the transfer request
1325 UfsReconcileDataTransferBuffer (
1326 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1327 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
1330 if (TransReq
->DataBufMapping
!= NULL
) {
1331 Private
->UfsHostController
->Unmap (
1332 Private
->UfsHostController
,
1333 TransReq
->DataBufMapping
1338 // Check if unaligned transfer was performed. If it was and we read
1339 // data from device copy memory to user data buffers before cleanup.
1340 // The assumption is if auxiliary aligned data buffer is not NULL then
1341 // unaligned transfer has been performed.
1343 if (TransReq
->AlignedDataBuf
!= NULL
) {
1344 if (TransReq
->Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1345 CopyMem (TransReq
->Packet
->InDataBuffer
, TransReq
->AlignedDataBuf
, TransReq
->Packet
->InTransferLength
);
1348 // Wipe out the transfer buffer in case it contains sensitive data.
1350 ZeroMem (TransReq
->AlignedDataBuf
, TransReq
->AlignedDataBufSize
);
1351 FreeAlignedPages (TransReq
->AlignedDataBuf
, EFI_SIZE_TO_PAGES (TransReq
->AlignedDataBufSize
));
1352 TransReq
->AlignedDataBuf
= NULL
;
1357 Prepare data buffer for transfer.
1359 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA
1360 @param[in, out] TransReq Pointer to the transfer request
1362 @retval EFI_DEVICE_ERROR Failed to prepare buffer for transfer
1363 @retval EFI_SUCCESS Buffer ready for transfer
1366 UfsPrepareDataTransferBuffer (
1367 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1368 IN OUT UFS_PASS_THRU_TRANS_REQ
*TransReq
1375 EFI_PHYSICAL_ADDRESS DataBufPhyAddr
;
1376 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag
;
1377 UTP_TR_PRD
*PrdtBase
;
1383 // For unaligned data transfers we allocate auxiliary DWORD aligned memory pool.
1384 // When command is finished auxiliary memory pool is copied into actual user memory.
1385 // This is requiered to assure data transfer safety(DWORD alignment required by UFS spec.)
1387 if (TransReq
->Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1388 if (((UINTN
)TransReq
->Packet
->InDataBuffer
% 4 != 0) || (TransReq
->Packet
->InTransferLength
% 4 != 0)) {
1389 DataLen
= TransReq
->Packet
->InTransferLength
+ (4 - (TransReq
->Packet
->InTransferLength
% 4));
1390 DataBuf
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen
), 4);
1391 if (DataBuf
== NULL
) {
1392 return EFI_DEVICE_ERROR
;
1394 ZeroMem (DataBuf
, DataLen
);
1395 TransReq
->AlignedDataBuf
= DataBuf
;
1396 TransReq
->AlignedDataBufSize
= DataLen
;
1398 DataLen
= TransReq
->Packet
->InTransferLength
;
1399 DataBuf
= TransReq
->Packet
->InDataBuffer
;
1401 Flag
= EdkiiUfsHcOperationBusMasterWrite
;
1403 if (((UINTN
)TransReq
->Packet
->OutDataBuffer
% 4 != 0) || (TransReq
->Packet
->OutTransferLength
% 4 != 0)) {
1404 DataLen
= TransReq
->Packet
->OutTransferLength
+ (4 - (TransReq
->Packet
->OutTransferLength
% 4));
1405 DataBuf
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen
), 4);
1406 if (DataBuf
== NULL
) {
1407 return EFI_DEVICE_ERROR
;
1409 CopyMem (DataBuf
, TransReq
->Packet
->OutDataBuffer
, TransReq
->Packet
->OutTransferLength
);
1410 TransReq
->AlignedDataBuf
= DataBuf
;
1411 TransReq
->AlignedDataBufSize
= DataLen
;
1413 DataLen
= TransReq
->Packet
->OutTransferLength
;
1414 DataBuf
= TransReq
->Packet
->OutDataBuffer
;
1416 Flag
= EdkiiUfsHcOperationBusMasterRead
;
1420 MapLength
= DataLen
;
1421 Status
= Private
->UfsHostController
->Map (
1422 Private
->UfsHostController
,
1427 &TransReq
->DataBufMapping
1430 if (EFI_ERROR (Status
) || (DataLen
!= MapLength
)) {
1431 if (TransReq
->AlignedDataBuf
!= NULL
) {
1433 // Wipe out the transfer buffer in case it contains sensitive data.
1435 ZeroMem (TransReq
->AlignedDataBuf
, TransReq
->AlignedDataBufSize
);
1436 FreeAlignedPages (TransReq
->AlignedDataBuf
, EFI_SIZE_TO_PAGES (TransReq
->AlignedDataBufSize
));
1437 TransReq
->AlignedDataBuf
= NULL
;
1439 return EFI_DEVICE_ERROR
;
1444 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1446 PrdtBase
= (UTP_TR_PRD
*)((UINT8
*)TransReq
->CmdDescHost
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
1447 ASSERT (PrdtBase
!= NULL
);
1448 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)DataBufPhyAddr
, DataLen
);
1454 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1456 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1457 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1458 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1460 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1461 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1462 Event is not NULL and non blocking I/O is supported, then
1463 nonblocking I/O is performed, and Event will be signaled when the
1464 SCSI Request Packet completes.
1466 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1467 commands, InTransferLength bytes were transferred from
1468 InDataBuffer. For write and bi-directional commands,
1469 OutTransferLength bytes were transferred by
1471 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1473 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1474 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1479 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1481 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
1482 IN EFI_EVENT Event OPTIONAL
1486 UTP_RESPONSE_UPIU
*Response
;
1487 UINT16 SenseDataLen
;
1488 UINT32 ResTranCount
;
1490 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
1491 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1493 TransReq
= AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ
));
1494 if (TransReq
== NULL
) {
1495 return EFI_OUT_OF_RESOURCES
;
1498 TransReq
->Signature
= UFS_PASS_THRU_TRANS_REQ_SIG
;
1499 TransReq
->TimeoutRemain
= Packet
->Timeout
;
1500 TransReq
->Packet
= Packet
;
1502 UfsHc
= Private
->UfsHostController
;
1504 // Find out which slot of transfer request list is available.
1506 Status
= UfsFindAvailableSlotInTrl (Private
, &TransReq
->Slot
);
1507 if (EFI_ERROR (Status
)) {
1511 TransReq
->Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + TransReq
->Slot
;
1514 // Fill transfer request descriptor to this slot.
1516 Status
= UfsCreateScsiCommandDesc (
1521 &TransReq
->CmdDescHost
,
1522 &TransReq
->CmdDescMapping
1524 if (EFI_ERROR (Status
)) {
1528 TransReq
->CmdDescSize
= TransReq
->Trd
->PrdtO
* sizeof (UINT32
) + TransReq
->Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1530 Status
= UfsPrepareDataTransferBuffer (Private
, TransReq
);
1531 if (EFI_ERROR (Status
)) {
1536 // Insert the async SCSI cmd to the Async I/O list
1538 if (Event
!= NULL
) {
1539 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1540 TransReq
->CallerEvent
= Event
;
1541 InsertTailList (&Private
->Queue
, &TransReq
->TransferList
);
1542 gBS
->RestoreTPL (OldTpl
);
1546 // Start to execute the transfer request.
1548 UfsStartExecCmd (Private
, TransReq
->Slot
);
1551 // Immediately return for async I/O.
1553 if (Event
!= NULL
) {
1558 // Wait for the completion of the transfer request.
1560 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< TransReq
->Slot
, 0, Packet
->Timeout
);
1561 if (EFI_ERROR (Status
)) {
1566 // Get sense data if exists
1568 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
1569 ASSERT (Response
!= NULL
);
1570 SenseDataLen
= Response
->SenseDataLen
;
1571 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1573 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1575 // Make sure the hardware device does not return more data than expected.
1577 if (SenseDataLen
<= Packet
->SenseDataLength
) {
1578 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1579 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1581 Packet
->SenseDataLength
= 0;
1586 // Check the transfer request result.
1588 Packet
->TargetStatus
= Response
->Status
;
1589 if (Response
->Response
!= 0) {
1590 DEBUG ((DEBUG_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1591 Status
= EFI_DEVICE_ERROR
;
1595 if (TransReq
->Trd
->Ocs
== 0) {
1596 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1597 if ((Response
->Flags
& BIT5
) == BIT5
) {
1598 ResTranCount
= Response
->ResTranCount
;
1599 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1600 Packet
->InTransferLength
-= ResTranCount
;
1603 if ((Response
->Flags
& BIT5
) == BIT5
) {
1604 ResTranCount
= Response
->ResTranCount
;
1605 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1606 Packet
->OutTransferLength
-= ResTranCount
;
1610 Status
= EFI_DEVICE_ERROR
;
1614 UfsHc
->Flush (UfsHc
);
1616 UfsStopExecCmd (Private
, TransReq
->Slot
);
1618 UfsReconcileDataTransferBuffer (Private
, TransReq
);
1621 if (TransReq
->CmdDescMapping
!= NULL
) {
1622 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
1624 if (TransReq
->CmdDescHost
!= NULL
) {
1625 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
), TransReq
->CmdDescHost
);
1627 if (TransReq
!= NULL
) {
1628 FreePool (TransReq
);
1636 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1637 @param[in, out] UicCommand UIC command descriptor. On exit contains UIC command results.
1639 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1640 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1644 UfsExecUicCommands (
1645 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1646 IN OUT EDKII_UIC_COMMAND
*UicCommand
1652 Status
= UfsMmioRead32 (Private
, UFS_HC_IS_OFFSET
, &Data
);
1653 if (EFI_ERROR (Status
)) {
1657 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1659 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1661 Status
= UfsMmioWrite32 (Private
, UFS_HC_IS_OFFSET
, Data
);
1662 if (EFI_ERROR (Status
)) {
1668 // When programming UIC command registers, host software shall set the register UICCMD
1669 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1672 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG1_OFFSET
, UicCommand
->Arg1
);
1673 if (EFI_ERROR (Status
)) {
1677 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, UicCommand
->Arg2
);
1678 if (EFI_ERROR (Status
)) {
1682 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, UicCommand
->Arg3
);
1683 if (EFI_ERROR (Status
)) {
1688 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1690 Status
= UfsWaitMemSet (Private
, UFS_HC_STATUS_OFFSET
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1691 if (EFI_ERROR (Status
)) {
1695 Status
= UfsMmioWrite32 (Private
, UFS_HC_UIC_CMD_OFFSET
, UicCommand
->Opcode
);
1696 if (EFI_ERROR (Status
)) {
1701 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1702 // This bit is set to '1' by the host controller upon completion of a UIC command.
1704 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1705 if (EFI_ERROR (Status
)) {
1709 if (UicCommand
->Opcode
!= UfsUicDmeReset
) {
1710 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, &UicCommand
->Arg2
);
1711 if (EFI_ERROR (Status
)) {
1714 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, &UicCommand
->Arg3
);
1715 if (EFI_ERROR (Status
)) {
1718 if ((UicCommand
->Arg2
& 0xFF) != 0) {
1720 DumpUicCmdExecResult ((UINT8
)UicCommand
->Opcode
, (UINT8
)(UicCommand
->Arg2
& 0xFF));
1722 return EFI_DEVICE_ERROR
;
1730 Allocate common buffer for host and UFS bus master access simultaneously.
1732 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1733 @param[in] Size The length of buffer to be allocated.
1734 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1735 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1736 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1738 @retval EFI_SUCCESS The common buffer was allocated successfully.
1739 @retval EFI_DEVICE_ERROR The allocation fails.
1740 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1744 UfsAllocateAlignCommonBuffer (
1745 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1747 OUT VOID
**CmdDescHost
,
1748 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1749 OUT VOID
**CmdDescMapping
1754 BOOLEAN Is32BitAddr
;
1755 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1757 if ((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1758 Is32BitAddr
= FALSE
;
1763 UfsHc
= Private
->UfsHostController
;
1764 Status
= UfsHc
->AllocateBuffer (
1767 EfiBootServicesData
,
1768 EFI_SIZE_TO_PAGES (Size
),
1772 if (EFI_ERROR (Status
)) {
1773 *CmdDescMapping
= NULL
;
1774 *CmdDescHost
= NULL
;
1775 *CmdDescPhyAddr
= 0;
1776 return EFI_OUT_OF_RESOURCES
;
1779 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1780 Status
= UfsHc
->Map (
1782 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1789 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1792 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1795 *CmdDescHost
= NULL
;
1796 return EFI_OUT_OF_RESOURCES
;
1799 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1801 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1809 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1812 *CmdDescMapping
= NULL
;
1813 *CmdDescHost
= NULL
;
1814 return EFI_DEVICE_ERROR
;
1817 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1822 Enable the UFS host controller for accessing.
1824 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1826 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1827 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1831 UfsEnableHostController (
1832 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1839 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1841 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1843 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
1844 if (EFI_ERROR (Status
)) {
1848 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1850 // Write a 0 to the HCE register at first to disable the host controller.
1852 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
1853 if (EFI_ERROR (Status
)) {
1857 // Wait until HCE is read as '0' before continuing.
1859 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1860 if (EFI_ERROR (Status
)) {
1861 return EFI_DEVICE_ERROR
;
1866 // Write a 1 to the HCE register to enable the UFS host controller.
1868 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
);
1869 if (EFI_ERROR (Status
)) {
1874 // Wait until HCE is read as '1' before continuing.
1876 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1877 if (EFI_ERROR (Status
)) {
1878 return EFI_DEVICE_ERROR
;
1885 Detect if a UFS device attached.
1887 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1889 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1890 @retval EFI_NOT_FOUND Not found a UFS device attached.
1891 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1895 UfsDeviceDetection (
1896 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1902 EDKII_UIC_COMMAND LinkStartupCommand
;
1905 // Start UFS device detection.
1906 // Try up to 3 times for establishing data link with device.
1908 for (Retry
= 0; Retry
< 3; Retry
++) {
1909 LinkStartupCommand
.Opcode
= UfsUicDmeLinkStartup
;
1910 LinkStartupCommand
.Arg1
= 0;
1911 LinkStartupCommand
.Arg2
= 0;
1912 LinkStartupCommand
.Arg3
= 0;
1913 Status
= UfsExecUicCommands (Private
, &LinkStartupCommand
);
1914 if (EFI_ERROR (Status
)) {
1915 return EFI_DEVICE_ERROR
;
1918 Status
= UfsMmioRead32 (Private
, UFS_HC_STATUS_OFFSET
, &Data
);
1919 if (EFI_ERROR (Status
)) {
1920 return EFI_DEVICE_ERROR
;
1923 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1924 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1925 if (EFI_ERROR (Status
)) {
1926 return EFI_DEVICE_ERROR
;
1933 return EFI_NOT_FOUND
;
1937 Initialize UFS task management request list related h/w context.
1939 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1941 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1942 @retval EFI_DEVICE_ERROR The initialization fails.
1946 UfsInitTaskManagementRequestList (
1947 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1952 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1953 VOID
*CmdDescMapping
;
1957 // Initial h/w and s/w context for future operations.
1960 CmdDescMapping
= NULL
;
1964 // Allocate and initialize UTP Task Management Request List.
1966 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1967 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1968 if (EFI_ERROR (Status
)) {
1973 // Program the UTP Task Management Request List Base Address and UTP Task Management
1974 // Request List Base Address with a 64-bit address allocated at step 6.
1976 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1977 if (EFI_ERROR (Status
)) {
1981 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1982 if (EFI_ERROR (Status
)) {
1985 Private
->UtpTmrlBase
= CmdDescHost
;
1986 Private
->Nutmrs
= Nutmrs
;
1987 Private
->TmrlMapping
= CmdDescMapping
;
1990 // Enable the UTP Task Management Request List by setting the UTP Task Management
1991 // Request List RunStop Register (UTMRLRSR) to '1'.
1993 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
1994 if (EFI_ERROR (Status
)) {
2002 Initialize UFS transfer request list related h/w context.
2004 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2006 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
2007 @retval EFI_DEVICE_ERROR The initialization fails.
2011 UfsInitTransferRequestList (
2012 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2017 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
2018 VOID
*CmdDescMapping
;
2022 // Initial h/w and s/w context for future operations.
2025 CmdDescMapping
= NULL
;
2029 // Allocate and initialize UTP Transfer Request List.
2031 Nutrs
= (UINT8
)((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
2032 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
2033 if (EFI_ERROR (Status
)) {
2038 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
2039 // Base Address with a 64-bit address allocated at step 8.
2041 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
2042 if (EFI_ERROR (Status
)) {
2046 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
2047 if (EFI_ERROR (Status
)) {
2051 Private
->UtpTrlBase
= CmdDescHost
;
2052 Private
->Nutrs
= Nutrs
;
2053 Private
->TrlMapping
= CmdDescMapping
;
2056 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2057 // RunStop Register (UTRLRSR) to '1'.
2059 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
2060 if (EFI_ERROR (Status
)) {
2068 Initialize the UFS host controller.
2070 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2072 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2073 @retval Others A device error occurred while initializing the controller.
2078 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2083 Status
= UfsEnableHostController (Private
);
2084 if (EFI_ERROR (Status
)) {
2085 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2089 Status
= UfsDeviceDetection (Private
);
2090 if (EFI_ERROR (Status
)) {
2091 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2095 Status
= UfsInitTaskManagementRequestList (Private
);
2096 if (EFI_ERROR (Status
)) {
2097 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2101 Status
= UfsInitTransferRequestList (Private
);
2102 if (EFI_ERROR (Status
)) {
2103 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2107 DEBUG ((DEBUG_INFO
, "UfsControllerInit Finished\n"));
2112 Stop the UFS host controller.
2114 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2116 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2117 @retval Others A device error occurred while stopping the controller.
2122 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2129 // Enable the UTP Task Management Request List by setting the UTP Task Management
2130 // Request List RunStop Register (UTMRLRSR) to '1'.
2132 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2133 if (EFI_ERROR (Status
)) {
2138 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2139 // RunStop Register (UTRLRSR) to '1'.
2141 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2142 if (EFI_ERROR (Status
)) {
2147 // Write a 0 to the HCE register in order to disable the host controller.
2149 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2150 if (EFI_ERROR (Status
)) {
2153 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2155 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2156 if (EFI_ERROR (Status
)) {
2161 // Wait until HCE is read as '0' before continuing.
2163 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2164 if (EFI_ERROR (Status
)) {
2165 return EFI_DEVICE_ERROR
;
2168 DEBUG ((DEBUG_INFO
, "UfsController is stopped\n"));
2174 Internal helper function which will signal the caller event and clean up
2177 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2179 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2186 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
2187 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
2190 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
2191 EFI_EVENT CallerEvent
;
2193 ASSERT ((Private
!= NULL
) && (TransReq
!= NULL
));
2195 UfsHc
= Private
->UfsHostController
;
2196 CallerEvent
= TransReq
->CallerEvent
;
2198 RemoveEntryList (&TransReq
->TransferList
);
2200 UfsHc
->Flush (UfsHc
);
2202 UfsStopExecCmd (Private
, TransReq
->Slot
);
2204 UfsReconcileDataTransferBuffer (Private
, TransReq
);
2206 if (TransReq
->CmdDescMapping
!= NULL
) {
2207 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
2209 if (TransReq
->CmdDescHost
!= NULL
) {
2212 EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
),
2213 TransReq
->CmdDescHost
2217 FreePool (TransReq
);
2219 gBS
->SignalEvent (CallerEvent
);
2224 Call back function when the timer event is signaled.
2226 @param[in] Event The Event this notify function registered to.
2227 @param[in] Context Pointer to the context data registered to the Event.
2232 ProcessAsyncTaskList (
2237 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2239 LIST_ENTRY
*NextEntry
;
2240 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
2241 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
;
2242 UTP_RESPONSE_UPIU
*Response
;
2243 UINT16 SenseDataLen
;
2244 UINT32 ResTranCount
;
2249 Private
= (UFS_PASS_THRU_PRIVATE_DATA
*) Context
;
2253 // Check the entries in the async I/O queue are done or not.
2255 if (!IsListEmpty(&Private
->Queue
)) {
2256 EFI_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
2257 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
2258 Packet
= TransReq
->Packet
;
2260 if ((SlotsMap
& (BIT0
<< TransReq
->Slot
)) != 0) {
2263 SlotsMap
|= BIT0
<< TransReq
->Slot
;
2265 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Value
);
2266 if (EFI_ERROR (Status
)) {
2268 // TODO: Should find/add a proper host adapter return status for this
2271 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
2272 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq
->CallerEvent
));
2273 SignalCallerEvent (Private
, TransReq
);
2277 if ((Value
& (BIT0
<< TransReq
->Slot
)) != 0) {
2279 // Scsi cmd not finished yet.
2281 if (TransReq
->TimeoutRemain
> UFS_HC_ASYNC_TIMER
) {
2282 TransReq
->TimeoutRemain
-= UFS_HC_ASYNC_TIMER
;
2288 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
2289 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq
->CallerEvent
));
2290 SignalCallerEvent (Private
, TransReq
);
2295 // Scsi cmd finished.
2297 // Get sense data if exists
2299 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
2300 ASSERT (Response
!= NULL
);
2301 SenseDataLen
= Response
->SenseDataLen
;
2302 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
2304 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
2306 // Make sure the hardware device does not return more data than expected.
2308 if (SenseDataLen
<= Packet
->SenseDataLength
) {
2309 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
2310 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
2312 Packet
->SenseDataLength
= 0;
2317 // Check the transfer request result.
2319 Packet
->TargetStatus
= Response
->Status
;
2320 if (Response
->Response
!= 0) {
2321 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq
->CallerEvent
));
2322 SignalCallerEvent (Private
, TransReq
);
2326 if (TransReq
->Trd
->Ocs
== 0) {
2327 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2328 if ((Response
->Flags
& BIT5
) == BIT5
) {
2329 ResTranCount
= Response
->ResTranCount
;
2330 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2331 Packet
->InTransferLength
-= ResTranCount
;
2334 if ((Response
->Flags
& BIT5
) == BIT5
) {
2335 ResTranCount
= Response
->ResTranCount
;
2336 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2337 Packet
->OutTransferLength
-= ResTranCount
;
2341 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq
->CallerEvent
));
2342 SignalCallerEvent (Private
, TransReq
);
2346 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq
->CallerEvent
));
2347 SignalCallerEvent (Private
, TransReq
);
2354 Initializes UfsHcInfo field in private data.
2356 @param[in] Private Pointer to host controller private data.
2358 @retval EFI_SUCCESS UfsHcInfo initialized successfully.
2359 @retval Others Failed to initalize UfsHcInfo.
2363 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2369 Status
= UfsMmioRead32 (Private
, UFS_HC_VER_OFFSET
, &Data
);
2370 if (EFI_ERROR (Status
)) {
2374 Private
->UfsHcInfo
.Version
= Data
;
2376 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
2377 if (EFI_ERROR (Status
)) {
2381 Private
->UfsHcInfo
.Capabilities
= Data
;