2 UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface
3 for upper layer application to execute UFS-supported SCSI cmds.
5 Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
6 Copyright (c) Microsoft Corporation.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "UfsPassThru.h"
14 Read 32bits data from specified UFS MMIO register.
16 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
17 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
19 @param[out] Value The data buffer to store.
21 @retval EFI_TIMEOUT The operation is time out.
22 @retval EFI_SUCCESS The operation succeeds.
23 @retval Others The operation fails.
28 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
33 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
36 UfsHc
= Private
->UfsHostController
;
38 Status
= UfsHc
->Read (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, Value
);
44 Write 32bits data to specified UFS MMIO register.
46 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
47 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
49 @param[in] Value The data to write.
51 @retval EFI_TIMEOUT The operation is time out.
52 @retval EFI_SUCCESS The operation succeeds.
53 @retval Others The operation fails.
58 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
63 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
66 UfsHc
= Private
->UfsHostController
;
68 Status
= UfsHc
->Write (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, &Value
);
74 Wait for the value of the specified system memory set to the test value.
76 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
77 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
79 @param[in] MaskValue The mask value of memory.
80 @param[in] TestValue The test value of memory.
81 @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.
83 @retval EFI_TIMEOUT The system memory setting is time out.
84 @retval EFI_SUCCESS The system memory is correct set.
85 @retval Others The operation fails.
90 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
105 InfiniteWait
= FALSE
;
108 Delay
= DivU64x32 (Timeout
, 10) + 1;
112 // Access PCI MMIO space to see if the value is the tested one.
114 Status
= UfsMmioRead32 (Private
, Offset
, &Value
);
115 if (EFI_ERROR (Status
)) {
121 if (Value
== TestValue
) {
126 // Stall for 1 microseconds.
128 MicroSecondDelay (1);
132 } while (InfiniteWait
|| (Delay
> 0));
138 Dump UIC command execution result for debugging.
140 @param[in] UicOpcode The executed UIC opcode.
141 @param[in] Result The result to be parsed.
145 DumpUicCmdExecResult (
150 if (UicOpcode
<= UfsUicDmePeerSet
) {
155 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
158 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
161 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
164 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
167 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BAD_INDEX\n"));
170 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
173 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
176 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
179 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BUSY\n"));
182 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - DME_FAILURE\n"));
193 DEBUG ((DEBUG_VERBOSE
, "UIC control command fails - FAILURE\n"));
203 Dump QUERY RESPONSE UPIU result for debugging.
205 @param[in] Result The result to be parsed.
209 DumpQueryResponseResult (
215 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Not Readable\n"));
218 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Not Writeable\n"));
221 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Already Written\n"));
224 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Length\n"));
227 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Value\n"));
230 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Selector\n"));
233 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Index\n"));
236 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Idn\n"));
239 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Opcode\n"));
242 DEBUG ((DEBUG_VERBOSE
, "Query Response with General Failure\n"));
251 Swap little endian to big endian.
253 @param[in, out] Buffer The data buffer. In input, it contains little endian data.
254 In output, it will become big endian.
255 @param[in] BufferSize The length of converted data.
259 SwapLittleEndianToBigEndian (
260 IN OUT UINT8
*Buffer
,
268 SwapCount
= BufferSize
/ 2;
269 for (Index
= 0; Index
< SwapCount
; Index
++) {
270 Temp
= Buffer
[Index
];
271 Buffer
[Index
] = Buffer
[BufferSize
- 1 - Index
];
272 Buffer
[BufferSize
- 1 - Index
] = Temp
;
277 Fill TSF field of QUERY REQUEST UPIU.
279 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
280 @param[in] Opcode The opcode of request.
281 @param[in] DescId The descriptor ID of request.
282 @param[in] Index The index of request.
283 @param[in] Selector The selector of request.
284 @param[in] Length The length of transferred data. The maximum is 4.
285 @param[in] Value The value of transferred data.
289 UfsFillTsfOfQueryReqUpiu (
290 IN OUT UTP_UPIU_TSF
*TsfBase
,
292 IN UINT8 DescId OPTIONAL
,
293 IN UINT8 Index OPTIONAL
,
294 IN UINT8 Selector OPTIONAL
,
295 IN UINT16 Length OPTIONAL
,
296 IN UINT32 Value OPTIONAL
299 ASSERT (TsfBase
!= NULL
);
300 ASSERT (Opcode
<= UtpQueryFuncOpcodeTogFlag
);
302 TsfBase
->Opcode
= Opcode
;
303 if (Opcode
!= UtpQueryFuncOpcodeNop
) {
304 TsfBase
->DescId
= DescId
;
305 TsfBase
->Index
= Index
;
306 TsfBase
->Selector
= Selector
;
308 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
309 SwapLittleEndianToBigEndian ((UINT8
*)&Length
, sizeof (Length
));
310 TsfBase
->Length
= Length
;
313 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
314 SwapLittleEndianToBigEndian ((UINT8
*)&Value
, sizeof (Value
));
315 TsfBase
->Value
= Value
;
321 Initialize COMMAND UPIU.
323 @param[in, out] Command The base address of COMMAND UPIU.
324 @param[in] Lun The Lun on which the SCSI command is executed.
325 @param[in] TaskTag The task tag of request.
326 @param[in] Cdb The cdb buffer containing SCSI command.
327 @param[in] CdbLength The cdb length.
328 @param[in] DataDirection The direction of data transfer.
329 @param[in] ExpDataTranLen The expected transfer data length.
331 @retval EFI_SUCCESS The initialization succeed.
336 IN OUT UTP_COMMAND_UPIU
*Command
,
341 IN UFS_DATA_DIRECTION DataDirection
,
342 IN UINT32 ExpDataTranLen
347 ASSERT ((Command
!= NULL
) && (Cdb
!= NULL
));
350 // Task attribute is hard-coded to Ordered.
352 if (DataDirection
== UfsDataIn
) {
354 } else if (DataDirection
== UfsDataOut
) {
361 // Fill UTP COMMAND UPIU associated fields.
363 Command
->TransCode
= 0x01;
364 Command
->Flags
= Flags
;
366 Command
->TaskTag
= TaskTag
;
367 Command
->CmdSet
= 0x00;
368 SwapLittleEndianToBigEndian ((UINT8
*)&ExpDataTranLen
, sizeof (ExpDataTranLen
));
369 Command
->ExpDataTranLen
= ExpDataTranLen
;
371 CopyMem (Command
->Cdb
, Cdb
, CdbLength
);
377 Initialize UTP PRDT for data transfer.
379 @param[in] Prdt The base address of PRDT.
380 @param[in] Buffer The buffer to be read or written.
381 @param[in] BufferSize The data size to be read or written.
383 @retval EFI_SUCCESS The initialization succeed.
398 ASSERT (((UINTN
)Buffer
& (BIT0
| BIT1
)) == 0);
399 ASSERT ((BufferSize
& (BIT1
| BIT0
)) == 0);
401 if (BufferSize
== 0) {
405 RemainingLen
= BufferSize
;
407 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)BufferSize
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
409 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
410 if (RemainingLen
< UFS_MAX_DATA_LEN_PER_PRD
) {
411 Prdt
[PrdtIndex
].DbCount
= (UINT32
)RemainingLen
- 1;
413 Prdt
[PrdtIndex
].DbCount
= UFS_MAX_DATA_LEN_PER_PRD
- 1;
416 Prdt
[PrdtIndex
].DbAddr
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 2);
417 Prdt
[PrdtIndex
].DbAddrU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 32);
418 RemainingLen
-= UFS_MAX_DATA_LEN_PER_PRD
;
419 Remaining
+= UFS_MAX_DATA_LEN_PER_PRD
;
426 Initialize QUERY REQUEST UPIU.
428 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
429 @param[in] TaskTag The task tag of request.
430 @param[in] Opcode The opcode of request.
431 @param[in] DescId The descriptor ID of request.
432 @param[in] Index The index of request.
433 @param[in] Selector The selector of request.
434 @param[in] DataSize The data size to be read or written.
435 @param[in] Data The buffer to be read or written.
437 @retval EFI_SUCCESS The initialization succeed.
441 UfsInitQueryRequestUpiu (
442 IN OUT UTP_QUERY_REQ_UPIU
*QueryReq
,
448 IN UINTN DataSize OPTIONAL
,
449 IN UINT8
*Data OPTIONAL
452 ASSERT (QueryReq
!= NULL
);
454 QueryReq
->TransCode
= 0x16;
455 QueryReq
->TaskTag
= TaskTag
;
456 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeRdFlag
) || (Opcode
== UtpQueryFuncOpcodeRdAttr
)) {
457 QueryReq
->QueryFunc
= QUERY_FUNC_STD_READ_REQ
;
459 QueryReq
->QueryFunc
= QUERY_FUNC_STD_WRITE_REQ
;
462 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
463 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, *(UINT32
*)Data
);
464 } else if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
465 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, (UINT16
)DataSize
, 0);
467 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, 0);
470 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
471 CopyMem (QueryReq
+ 1, Data
, DataSize
);
473 SwapLittleEndianToBigEndian ((UINT8
*)&DataSize
, sizeof (UINT16
));
474 QueryReq
->DataSegLen
= (UINT16
)DataSize
;
481 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
483 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
484 @param[in] Lun The Lun on which the SCSI command is executed.
485 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
486 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
487 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
488 @param[out] CmdDescMapping A resulting value to pass to Unmap().
490 @retval EFI_SUCCESS The creation succeed.
491 @retval EFI_DEVICE_ERROR The creation failed.
492 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
496 UfsCreateScsiCommandDesc (
497 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
499 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
501 OUT VOID
**CmdDescHost
,
502 OUT VOID
**CmdDescMapping
507 UTP_COMMAND_UPIU
*CommandUpiu
;
508 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
511 UFS_DATA_DIRECTION DataDirection
;
513 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
515 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
516 DataLen
= Packet
->InTransferLength
;
517 DataDirection
= UfsDataIn
;
519 DataLen
= Packet
->OutTransferLength
;
520 DataDirection
= UfsDataOut
;
524 DataDirection
= UfsNoData
;
527 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)DataLen
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
529 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
531 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
532 if (EFI_ERROR (Status
)) {
536 CommandUpiu
= (UTP_COMMAND_UPIU
*)*CmdDescHost
;
538 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, DataLen
);
541 // Fill UTP_TRD associated fields
542 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
543 // *MUST* be located at a 64-bit aligned boundary.
545 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
546 Trd
->Dd
= DataDirection
;
547 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
548 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
549 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
550 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
551 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
552 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
553 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
554 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
559 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
561 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
562 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
563 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
564 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
565 @param[out] CmdDescMapping A resulting value to pass to Unmap().
567 @retval EFI_SUCCESS The creation succeed.
568 @retval EFI_DEVICE_ERROR The creation failed.
569 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
570 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
574 UfsCreateDMCommandDesc (
575 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
576 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
578 OUT VOID
**CmdDescHost
,
579 OUT VOID
**CmdDescMapping
583 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
588 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
591 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
593 Opcode
= Packet
->Opcode
;
594 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
595 return EFI_INVALID_PARAMETER
;
598 DataDirection
= Packet
->DataDirection
;
599 DataSize
= Packet
->TransferLength
;
600 Data
= Packet
->DataBuffer
;
602 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
603 if (DataSize
== 0 || Data
== NULL
) {
604 return EFI_INVALID_PARAMETER
;
606 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
608 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
611 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
612 if (EFI_ERROR (Status
)) {
617 // Initialize UTP QUERY REQUEST UPIU
619 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)*CmdDescHost
;
620 ASSERT (QueryReqUpiu
!= NULL
);
621 UfsInitQueryRequestUpiu (
633 // Fill UTP_TRD associated fields
634 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
636 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
637 Trd
->Dd
= DataDirection
;
638 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
639 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
640 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
641 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
642 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
643 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
644 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
646 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
647 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
654 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
656 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
657 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
658 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
659 @param[out] CmdDescMapping A resulting value to pass to Unmap().
661 @retval EFI_SUCCESS The creation succeed.
662 @retval EFI_DEVICE_ERROR The creation failed.
663 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
667 UfsCreateNopCommandDesc (
668 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
670 OUT VOID
**CmdDescHost
,
671 OUT VOID
**CmdDescMapping
675 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
677 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
679 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
681 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
682 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
683 if (EFI_ERROR (Status
)) {
687 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)*CmdDescHost
;
688 ASSERT (NopOutUpiu
!= NULL
);
689 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
692 // Fill UTP_TRD associated fields
693 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
695 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
697 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
698 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
699 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
700 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
701 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
702 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
708 Find out available slot in transfer list of a UFS device.
710 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
711 @param[out] Slot The available slot.
713 @retval EFI_SUCCESS The available slot was found successfully.
714 @retval EFI_NOT_READY No slot is available at this moment.
718 UfsFindAvailableSlotInTrl (
719 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
728 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
730 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
731 if (EFI_ERROR (Status
)) {
735 Nutrs
= (UINT8
)((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
737 for (Index
= 0; Index
< Nutrs
; Index
++) {
738 if ((Data
& (BIT0
<< Index
)) == 0) {
744 return EFI_NOT_READY
;
749 Start specified slot in transfer list of a UFS device.
751 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
752 @param[in] Slot The slot to be started.
757 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
764 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLRSR_OFFSET
, &Data
);
765 if (EFI_ERROR (Status
)) {
769 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
770 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
771 if (EFI_ERROR (Status
)) {
776 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
);
777 if (EFI_ERROR (Status
)) {
785 Stop specified slot in transfer list of a UFS device.
787 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
788 @param[in] Slot The slot to be stop.
793 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
800 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
801 if (EFI_ERROR (Status
)) {
805 if ((Data
& (BIT0
<< Slot
)) != 0) {
806 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLCLR_OFFSET
, &Data
);
807 if (EFI_ERROR (Status
)) {
811 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLCLR_OFFSET
, Data
& ~(BIT0
<< Slot
));
812 if (EFI_ERROR (Status
)) {
821 Extracts return data from query response upiu.
823 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
824 @param[in] QueryResp Pointer to the query response.
826 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.
827 @retval EFI_DEVICE_ERROR Data returned from device is invalid.
828 @retval EFI_SUCCESS Data extracted.
832 UfsGetReturnDataFromQueryResponse (
833 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
834 IN UTP_QUERY_RESP_UPIU
*QueryResp
837 UINT16 ReturnDataSize
;
840 if (Packet
== NULL
|| QueryResp
== NULL
) {
841 return EFI_INVALID_PARAMETER
;
844 switch (Packet
->Opcode
) {
845 case UtpQueryFuncOpcodeRdDesc
:
846 ReturnDataSize
= QueryResp
->Tsf
.Length
;
847 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
849 // Make sure the hardware device does not return more data than expected.
851 if (ReturnDataSize
> Packet
->TransferLength
) {
852 return EFI_DEVICE_ERROR
;
855 CopyMem (Packet
->DataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
856 Packet
->TransferLength
= ReturnDataSize
;
858 case UtpQueryFuncOpcodeWrDesc
:
859 ReturnDataSize
= QueryResp
->Tsf
.Length
;
860 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
861 Packet
->TransferLength
= ReturnDataSize
;
863 case UtpQueryFuncOpcodeRdFlag
:
864 case UtpQueryFuncOpcodeSetFlag
:
865 case UtpQueryFuncOpcodeClrFlag
:
866 case UtpQueryFuncOpcodeTogFlag
:
868 // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value
870 *((UINT8
*)(Packet
->DataBuffer
)) = *((UINT8
*)&(QueryResp
->Tsf
.Value
) + 3);
872 case UtpQueryFuncOpcodeRdAttr
:
873 case UtpQueryFuncOpcodeWrAttr
:
874 ReturnData
= QueryResp
->Tsf
.Value
;
875 SwapLittleEndianToBigEndian ((UINT8
*) &ReturnData
, sizeof (UINT32
));
876 CopyMem (Packet
->DataBuffer
, &ReturnData
, sizeof (UINT32
));
879 return EFI_INVALID_PARAMETER
;
886 Creates Transfer Request descriptor and sends Query Request to the device.
888 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
889 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
891 @retval EFI_SUCCESS The device descriptor was read/written successfully.
892 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
893 combination to point to a type of UFS device descriptor.
894 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
895 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
899 UfsSendDmRequestRetry (
900 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
901 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
907 VOID
*CmdDescMapping
;
909 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
910 UTP_QUERY_RESP_UPIU
*QueryResp
;
914 // Find out which slot of transfer request list is available.
916 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
917 if (EFI_ERROR (Status
)) {
921 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
923 // Fill transfer request descriptor to this slot.
925 Status
= UfsCreateDMCommandDesc (Private
, Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
926 if (EFI_ERROR (Status
)) {
927 DEBUG ((DEBUG_ERROR
, "Failed to create DM command descriptor\n"));
931 UfsHc
= Private
->UfsHostController
;
932 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
933 ASSERT (QueryResp
!= NULL
);
934 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
937 // Start to execute the transfer request.
939 UfsStartExecCmd (Private
, Slot
);
942 // Wait for the completion of the transfer request.
944 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
, 0, Packet
->Timeout
);
945 if (EFI_ERROR (Status
)) {
949 if (Trd
->Ocs
!= 0 || QueryResp
->QueryResp
!= UfsUtpQueryResponseSuccess
) {
950 DEBUG ((DEBUG_ERROR
, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd
->Ocs
, QueryResp
->QueryResp
));
951 DumpQueryResponseResult (QueryResp
->QueryResp
);
953 if ((QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidSelector
) ||
954 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIndex
) ||
955 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIdn
)) {
956 Status
= EFI_INVALID_PARAMETER
;
958 Status
= EFI_DEVICE_ERROR
;
963 Status
= UfsGetReturnDataFromQueryResponse (Packet
, QueryResp
);
964 if (EFI_ERROR (Status
)) {
965 DEBUG ((DEBUG_ERROR
, "Failed to get return data from query response\n"));
970 UfsHc
->Flush (UfsHc
);
972 UfsStopExecCmd (Private
, Slot
);
974 if (CmdDescMapping
!= NULL
) {
975 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
977 if (CmdDescHost
!= NULL
) {
978 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
985 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
987 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
988 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.
990 @retval EFI_SUCCESS The device responded correctly to the Query request.
991 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
992 combination to point to a type of UFS device descriptor.
993 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
994 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
999 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1000 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
1006 Status
= EFI_SUCCESS
;
1008 for (Retry
= 0; Retry
< 5; Retry
++) {
1009 Status
= UfsSendDmRequestRetry (Private
, Packet
);
1010 if (!EFI_ERROR (Status
)) {
1015 DEBUG ((DEBUG_ERROR
, "Failed to get response from the device after %d retries\n", Retry
));
1020 Read or write specified device descriptor of a UFS device.
1022 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1023 @param[in] Read The boolean variable to show r/w direction.
1024 @param[in] DescId The ID of device descriptor.
1025 @param[in] Index The Index of device descriptor.
1026 @param[in] Selector The Selector of device descriptor.
1027 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
1028 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
1029 of the data buffer specified by Descriptor. On output, the number
1030 of bytes that were actually transferred.
1032 @retval EFI_SUCCESS The device descriptor was read/written successfully.
1033 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a
1034 type of UFS device descriptor.
1035 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
1036 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
1041 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1046 IN OUT VOID
*Descriptor
,
1047 IN OUT UINT32
*DescSize
1050 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1053 if (DescSize
== NULL
) {
1054 return EFI_INVALID_PARAMETER
;
1057 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1060 Packet
.DataDirection
= UfsDataIn
;
1061 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
1063 Packet
.DataDirection
= UfsDataOut
;
1064 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
1066 Packet
.DataBuffer
= Descriptor
;
1067 Packet
.TransferLength
= *DescSize
;
1068 Packet
.DescId
= DescId
;
1069 Packet
.Index
= Index
;
1070 Packet
.Selector
= Selector
;
1071 Packet
.Timeout
= UFS_TIMEOUT
;
1073 Status
= UfsSendDmRequest (Private
, &Packet
);
1074 if (EFI_ERROR (Status
)) {
1077 *DescSize
= Packet
.TransferLength
;
1084 Read or write specified attribute of a UFS device.
1086 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1087 @param[in] Read The boolean variable to show r/w direction.
1088 @param[in] AttrId The ID of Attribute.
1089 @param[in] Index The Index of Attribute.
1090 @param[in] Selector The Selector of Attribute.
1091 @param[in, out] Attributes The value of Attribute to be read or written.
1093 @retval EFI_SUCCESS The Attribute was read/written successfully.
1094 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a
1095 type of UFS device descriptor.
1096 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
1097 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
1102 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1107 IN OUT UINT32
*Attributes
1110 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1112 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1115 Packet
.DataDirection
= UfsDataIn
;
1116 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
1118 Packet
.DataDirection
= UfsDataOut
;
1119 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
1121 Packet
.DataBuffer
= Attributes
;
1122 Packet
.DescId
= AttrId
;
1123 Packet
.Index
= Index
;
1124 Packet
.Selector
= Selector
;
1125 Packet
.Timeout
= UFS_TIMEOUT
;
1127 return UfsSendDmRequest (Private
, &Packet
);
1131 Read or write specified flag of a UFS device.
1133 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1134 @param[in] Read The boolean variable to show r/w direction.
1135 @param[in] FlagId The ID of flag to be read or written.
1136 @param[in, out] Value The value to set or clear flag.
1138 @retval EFI_SUCCESS The flag was read/written successfully.
1139 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.
1140 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1141 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1146 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1152 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1154 if (Value
== NULL
) {
1155 return EFI_INVALID_PARAMETER
;
1158 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1161 ASSERT (Value
!= NULL
);
1162 Packet
.DataDirection
= UfsDataIn
;
1163 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1165 Packet
.DataDirection
= UfsDataOut
;
1167 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1168 } else if (*Value
== 0) {
1169 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1171 return EFI_INVALID_PARAMETER
;
1174 Packet
.DataBuffer
= Value
;
1175 Packet
.DescId
= FlagId
;
1177 Packet
.Selector
= 0;
1178 Packet
.Timeout
= UFS_TIMEOUT
;
1180 return UfsSendDmRequest (Private
, &Packet
);
1184 Set specified flag to 1 on a UFS device.
1186 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1187 @param[in] FlagId The ID of flag to be set.
1189 @retval EFI_SUCCESS The flag was set successfully.
1190 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1191 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1196 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1204 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1210 Read specified flag from a UFS device.
1212 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1213 @param[in] FlagId The ID of flag to be read.
1214 @param[out] Value The flag's value.
1216 @retval EFI_SUCCESS The flag was read successfully.
1217 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1218 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1223 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1230 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1236 Sends NOP IN cmd to a UFS device for initialization process request.
1237 For more details, please refer to UFS 2.0 spec Figure 13.3.
1239 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1241 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1242 received successfully.
1243 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1244 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1245 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1250 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1256 UTP_NOP_IN_UPIU
*NopInUpiu
;
1259 VOID
*CmdDescMapping
;
1260 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1263 // Find out which slot of transfer request list is available.
1265 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1266 if (EFI_ERROR (Status
)) {
1270 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1271 Status
= UfsCreateNopCommandDesc (Private
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1272 if (EFI_ERROR (Status
)) {
1277 // Check the transfer request result.
1279 UfsHc
= Private
->UfsHostController
;
1280 NopInUpiu
= (UTP_NOP_IN_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1281 ASSERT (NopInUpiu
!= NULL
);
1282 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1285 // Start to execute the transfer request.
1287 UfsStartExecCmd (Private
, Slot
);
1290 // Wait for the completion of the transfer request.
1292 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1293 if (EFI_ERROR (Status
)) {
1297 if (NopInUpiu
->Resp
!= 0) {
1298 Status
= EFI_DEVICE_ERROR
;
1300 Status
= EFI_SUCCESS
;
1304 UfsHc
->Flush (UfsHc
);
1306 UfsStopExecCmd (Private
, Slot
);
1308 if (CmdDescMapping
!= NULL
) {
1309 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1311 if (CmdDescHost
!= NULL
) {
1312 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1319 Cleanup data buffers after data transfer. This function
1320 also takes care to copy all data to user memory pool for
1321 unaligned data transfers.
1323 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA
1324 @param[in] TransReq Pointer to the transfer request
1327 UfsReconcileDataTransferBuffer (
1328 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1329 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
1332 if (TransReq
->DataBufMapping
!= NULL
) {
1333 Private
->UfsHostController
->Unmap (
1334 Private
->UfsHostController
,
1335 TransReq
->DataBufMapping
1340 // Check if unaligned transfer was performed. If it was and we read
1341 // data from device copy memory to user data buffers before cleanup.
1342 // The assumption is if auxiliary aligned data buffer is not NULL then
1343 // unaligned transfer has been performed.
1345 if (TransReq
->AlignedDataBuf
!= NULL
) {
1346 if (TransReq
->Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1347 CopyMem (TransReq
->Packet
->InDataBuffer
, TransReq
->AlignedDataBuf
, TransReq
->Packet
->InTransferLength
);
1350 // Wipe out the transfer buffer in case it contains sensitive data.
1352 ZeroMem (TransReq
->AlignedDataBuf
, TransReq
->AlignedDataBufSize
);
1353 FreeAlignedPages (TransReq
->AlignedDataBuf
, EFI_SIZE_TO_PAGES (TransReq
->AlignedDataBufSize
));
1354 TransReq
->AlignedDataBuf
= NULL
;
1359 Prepare data buffer for transfer.
1361 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA
1362 @param[in, out] TransReq Pointer to the transfer request
1364 @retval EFI_DEVICE_ERROR Failed to prepare buffer for transfer
1365 @retval EFI_SUCCESS Buffer ready for transfer
1368 UfsPrepareDataTransferBuffer (
1369 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1370 IN OUT UFS_PASS_THRU_TRANS_REQ
*TransReq
1377 EFI_PHYSICAL_ADDRESS DataBufPhyAddr
;
1378 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag
;
1379 UTP_TR_PRD
*PrdtBase
;
1385 // For unaligned data transfers we allocate auxiliary DWORD aligned memory pool.
1386 // When command is finished auxiliary memory pool is copied into actual user memory.
1387 // This is requiered to assure data transfer safety(DWORD alignment required by UFS spec.)
1389 if (TransReq
->Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1390 if (((UINTN
)TransReq
->Packet
->InDataBuffer
% 4 != 0) || (TransReq
->Packet
->InTransferLength
% 4 != 0)) {
1391 DataLen
= TransReq
->Packet
->InTransferLength
+ (4 - (TransReq
->Packet
->InTransferLength
% 4));
1392 DataBuf
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen
), 4);
1393 if (DataBuf
== NULL
) {
1394 return EFI_DEVICE_ERROR
;
1396 ZeroMem (DataBuf
, DataLen
);
1397 TransReq
->AlignedDataBuf
= DataBuf
;
1398 TransReq
->AlignedDataBufSize
= DataLen
;
1400 DataLen
= TransReq
->Packet
->InTransferLength
;
1401 DataBuf
= TransReq
->Packet
->InDataBuffer
;
1403 Flag
= EdkiiUfsHcOperationBusMasterWrite
;
1405 if (((UINTN
)TransReq
->Packet
->OutDataBuffer
% 4 != 0) || (TransReq
->Packet
->OutTransferLength
% 4 != 0)) {
1406 DataLen
= TransReq
->Packet
->OutTransferLength
+ (4 - (TransReq
->Packet
->OutTransferLength
% 4));
1407 DataBuf
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen
), 4);
1408 if (DataBuf
== NULL
) {
1409 return EFI_DEVICE_ERROR
;
1411 CopyMem (DataBuf
, TransReq
->Packet
->OutDataBuffer
, TransReq
->Packet
->OutTransferLength
);
1412 TransReq
->AlignedDataBuf
= DataBuf
;
1413 TransReq
->AlignedDataBufSize
= DataLen
;
1415 DataLen
= TransReq
->Packet
->OutTransferLength
;
1416 DataBuf
= TransReq
->Packet
->OutDataBuffer
;
1418 Flag
= EdkiiUfsHcOperationBusMasterRead
;
1422 MapLength
= DataLen
;
1423 Status
= Private
->UfsHostController
->Map (
1424 Private
->UfsHostController
,
1429 &TransReq
->DataBufMapping
1432 if (EFI_ERROR (Status
) || (DataLen
!= MapLength
)) {
1433 if (TransReq
->AlignedDataBuf
!= NULL
) {
1435 // Wipe out the transfer buffer in case it contains sensitive data.
1437 ZeroMem (TransReq
->AlignedDataBuf
, TransReq
->AlignedDataBufSize
);
1438 FreeAlignedPages (TransReq
->AlignedDataBuf
, EFI_SIZE_TO_PAGES (TransReq
->AlignedDataBufSize
));
1439 TransReq
->AlignedDataBuf
= NULL
;
1441 return EFI_DEVICE_ERROR
;
1446 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1448 PrdtBase
= (UTP_TR_PRD
*)((UINT8
*)TransReq
->CmdDescHost
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
1449 ASSERT (PrdtBase
!= NULL
);
1450 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)DataBufPhyAddr
, DataLen
);
1456 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1458 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1459 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1460 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1462 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1463 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1464 Event is not NULL and non blocking I/O is supported, then
1465 nonblocking I/O is performed, and Event will be signaled when the
1466 SCSI Request Packet completes.
1468 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1469 commands, InTransferLength bytes were transferred from
1470 InDataBuffer. For write and bi-directional commands,
1471 OutTransferLength bytes were transferred by
1473 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1475 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1476 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1481 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1483 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
1484 IN EFI_EVENT Event OPTIONAL
1488 UTP_RESPONSE_UPIU
*Response
;
1489 UINT16 SenseDataLen
;
1490 UINT32 ResTranCount
;
1492 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
1493 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1495 TransReq
= AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ
));
1496 if (TransReq
== NULL
) {
1497 return EFI_OUT_OF_RESOURCES
;
1500 TransReq
->Signature
= UFS_PASS_THRU_TRANS_REQ_SIG
;
1501 TransReq
->TimeoutRemain
= Packet
->Timeout
;
1502 TransReq
->Packet
= Packet
;
1504 UfsHc
= Private
->UfsHostController
;
1506 // Find out which slot of transfer request list is available.
1508 Status
= UfsFindAvailableSlotInTrl (Private
, &TransReq
->Slot
);
1509 if (EFI_ERROR (Status
)) {
1513 TransReq
->Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + TransReq
->Slot
;
1516 // Fill transfer request descriptor to this slot.
1518 Status
= UfsCreateScsiCommandDesc (
1523 &TransReq
->CmdDescHost
,
1524 &TransReq
->CmdDescMapping
1526 if (EFI_ERROR (Status
)) {
1530 TransReq
->CmdDescSize
= TransReq
->Trd
->PrdtO
* sizeof (UINT32
) + TransReq
->Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1532 Status
= UfsPrepareDataTransferBuffer (Private
, TransReq
);
1533 if (EFI_ERROR (Status
)) {
1538 // Insert the async SCSI cmd to the Async I/O list
1540 if (Event
!= NULL
) {
1541 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1542 TransReq
->CallerEvent
= Event
;
1543 InsertTailList (&Private
->Queue
, &TransReq
->TransferList
);
1544 gBS
->RestoreTPL (OldTpl
);
1548 // Start to execute the transfer request.
1550 UfsStartExecCmd (Private
, TransReq
->Slot
);
1553 // Immediately return for async I/O.
1555 if (Event
!= NULL
) {
1560 // Wait for the completion of the transfer request.
1562 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< TransReq
->Slot
, 0, Packet
->Timeout
);
1563 if (EFI_ERROR (Status
)) {
1568 // Get sense data if exists
1570 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
1571 ASSERT (Response
!= NULL
);
1572 SenseDataLen
= Response
->SenseDataLen
;
1573 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1575 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1577 // Make sure the hardware device does not return more data than expected.
1579 if (SenseDataLen
<= Packet
->SenseDataLength
) {
1580 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1581 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1583 Packet
->SenseDataLength
= 0;
1588 // Check the transfer request result.
1590 Packet
->TargetStatus
= Response
->Status
;
1591 if (Response
->Response
!= 0) {
1592 DEBUG ((DEBUG_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1593 Status
= EFI_DEVICE_ERROR
;
1597 if (TransReq
->Trd
->Ocs
== 0) {
1598 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1599 if ((Response
->Flags
& BIT5
) == BIT5
) {
1600 ResTranCount
= Response
->ResTranCount
;
1601 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1602 Packet
->InTransferLength
-= ResTranCount
;
1605 if ((Response
->Flags
& BIT5
) == BIT5
) {
1606 ResTranCount
= Response
->ResTranCount
;
1607 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1608 Packet
->OutTransferLength
-= ResTranCount
;
1612 Status
= EFI_DEVICE_ERROR
;
1616 UfsHc
->Flush (UfsHc
);
1618 UfsStopExecCmd (Private
, TransReq
->Slot
);
1620 UfsReconcileDataTransferBuffer (Private
, TransReq
);
1623 if (TransReq
->CmdDescMapping
!= NULL
) {
1624 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
1626 if (TransReq
->CmdDescHost
!= NULL
) {
1627 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
), TransReq
->CmdDescHost
);
1629 if (TransReq
!= NULL
) {
1630 FreePool (TransReq
);
1638 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1639 @param[in, out] UicCommand UIC command descriptor. On exit contains UIC command results.
1641 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1642 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1646 UfsExecUicCommands (
1647 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1648 IN OUT EDKII_UIC_COMMAND
*UicCommand
1654 Status
= UfsMmioRead32 (Private
, UFS_HC_IS_OFFSET
, &Data
);
1655 if (EFI_ERROR (Status
)) {
1659 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1661 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1663 Status
= UfsMmioWrite32 (Private
, UFS_HC_IS_OFFSET
, Data
);
1664 if (EFI_ERROR (Status
)) {
1670 // When programming UIC command registers, host software shall set the register UICCMD
1671 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1674 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG1_OFFSET
, UicCommand
->Arg1
);
1675 if (EFI_ERROR (Status
)) {
1679 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, UicCommand
->Arg2
);
1680 if (EFI_ERROR (Status
)) {
1684 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, UicCommand
->Arg3
);
1685 if (EFI_ERROR (Status
)) {
1690 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1692 Status
= UfsWaitMemSet (Private
, UFS_HC_STATUS_OFFSET
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1693 if (EFI_ERROR (Status
)) {
1697 Status
= UfsMmioWrite32 (Private
, UFS_HC_UIC_CMD_OFFSET
, UicCommand
->Opcode
);
1698 if (EFI_ERROR (Status
)) {
1703 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1704 // This bit is set to '1' by the host controller upon completion of a UIC command.
1706 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1707 if (EFI_ERROR (Status
)) {
1711 if (UicCommand
->Opcode
!= UfsUicDmeReset
) {
1712 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, &UicCommand
->Arg2
);
1713 if (EFI_ERROR (Status
)) {
1716 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, &UicCommand
->Arg3
);
1717 if (EFI_ERROR (Status
)) {
1720 if ((UicCommand
->Arg2
& 0xFF) != 0) {
1722 DumpUicCmdExecResult ((UINT8
)UicCommand
->Opcode
, (UINT8
)(UicCommand
->Arg2
& 0xFF));
1724 return EFI_DEVICE_ERROR
;
1732 Allocate common buffer for host and UFS bus master access simultaneously.
1734 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1735 @param[in] Size The length of buffer to be allocated.
1736 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1737 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1738 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1740 @retval EFI_SUCCESS The common buffer was allocated successfully.
1741 @retval EFI_DEVICE_ERROR The allocation fails.
1742 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1746 UfsAllocateAlignCommonBuffer (
1747 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1749 OUT VOID
**CmdDescHost
,
1750 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1751 OUT VOID
**CmdDescMapping
1756 BOOLEAN Is32BitAddr
;
1757 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1759 if ((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1760 Is32BitAddr
= FALSE
;
1765 UfsHc
= Private
->UfsHostController
;
1766 Status
= UfsHc
->AllocateBuffer (
1769 EfiBootServicesData
,
1770 EFI_SIZE_TO_PAGES (Size
),
1774 if (EFI_ERROR (Status
)) {
1775 *CmdDescMapping
= NULL
;
1776 *CmdDescHost
= NULL
;
1777 *CmdDescPhyAddr
= 0;
1778 return EFI_OUT_OF_RESOURCES
;
1781 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1782 Status
= UfsHc
->Map (
1784 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1791 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1794 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1797 *CmdDescHost
= NULL
;
1798 return EFI_OUT_OF_RESOURCES
;
1801 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1803 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1811 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1814 *CmdDescMapping
= NULL
;
1815 *CmdDescHost
= NULL
;
1816 return EFI_DEVICE_ERROR
;
1819 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1824 Enable the UFS host controller for accessing.
1826 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1828 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1829 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1833 UfsEnableHostController (
1834 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1840 if (mUfsHcPlatform
!= NULL
&& mUfsHcPlatform
->Callback
!= NULL
) {
1841 Status
= mUfsHcPlatform
->Callback (Private
->Handle
, EdkiiUfsHcPreHce
, &Private
->UfsHcDriverInterface
);
1842 if (EFI_ERROR (Status
)) {
1843 DEBUG ((DEBUG_ERROR
, "Failure from platform driver during EdkiiUfsHcPreHce, Status = %r\n", Status
));
1849 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1851 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1853 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
1854 if (EFI_ERROR (Status
)) {
1858 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1860 // Write a 0 to the HCE register at first to disable the host controller.
1862 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
1863 if (EFI_ERROR (Status
)) {
1867 // Wait until HCE is read as '0' before continuing.
1869 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1870 if (EFI_ERROR (Status
)) {
1871 return EFI_DEVICE_ERROR
;
1876 // Write a 1 to the HCE register to enable the UFS host controller.
1878 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
);
1879 if (EFI_ERROR (Status
)) {
1884 // Wait until HCE is read as '1' before continuing.
1886 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1887 if (EFI_ERROR (Status
)) {
1888 return EFI_DEVICE_ERROR
;
1891 if (mUfsHcPlatform
!= NULL
&& mUfsHcPlatform
->Callback
!= NULL
) {
1892 Status
= mUfsHcPlatform
->Callback (Private
->Handle
, EdkiiUfsHcPostHce
, &Private
->UfsHcDriverInterface
);
1893 if (EFI_ERROR (Status
)) {
1894 DEBUG ((DEBUG_ERROR
, "Failure from platform driver during EdkiiUfsHcPostHce, Status = %r\n", Status
));
1903 Detect if a UFS device attached.
1905 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1907 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1908 @retval EFI_NOT_FOUND Not found a UFS device attached.
1909 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1913 UfsDeviceDetection (
1914 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1920 EDKII_UIC_COMMAND LinkStartupCommand
;
1922 if (mUfsHcPlatform
!= NULL
&& mUfsHcPlatform
->Callback
!= NULL
) {
1923 Status
= mUfsHcPlatform
->Callback (Private
->Handle
, EdkiiUfsHcPreLinkStartup
, &Private
->UfsHcDriverInterface
);
1924 if (EFI_ERROR (Status
)) {
1925 DEBUG ((DEBUG_ERROR
, "Failure from platform driver during EdkiiUfsHcPreLinkStartup, Status = %r\n", Status
));
1931 // Start UFS device detection.
1932 // Try up to 3 times for establishing data link with device.
1934 for (Retry
= 0; Retry
< 3; Retry
++) {
1935 LinkStartupCommand
.Opcode
= UfsUicDmeLinkStartup
;
1936 LinkStartupCommand
.Arg1
= 0;
1937 LinkStartupCommand
.Arg2
= 0;
1938 LinkStartupCommand
.Arg3
= 0;
1939 Status
= UfsExecUicCommands (Private
, &LinkStartupCommand
);
1940 if (EFI_ERROR (Status
)) {
1941 return EFI_DEVICE_ERROR
;
1944 Status
= UfsMmioRead32 (Private
, UFS_HC_STATUS_OFFSET
, &Data
);
1945 if (EFI_ERROR (Status
)) {
1946 return EFI_DEVICE_ERROR
;
1949 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1950 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1951 if (EFI_ERROR (Status
)) {
1952 return EFI_DEVICE_ERROR
;
1955 if (mUfsHcPlatform
!= NULL
&& mUfsHcPlatform
->Callback
!= NULL
) {
1956 Status
= mUfsHcPlatform
->Callback (Private
->Handle
, EdkiiUfsHcPostLinkStartup
, &Private
->UfsHcDriverInterface
);
1957 if (EFI_ERROR (Status
)) {
1958 DEBUG ((DEBUG_ERROR
, "Failure from platform driver during EdkiiUfsHcPostLinkStartup, Status = %r\n", Status
));
1966 return EFI_NOT_FOUND
;
1970 Initialize UFS task management request list related h/w context.
1972 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1974 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1975 @retval EFI_DEVICE_ERROR The initialization fails.
1979 UfsInitTaskManagementRequestList (
1980 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1985 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1986 VOID
*CmdDescMapping
;
1990 // Initial h/w and s/w context for future operations.
1993 CmdDescMapping
= NULL
;
1997 // Allocate and initialize UTP Task Management Request List.
1999 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
2000 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
2001 if (EFI_ERROR (Status
)) {
2006 // Program the UTP Task Management Request List Base Address and UTP Task Management
2007 // Request List Base Address with a 64-bit address allocated at step 6.
2009 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
2010 if (EFI_ERROR (Status
)) {
2014 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
2015 if (EFI_ERROR (Status
)) {
2018 Private
->UtpTmrlBase
= CmdDescHost
;
2019 Private
->Nutmrs
= Nutmrs
;
2020 Private
->TmrlMapping
= CmdDescMapping
;
2023 // Enable the UTP Task Management Request List by setting the UTP Task Management
2024 // Request List RunStop Register (UTMRLRSR) to '1'.
2026 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
2027 if (EFI_ERROR (Status
)) {
2035 Initialize UFS transfer request list related h/w context.
2037 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2039 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
2040 @retval EFI_DEVICE_ERROR The initialization fails.
2044 UfsInitTransferRequestList (
2045 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2050 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
2051 VOID
*CmdDescMapping
;
2055 // Initial h/w and s/w context for future operations.
2058 CmdDescMapping
= NULL
;
2062 // Allocate and initialize UTP Transfer Request List.
2064 Nutrs
= (UINT8
)((Private
->UfsHcInfo
.Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
2065 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
2066 if (EFI_ERROR (Status
)) {
2071 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
2072 // Base Address with a 64-bit address allocated at step 8.
2074 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
2075 if (EFI_ERROR (Status
)) {
2079 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
2080 if (EFI_ERROR (Status
)) {
2084 Private
->UtpTrlBase
= CmdDescHost
;
2085 Private
->Nutrs
= Nutrs
;
2086 Private
->TrlMapping
= CmdDescMapping
;
2089 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2090 // RunStop Register (UTRLRSR) to '1'.
2092 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
2093 if (EFI_ERROR (Status
)) {
2101 Initialize the UFS host controller.
2103 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2105 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2106 @retval Others A device error occurred while initializing the controller.
2111 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2116 Status
= UfsEnableHostController (Private
);
2117 if (EFI_ERROR (Status
)) {
2118 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2122 Status
= UfsDeviceDetection (Private
);
2123 if (EFI_ERROR (Status
)) {
2124 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2128 Status
= UfsInitTaskManagementRequestList (Private
);
2129 if (EFI_ERROR (Status
)) {
2130 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2134 Status
= UfsInitTransferRequestList (Private
);
2135 if (EFI_ERROR (Status
)) {
2136 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2140 DEBUG ((DEBUG_INFO
, "UfsControllerInit Finished\n"));
2145 Stop the UFS host controller.
2147 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2149 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2150 @retval Others A device error occurred while stopping the controller.
2155 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2162 // Enable the UTP Task Management Request List by setting the UTP Task Management
2163 // Request List RunStop Register (UTMRLRSR) to '1'.
2165 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2166 if (EFI_ERROR (Status
)) {
2171 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2172 // RunStop Register (UTRLRSR) to '1'.
2174 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2175 if (EFI_ERROR (Status
)) {
2180 // Write a 0 to the HCE register in order to disable the host controller.
2182 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2183 if (EFI_ERROR (Status
)) {
2186 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2188 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2189 if (EFI_ERROR (Status
)) {
2194 // Wait until HCE is read as '0' before continuing.
2196 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2197 if (EFI_ERROR (Status
)) {
2198 return EFI_DEVICE_ERROR
;
2201 DEBUG ((DEBUG_INFO
, "UfsController is stopped\n"));
2207 Internal helper function which will signal the caller event and clean up
2210 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2212 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2219 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
2220 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
2223 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
2224 EFI_EVENT CallerEvent
;
2226 ASSERT ((Private
!= NULL
) && (TransReq
!= NULL
));
2228 UfsHc
= Private
->UfsHostController
;
2229 CallerEvent
= TransReq
->CallerEvent
;
2231 RemoveEntryList (&TransReq
->TransferList
);
2233 UfsHc
->Flush (UfsHc
);
2235 UfsStopExecCmd (Private
, TransReq
->Slot
);
2237 UfsReconcileDataTransferBuffer (Private
, TransReq
);
2239 if (TransReq
->CmdDescMapping
!= NULL
) {
2240 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
2242 if (TransReq
->CmdDescHost
!= NULL
) {
2245 EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
),
2246 TransReq
->CmdDescHost
2250 FreePool (TransReq
);
2252 gBS
->SignalEvent (CallerEvent
);
2257 Call back function when the timer event is signaled.
2259 @param[in] Event The Event this notify function registered to.
2260 @param[in] Context Pointer to the context data registered to the Event.
2265 ProcessAsyncTaskList (
2270 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2272 LIST_ENTRY
*NextEntry
;
2273 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
2274 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
;
2275 UTP_RESPONSE_UPIU
*Response
;
2276 UINT16 SenseDataLen
;
2277 UINT32 ResTranCount
;
2282 Private
= (UFS_PASS_THRU_PRIVATE_DATA
*) Context
;
2286 // Check the entries in the async I/O queue are done or not.
2288 if (!IsListEmpty(&Private
->Queue
)) {
2289 BASE_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
2290 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
2291 Packet
= TransReq
->Packet
;
2293 if ((SlotsMap
& (BIT0
<< TransReq
->Slot
)) != 0) {
2296 SlotsMap
|= BIT0
<< TransReq
->Slot
;
2298 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Value
);
2299 if (EFI_ERROR (Status
)) {
2301 // TODO: Should find/add a proper host adapter return status for this
2304 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
2305 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq
->CallerEvent
));
2306 SignalCallerEvent (Private
, TransReq
);
2310 if ((Value
& (BIT0
<< TransReq
->Slot
)) != 0) {
2312 // Scsi cmd not finished yet.
2314 if (TransReq
->TimeoutRemain
> UFS_HC_ASYNC_TIMER
) {
2315 TransReq
->TimeoutRemain
-= UFS_HC_ASYNC_TIMER
;
2321 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
2322 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq
->CallerEvent
));
2323 SignalCallerEvent (Private
, TransReq
);
2328 // Scsi cmd finished.
2330 // Get sense data if exists
2332 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
2333 ASSERT (Response
!= NULL
);
2334 SenseDataLen
= Response
->SenseDataLen
;
2335 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
2337 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
2339 // Make sure the hardware device does not return more data than expected.
2341 if (SenseDataLen
<= Packet
->SenseDataLength
) {
2342 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
2343 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
2345 Packet
->SenseDataLength
= 0;
2350 // Check the transfer request result.
2352 Packet
->TargetStatus
= Response
->Status
;
2353 if (Response
->Response
!= 0) {
2354 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq
->CallerEvent
));
2355 SignalCallerEvent (Private
, TransReq
);
2359 if (TransReq
->Trd
->Ocs
== 0) {
2360 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2361 if ((Response
->Flags
& BIT5
) == BIT5
) {
2362 ResTranCount
= Response
->ResTranCount
;
2363 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2364 Packet
->InTransferLength
-= ResTranCount
;
2367 if ((Response
->Flags
& BIT5
) == BIT5
) {
2368 ResTranCount
= Response
->ResTranCount
;
2369 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2370 Packet
->OutTransferLength
-= ResTranCount
;
2374 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq
->CallerEvent
));
2375 SignalCallerEvent (Private
, TransReq
);
2379 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq
->CallerEvent
));
2380 SignalCallerEvent (Private
, TransReq
);
2387 Execute UIC command.
2389 @param[in] This Pointer to driver interface produced by the UFS controller.
2390 @param[in, out] UicCommand Descriptor of the command that will be executed.
2392 @retval EFI_SUCCESS Command executed successfully.
2393 @retval EFI_INVALID_PARAMETER This or UicCommand is NULL.
2394 @retval Others Command failed to execute.
2398 UfsHcDriverInterfaceExecUicCommand (
2399 IN EDKII_UFS_HC_DRIVER_INTERFACE
*This
,
2400 IN OUT EDKII_UIC_COMMAND
*UicCommand
2403 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2405 if (This
== NULL
|| UicCommand
== NULL
) {
2406 return EFI_INVALID_PARAMETER
;
2409 Private
= UFS_PASS_THRU_PRIVATE_DATA_FROM_DRIVER_INTF (This
);
2411 return UfsExecUicCommands (Private
, UicCommand
);
2415 Initializes UfsHcInfo field in private data.
2417 @param[in] Private Pointer to host controller private data.
2419 @retval EFI_SUCCESS UfsHcInfo initialized successfully.
2420 @retval Others Failed to initalize UfsHcInfo.
2424 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2430 Status
= UfsMmioRead32 (Private
, UFS_HC_VER_OFFSET
, &Data
);
2431 if (EFI_ERROR (Status
)) {
2435 Private
->UfsHcInfo
.Version
= Data
;
2437 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
2438 if (EFI_ERROR (Status
)) {
2442 Private
->UfsHcInfo
.Capabilities
= Data
;
2444 if (mUfsHcPlatform
!= NULL
&& mUfsHcPlatform
->OverrideHcInfo
!= NULL
) {
2445 Status
= mUfsHcPlatform
->OverrideHcInfo (Private
->Handle
, &Private
->UfsHcInfo
);
2446 if (EFI_ERROR (Status
)) {
2447 DEBUG ((DEBUG_ERROR
, "Failure from platform on OverrideHcInfo, Status = %r\n", Status
));