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
->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
->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
1953 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1954 VOID
*CmdDescMapping
;
1958 // Initial h/w and s/w context for future operations.
1961 CmdDescMapping
= NULL
;
1964 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1965 if (EFI_ERROR (Status
)) {
1969 Private
->Capabilities
= Data
;
1972 // Allocate and initialize UTP Task Management Request List.
1974 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1975 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1976 if (EFI_ERROR (Status
)) {
1981 // Program the UTP Task Management Request List Base Address and UTP Task Management
1982 // Request List Base Address with a 64-bit address allocated at step 6.
1984 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1985 if (EFI_ERROR (Status
)) {
1989 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1990 if (EFI_ERROR (Status
)) {
1993 Private
->UtpTmrlBase
= CmdDescHost
;
1994 Private
->Nutmrs
= Nutmrs
;
1995 Private
->TmrlMapping
= CmdDescMapping
;
1998 // Enable the UTP Task Management Request List by setting the UTP Task Management
1999 // Request List RunStop Register (UTMRLRSR) to '1'.
2001 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
2002 if (EFI_ERROR (Status
)) {
2010 Initialize UFS transfer request list related h/w context.
2012 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2014 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
2015 @retval EFI_DEVICE_ERROR The initialization fails.
2019 UfsInitTransferRequestList (
2020 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2026 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
2027 VOID
*CmdDescMapping
;
2031 // Initial h/w and s/w context for future operations.
2034 CmdDescMapping
= NULL
;
2037 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
2038 if (EFI_ERROR (Status
)) {
2042 Private
->Capabilities
= Data
;
2045 // Allocate and initialize UTP Transfer Request List.
2047 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
2048 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
2049 if (EFI_ERROR (Status
)) {
2054 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
2055 // Base Address with a 64-bit address allocated at step 8.
2057 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
2058 if (EFI_ERROR (Status
)) {
2062 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
2063 if (EFI_ERROR (Status
)) {
2067 Private
->UtpTrlBase
= CmdDescHost
;
2068 Private
->Nutrs
= Nutrs
;
2069 Private
->TrlMapping
= CmdDescMapping
;
2072 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2073 // RunStop Register (UTRLRSR) to '1'.
2075 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
2076 if (EFI_ERROR (Status
)) {
2084 Initialize the UFS host controller.
2086 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2088 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2089 @retval Others A device error occurred while initializing the controller.
2094 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2099 Status
= UfsEnableHostController (Private
);
2100 if (EFI_ERROR (Status
)) {
2101 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2105 Status
= UfsDeviceDetection (Private
);
2106 if (EFI_ERROR (Status
)) {
2107 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2111 Status
= UfsInitTaskManagementRequestList (Private
);
2112 if (EFI_ERROR (Status
)) {
2113 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2117 Status
= UfsInitTransferRequestList (Private
);
2118 if (EFI_ERROR (Status
)) {
2119 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2123 DEBUG ((DEBUG_INFO
, "UfsControllerInit Finished\n"));
2128 Stop the UFS host controller.
2130 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2132 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2133 @retval Others A device error occurred while stopping the controller.
2138 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2145 // Enable the UTP Task Management Request List by setting the UTP Task Management
2146 // Request List RunStop Register (UTMRLRSR) to '1'.
2148 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2149 if (EFI_ERROR (Status
)) {
2154 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2155 // RunStop Register (UTRLRSR) to '1'.
2157 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2158 if (EFI_ERROR (Status
)) {
2163 // Write a 0 to the HCE register in order to disable the host controller.
2165 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2166 if (EFI_ERROR (Status
)) {
2169 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2171 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2172 if (EFI_ERROR (Status
)) {
2177 // Wait until HCE is read as '0' before continuing.
2179 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2180 if (EFI_ERROR (Status
)) {
2181 return EFI_DEVICE_ERROR
;
2184 DEBUG ((DEBUG_INFO
, "UfsController is stopped\n"));
2190 Internal helper function which will signal the caller event and clean up
2193 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2195 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2202 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
2203 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
2206 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
2207 EFI_EVENT CallerEvent
;
2209 ASSERT ((Private
!= NULL
) && (TransReq
!= NULL
));
2211 UfsHc
= Private
->UfsHostController
;
2212 CallerEvent
= TransReq
->CallerEvent
;
2214 RemoveEntryList (&TransReq
->TransferList
);
2216 UfsHc
->Flush (UfsHc
);
2218 UfsStopExecCmd (Private
, TransReq
->Slot
);
2220 UfsReconcileDataTransferBuffer (Private
, TransReq
);
2222 if (TransReq
->CmdDescMapping
!= NULL
) {
2223 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
2225 if (TransReq
->CmdDescHost
!= NULL
) {
2228 EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
),
2229 TransReq
->CmdDescHost
2233 FreePool (TransReq
);
2235 gBS
->SignalEvent (CallerEvent
);
2240 Call back function when the timer event is signaled.
2242 @param[in] Event The Event this notify function registered to.
2243 @param[in] Context Pointer to the context data registered to the Event.
2248 ProcessAsyncTaskList (
2253 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2255 LIST_ENTRY
*NextEntry
;
2256 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
2257 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
;
2258 UTP_RESPONSE_UPIU
*Response
;
2259 UINT16 SenseDataLen
;
2260 UINT32 ResTranCount
;
2265 Private
= (UFS_PASS_THRU_PRIVATE_DATA
*) Context
;
2269 // Check the entries in the async I/O queue are done or not.
2271 if (!IsListEmpty(&Private
->Queue
)) {
2272 EFI_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
2273 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
2274 Packet
= TransReq
->Packet
;
2276 if ((SlotsMap
& (BIT0
<< TransReq
->Slot
)) != 0) {
2279 SlotsMap
|= BIT0
<< TransReq
->Slot
;
2281 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Value
);
2282 if (EFI_ERROR (Status
)) {
2284 // TODO: Should find/add a proper host adapter return status for this
2287 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
2288 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq
->CallerEvent
));
2289 SignalCallerEvent (Private
, TransReq
);
2293 if ((Value
& (BIT0
<< TransReq
->Slot
)) != 0) {
2295 // Scsi cmd not finished yet.
2297 if (TransReq
->TimeoutRemain
> UFS_HC_ASYNC_TIMER
) {
2298 TransReq
->TimeoutRemain
-= UFS_HC_ASYNC_TIMER
;
2304 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
2305 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq
->CallerEvent
));
2306 SignalCallerEvent (Private
, TransReq
);
2311 // Scsi cmd finished.
2313 // Get sense data if exists
2315 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
2316 ASSERT (Response
!= NULL
);
2317 SenseDataLen
= Response
->SenseDataLen
;
2318 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
2320 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
2322 // Make sure the hardware device does not return more data than expected.
2324 if (SenseDataLen
<= Packet
->SenseDataLength
) {
2325 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
2326 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
2328 Packet
->SenseDataLength
= 0;
2333 // Check the transfer request result.
2335 Packet
->TargetStatus
= Response
->Status
;
2336 if (Response
->Response
!= 0) {
2337 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq
->CallerEvent
));
2338 SignalCallerEvent (Private
, TransReq
);
2342 if (TransReq
->Trd
->Ocs
== 0) {
2343 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2344 if ((Response
->Flags
& BIT5
) == BIT5
) {
2345 ResTranCount
= Response
->ResTranCount
;
2346 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2347 Packet
->InTransferLength
-= ResTranCount
;
2350 if ((Response
->Flags
& BIT5
) == BIT5
) {
2351 ResTranCount
= Response
->ResTranCount
;
2352 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2353 Packet
->OutTransferLength
-= ResTranCount
;
2357 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq
->CallerEvent
));
2358 SignalCallerEvent (Private
, TransReq
);
2362 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq
->CallerEvent
));
2363 SignalCallerEvent (Private
, TransReq
);