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 - 2018, 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 if ((BufferSize
& (BIT0
| BIT1
)) != 0) {
398 BufferSize
&= ~(BIT0
| BIT1
);
399 DEBUG ((DEBUG_WARN
, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize
));
402 if (BufferSize
== 0) {
406 ASSERT (((UINTN
)Buffer
& (BIT0
| BIT1
)) == 0);
408 RemainingLen
= BufferSize
;
410 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)BufferSize
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
412 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
413 if (RemainingLen
< UFS_MAX_DATA_LEN_PER_PRD
) {
414 Prdt
[PrdtIndex
].DbCount
= (UINT32
)RemainingLen
- 1;
416 Prdt
[PrdtIndex
].DbCount
= UFS_MAX_DATA_LEN_PER_PRD
- 1;
419 Prdt
[PrdtIndex
].DbAddr
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 2);
420 Prdt
[PrdtIndex
].DbAddrU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 32);
421 RemainingLen
-= UFS_MAX_DATA_LEN_PER_PRD
;
422 Remaining
+= UFS_MAX_DATA_LEN_PER_PRD
;
429 Initialize QUERY REQUEST UPIU.
431 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
432 @param[in] TaskTag The task tag of request.
433 @param[in] Opcode The opcode of request.
434 @param[in] DescId The descriptor ID of request.
435 @param[in] Index The index of request.
436 @param[in] Selector The selector of request.
437 @param[in] DataSize The data size to be read or written.
438 @param[in] Data The buffer to be read or written.
440 @retval EFI_SUCCESS The initialization succeed.
444 UfsInitQueryRequestUpiu (
445 IN OUT UTP_QUERY_REQ_UPIU
*QueryReq
,
451 IN UINTN DataSize OPTIONAL
,
452 IN UINT8
*Data OPTIONAL
455 ASSERT (QueryReq
!= NULL
);
457 QueryReq
->TransCode
= 0x16;
458 QueryReq
->TaskTag
= TaskTag
;
459 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeRdFlag
) || (Opcode
== UtpQueryFuncOpcodeRdAttr
)) {
460 QueryReq
->QueryFunc
= QUERY_FUNC_STD_READ_REQ
;
462 QueryReq
->QueryFunc
= QUERY_FUNC_STD_WRITE_REQ
;
465 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
466 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, *(UINT32
*)Data
);
467 } else if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
468 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, (UINT16
)DataSize
, 0);
470 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, 0);
473 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
474 CopyMem (QueryReq
+ 1, Data
, DataSize
);
476 SwapLittleEndianToBigEndian ((UINT8
*)&DataSize
, sizeof (UINT16
));
477 QueryReq
->DataSegLen
= (UINT16
)DataSize
;
484 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
486 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
487 @param[in] Lun The Lun on which the SCSI command is executed.
488 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
489 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
490 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
491 @param[out] CmdDescMapping A resulting value to pass to Unmap().
493 @retval EFI_SUCCESS The creation succeed.
494 @retval EFI_DEVICE_ERROR The creation failed.
495 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
499 UfsCreateScsiCommandDesc (
500 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
502 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
504 OUT VOID
**CmdDescHost
,
505 OUT VOID
**CmdDescMapping
510 UTP_COMMAND_UPIU
*CommandUpiu
;
511 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
514 UFS_DATA_DIRECTION DataDirection
;
516 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
518 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
519 DataLen
= Packet
->InTransferLength
;
520 DataDirection
= UfsDataIn
;
522 DataLen
= Packet
->OutTransferLength
;
523 DataDirection
= UfsDataOut
;
527 DataDirection
= UfsNoData
;
530 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)DataLen
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
532 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
534 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
535 if (EFI_ERROR (Status
)) {
539 CommandUpiu
= (UTP_COMMAND_UPIU
*)*CmdDescHost
;
541 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, DataLen
);
544 // Fill UTP_TRD associated fields
545 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
546 // *MUST* be located at a 64-bit aligned boundary.
548 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
549 Trd
->Dd
= DataDirection
;
550 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
551 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
552 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
553 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
554 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
555 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
556 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
557 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
562 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
564 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
565 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
566 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
567 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
568 @param[out] CmdDescMapping A resulting value to pass to Unmap().
570 @retval EFI_SUCCESS The creation succeed.
571 @retval EFI_DEVICE_ERROR The creation failed.
572 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
573 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
577 UfsCreateDMCommandDesc (
578 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
579 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
581 OUT VOID
**CmdDescHost
,
582 OUT VOID
**CmdDescMapping
586 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
591 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
594 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
596 Opcode
= Packet
->Opcode
;
597 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
598 return EFI_INVALID_PARAMETER
;
601 DataDirection
= Packet
->DataDirection
;
602 DataSize
= Packet
->TransferLength
;
603 Data
= Packet
->DataBuffer
;
605 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
606 if (DataSize
== 0 || Data
== NULL
) {
607 return EFI_INVALID_PARAMETER
;
609 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
611 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
614 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
615 if (EFI_ERROR (Status
)) {
620 // Initialize UTP QUERY REQUEST UPIU
622 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)*CmdDescHost
;
623 ASSERT (QueryReqUpiu
!= NULL
);
624 UfsInitQueryRequestUpiu (
636 // Fill UTP_TRD associated fields
637 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
639 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
640 Trd
->Dd
= DataDirection
;
641 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
642 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
643 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
644 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
645 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
646 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
647 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
649 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
650 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
657 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
659 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
660 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
661 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
662 @param[out] CmdDescMapping A resulting value to pass to Unmap().
664 @retval EFI_SUCCESS The creation succeed.
665 @retval EFI_DEVICE_ERROR The creation failed.
666 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
670 UfsCreateNopCommandDesc (
671 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
673 OUT VOID
**CmdDescHost
,
674 OUT VOID
**CmdDescMapping
678 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
680 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
682 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
684 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
685 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
686 if (EFI_ERROR (Status
)) {
690 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)*CmdDescHost
;
691 ASSERT (NopOutUpiu
!= NULL
);
692 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
695 // Fill UTP_TRD associated fields
696 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
698 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
700 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
701 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
702 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
703 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
704 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
705 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
711 Find out available slot in transfer list of a UFS device.
713 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
714 @param[out] Slot The available slot.
716 @retval EFI_SUCCESS The available slot was found successfully.
717 @retval EFI_NOT_READY No slot is available at this moment.
721 UfsFindAvailableSlotInTrl (
722 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
731 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
733 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
734 if (EFI_ERROR (Status
)) {
738 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
740 for (Index
= 0; Index
< Nutrs
; Index
++) {
741 if ((Data
& (BIT0
<< Index
)) == 0) {
747 return EFI_NOT_READY
;
752 Start specified slot in transfer list of a UFS device.
754 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
755 @param[in] Slot The slot to be started.
760 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
767 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLRSR_OFFSET
, &Data
);
768 if (EFI_ERROR (Status
)) {
772 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
773 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
774 if (EFI_ERROR (Status
)) {
779 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
);
780 if (EFI_ERROR (Status
)) {
788 Stop specified slot in transfer list of a UFS device.
790 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
791 @param[in] Slot The slot to be stop.
796 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
803 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
804 if (EFI_ERROR (Status
)) {
808 if ((Data
& (BIT0
<< Slot
)) != 0) {
809 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLCLR_OFFSET
, &Data
);
810 if (EFI_ERROR (Status
)) {
814 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLCLR_OFFSET
, Data
& ~(BIT0
<< Slot
));
815 if (EFI_ERROR (Status
)) {
824 Extracts return data from query response upiu.
826 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
827 @param[in] QueryResp Pointer to the query response.
829 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.
830 @retval EFI_DEVICE_ERROR Data returned from device is invalid.
831 @retval EFI_SUCCESS Data extracted.
835 UfsGetReturnDataFromQueryResponse (
836 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
837 IN UTP_QUERY_RESP_UPIU
*QueryResp
840 UINT16 ReturnDataSize
;
843 if (Packet
== NULL
|| QueryResp
== NULL
) {
844 return EFI_INVALID_PARAMETER
;
847 switch (Packet
->Opcode
) {
848 case UtpQueryFuncOpcodeRdDesc
:
849 ReturnDataSize
= QueryResp
->Tsf
.Length
;
850 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
852 // Make sure the hardware device does not return more data than expected.
854 if (ReturnDataSize
> Packet
->TransferLength
) {
855 return EFI_DEVICE_ERROR
;
858 CopyMem (Packet
->DataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
859 Packet
->TransferLength
= ReturnDataSize
;
861 case UtpQueryFuncOpcodeWrDesc
:
862 ReturnDataSize
= QueryResp
->Tsf
.Length
;
863 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
864 Packet
->TransferLength
= ReturnDataSize
;
866 case UtpQueryFuncOpcodeRdFlag
:
867 case UtpQueryFuncOpcodeSetFlag
:
868 case UtpQueryFuncOpcodeClrFlag
:
869 case UtpQueryFuncOpcodeTogFlag
:
870 CopyMem (Packet
->DataBuffer
, &QueryResp
->Tsf
.Value
, sizeof (UINT8
));
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
);
1212 Read specified flag from a UFS device.
1214 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1215 @param[in] FlagId The ID of flag to be read.
1216 @param[out] Value The flag's value.
1218 @retval EFI_SUCCESS The flag was read successfully.
1219 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1220 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1225 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1232 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1238 Sends NOP IN cmd to a UFS device for initialization process request.
1239 For more details, please refer to UFS 2.0 spec Figure 13.3.
1241 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1243 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1244 received successfully.
1245 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1246 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1247 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1252 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1258 UTP_NOP_IN_UPIU
*NopInUpiu
;
1261 VOID
*CmdDescMapping
;
1262 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1265 // Find out which slot of transfer request list is available.
1267 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1268 if (EFI_ERROR (Status
)) {
1272 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1273 Status
= UfsCreateNopCommandDesc (Private
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1274 if (EFI_ERROR (Status
)) {
1279 // Check the transfer request result.
1281 UfsHc
= Private
->UfsHostController
;
1282 NopInUpiu
= (UTP_NOP_IN_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1283 ASSERT (NopInUpiu
!= NULL
);
1284 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1287 // Start to execute the transfer request.
1289 UfsStartExecCmd (Private
, Slot
);
1292 // Wait for the completion of the transfer request.
1294 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1295 if (EFI_ERROR (Status
)) {
1299 if (NopInUpiu
->Resp
!= 0) {
1300 Status
= EFI_DEVICE_ERROR
;
1302 Status
= EFI_SUCCESS
;
1306 UfsHc
->Flush (UfsHc
);
1308 UfsStopExecCmd (Private
, Slot
);
1310 if (CmdDescMapping
!= NULL
) {
1311 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1313 if (CmdDescHost
!= NULL
) {
1314 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1321 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1323 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1324 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1325 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1327 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1328 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1329 Event is not NULL and non blocking I/O is supported, then
1330 nonblocking I/O is performed, and Event will be signaled when the
1331 SCSI Request Packet completes.
1333 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1334 commands, InTransferLength bytes were transferred from
1335 InDataBuffer. For write and bi-directional commands,
1336 OutTransferLength bytes were transferred by
1338 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1340 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1341 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1346 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1348 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
1349 IN EFI_EVENT Event OPTIONAL
1353 UTP_RESPONSE_UPIU
*Response
;
1354 UINT16 SenseDataLen
;
1355 UINT32 ResTranCount
;
1357 EFI_PHYSICAL_ADDRESS DataBufPhyAddr
;
1360 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1361 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag
;
1362 UTP_TR_PRD
*PrdtBase
;
1364 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
1366 TransReq
= AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ
));
1367 if (TransReq
== NULL
) {
1368 return EFI_OUT_OF_RESOURCES
;
1371 TransReq
->Signature
= UFS_PASS_THRU_TRANS_REQ_SIG
;
1372 TransReq
->TimeoutRemain
= Packet
->Timeout
;
1374 UfsHc
= Private
->UfsHostController
;
1376 // Find out which slot of transfer request list is available.
1378 Status
= UfsFindAvailableSlotInTrl (Private
, &TransReq
->Slot
);
1379 if (EFI_ERROR (Status
)) {
1383 TransReq
->Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + TransReq
->Slot
;
1386 // Fill transfer request descriptor to this slot.
1388 Status
= UfsCreateScsiCommandDesc (
1393 &TransReq
->CmdDescHost
,
1394 &TransReq
->CmdDescMapping
1396 if (EFI_ERROR (Status
)) {
1400 TransReq
->CmdDescSize
= TransReq
->Trd
->PrdtO
* sizeof (UINT32
) + TransReq
->Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1402 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1403 DataBuf
= Packet
->InDataBuffer
;
1404 DataLen
= Packet
->InTransferLength
;
1405 Flag
= EdkiiUfsHcOperationBusMasterWrite
;
1407 DataBuf
= Packet
->OutDataBuffer
;
1408 DataLen
= Packet
->OutTransferLength
;
1409 Flag
= EdkiiUfsHcOperationBusMasterRead
;
1413 MapLength
= DataLen
;
1414 Status
= UfsHc
->Map (
1420 &TransReq
->DataBufMapping
1423 if (EFI_ERROR (Status
) || (DataLen
!= MapLength
)) {
1428 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1430 PrdtBase
= (UTP_TR_PRD
*)((UINT8
*)TransReq
->CmdDescHost
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
1431 ASSERT (PrdtBase
!= NULL
);
1432 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)DataBufPhyAddr
, DataLen
);
1435 // Insert the async SCSI cmd to the Async I/O list
1437 if (Event
!= NULL
) {
1438 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1439 TransReq
->Packet
= Packet
;
1440 TransReq
->CallerEvent
= Event
;
1441 InsertTailList (&Private
->Queue
, &TransReq
->TransferList
);
1442 gBS
->RestoreTPL (OldTpl
);
1446 // Start to execute the transfer request.
1448 UfsStartExecCmd (Private
, TransReq
->Slot
);
1451 // Immediately return for async I/O.
1453 if (Event
!= NULL
) {
1458 // Wait for the completion of the transfer request.
1460 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< TransReq
->Slot
, 0, Packet
->Timeout
);
1461 if (EFI_ERROR (Status
)) {
1466 // Get sense data if exists
1468 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
1469 ASSERT (Response
!= NULL
);
1470 SenseDataLen
= Response
->SenseDataLen
;
1471 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1473 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1475 // Make sure the hardware device does not return more data than expected.
1477 if (SenseDataLen
<= Packet
->SenseDataLength
) {
1478 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1479 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1481 Packet
->SenseDataLength
= 0;
1486 // Check the transfer request result.
1488 Packet
->TargetStatus
= Response
->Status
;
1489 if (Response
->Response
!= 0) {
1490 DEBUG ((DEBUG_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1491 Status
= EFI_DEVICE_ERROR
;
1495 if (TransReq
->Trd
->Ocs
== 0) {
1496 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1497 if ((Response
->Flags
& BIT5
) == BIT5
) {
1498 ResTranCount
= Response
->ResTranCount
;
1499 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1500 Packet
->InTransferLength
-= ResTranCount
;
1503 if ((Response
->Flags
& BIT5
) == BIT5
) {
1504 ResTranCount
= Response
->ResTranCount
;
1505 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1506 Packet
->OutTransferLength
-= ResTranCount
;
1510 Status
= EFI_DEVICE_ERROR
;
1514 UfsHc
->Flush (UfsHc
);
1516 UfsStopExecCmd (Private
, TransReq
->Slot
);
1518 if (TransReq
->DataBufMapping
!= NULL
) {
1519 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
1523 if (TransReq
->CmdDescMapping
!= NULL
) {
1524 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
1526 if (TransReq
->CmdDescHost
!= NULL
) {
1527 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
), TransReq
->CmdDescHost
);
1529 if (TransReq
!= NULL
) {
1530 FreePool (TransReq
);
1537 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1539 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1540 @param[in] UicOpcode The opcode of the UIC command.
1541 @param[in] Arg1 The value for 1st argument of the UIC command.
1542 @param[in] Arg2 The value for 2nd argument of the UIC command.
1543 @param[in] Arg3 The value for 3rd argument of the UIC command.
1545 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1546 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1547 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1551 UfsExecUicCommands (
1552 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1562 Status
= UfsMmioRead32 (Private
, UFS_HC_IS_OFFSET
, &Data
);
1563 if (EFI_ERROR (Status
)) {
1567 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1569 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1571 Status
= UfsMmioWrite32 (Private
, UFS_HC_IS_OFFSET
, Data
);
1572 if (EFI_ERROR (Status
)) {
1578 // When programming UIC command registers, host software shall set the register UICCMD
1579 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1582 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG1_OFFSET
, Arg1
);
1583 if (EFI_ERROR (Status
)) {
1587 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, Arg2
);
1588 if (EFI_ERROR (Status
)) {
1592 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, Arg3
);
1593 if (EFI_ERROR (Status
)) {
1598 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1600 Status
= UfsWaitMemSet (Private
, UFS_HC_STATUS_OFFSET
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1601 if (EFI_ERROR (Status
)) {
1605 Status
= UfsMmioWrite32 (Private
, UFS_HC_UIC_CMD_OFFSET
, (UINT32
)UicOpcode
);
1606 if (EFI_ERROR (Status
)) {
1611 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1612 // This bit is set to '1' by the host controller upon completion of a UIC command.
1614 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1615 if (EFI_ERROR (Status
)) {
1619 if (UicOpcode
!= UfsUicDmeReset
) {
1620 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, &Data
);
1621 if (EFI_ERROR (Status
)) {
1624 if ((Data
& 0xFF) != 0) {
1626 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1628 return EFI_DEVICE_ERROR
;
1633 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1635 Status
= UfsMmioRead32 (Private
, UFS_HC_STATUS_OFFSET
, &Data
);
1636 if (EFI_ERROR (Status
)) {
1640 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1641 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1642 if (EFI_ERROR (Status
)) {
1643 return EFI_DEVICE_ERROR
;
1645 return EFI_NOT_FOUND
;
1648 DEBUG ((DEBUG_INFO
, "UfsPassThruDxe: found a attached UFS device\n"));
1654 Allocate common buffer for host and UFS bus master access simultaneously.
1656 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1657 @param[in] Size The length of buffer to be allocated.
1658 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1659 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1660 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1662 @retval EFI_SUCCESS The common buffer was allocated successfully.
1663 @retval EFI_DEVICE_ERROR The allocation fails.
1664 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1668 UfsAllocateAlignCommonBuffer (
1669 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1671 OUT VOID
**CmdDescHost
,
1672 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1673 OUT VOID
**CmdDescMapping
1678 BOOLEAN Is32BitAddr
;
1679 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1681 if ((Private
->Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1682 Is32BitAddr
= FALSE
;
1687 UfsHc
= Private
->UfsHostController
;
1688 Status
= UfsHc
->AllocateBuffer (
1691 EfiBootServicesData
,
1692 EFI_SIZE_TO_PAGES (Size
),
1696 if (EFI_ERROR (Status
)) {
1697 *CmdDescMapping
= NULL
;
1698 *CmdDescHost
= NULL
;
1699 *CmdDescPhyAddr
= 0;
1700 return EFI_OUT_OF_RESOURCES
;
1703 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1704 Status
= UfsHc
->Map (
1706 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1713 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1716 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1719 *CmdDescHost
= NULL
;
1720 return EFI_OUT_OF_RESOURCES
;
1723 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1725 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1733 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1736 *CmdDescMapping
= NULL
;
1737 *CmdDescHost
= NULL
;
1738 return EFI_DEVICE_ERROR
;
1741 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1746 Enable the UFS host controller for accessing.
1748 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1750 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1751 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1755 UfsEnableHostController (
1756 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1763 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1765 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1767 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
1768 if (EFI_ERROR (Status
)) {
1772 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1774 // Write a 0 to the HCE register at first to disable the host controller.
1776 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
1777 if (EFI_ERROR (Status
)) {
1781 // Wait until HCE is read as '0' before continuing.
1783 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1784 if (EFI_ERROR (Status
)) {
1785 return EFI_DEVICE_ERROR
;
1790 // Write a 1 to the HCE register to enable the UFS host controller.
1792 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
);
1793 if (EFI_ERROR (Status
)) {
1798 // Wait until HCE is read as '1' before continuing.
1800 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1801 if (EFI_ERROR (Status
)) {
1802 return EFI_DEVICE_ERROR
;
1809 Detect if a UFS device attached.
1811 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1813 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1814 @retval EFI_NOT_FOUND Not found a UFS device attached.
1815 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1819 UfsDeviceDetection (
1820 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1827 // Start UFS device detection.
1828 // Try up to 3 times for establishing data link with device.
1830 for (Retry
= 0; Retry
< 3; Retry
++) {
1831 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1832 if (!EFI_ERROR (Status
)) {
1836 if (Status
== EFI_NOT_FOUND
) {
1840 return EFI_DEVICE_ERROR
;
1844 return EFI_NOT_FOUND
;
1851 Initialize UFS task management request list related h/w context.
1853 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1855 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1856 @retval EFI_DEVICE_ERROR The initialization fails.
1860 UfsInitTaskManagementRequestList (
1861 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1867 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1868 VOID
*CmdDescMapping
;
1872 // Initial h/w and s/w context for future operations.
1875 CmdDescMapping
= NULL
;
1878 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1879 if (EFI_ERROR (Status
)) {
1883 Private
->Capabilities
= Data
;
1886 // Allocate and initialize UTP Task Management Request List.
1888 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1889 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1890 if (EFI_ERROR (Status
)) {
1895 // Program the UTP Task Management Request List Base Address and UTP Task Management
1896 // Request List Base Address with a 64-bit address allocated at step 6.
1898 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1899 if (EFI_ERROR (Status
)) {
1903 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1904 if (EFI_ERROR (Status
)) {
1907 Private
->UtpTmrlBase
= CmdDescHost
;
1908 Private
->Nutmrs
= Nutmrs
;
1909 Private
->TmrlMapping
= CmdDescMapping
;
1912 // Enable the UTP Task Management Request List by setting the UTP Task Management
1913 // Request List RunStop Register (UTMRLRSR) to '1'.
1915 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
1916 if (EFI_ERROR (Status
)) {
1924 Initialize UFS transfer request list related h/w context.
1926 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1928 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1929 @retval EFI_DEVICE_ERROR The initialization fails.
1933 UfsInitTransferRequestList (
1934 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1940 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1941 VOID
*CmdDescMapping
;
1945 // Initial h/w and s/w context for future operations.
1948 CmdDescMapping
= NULL
;
1951 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1952 if (EFI_ERROR (Status
)) {
1956 Private
->Capabilities
= Data
;
1959 // Allocate and initialize UTP Transfer Request List.
1961 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1962 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1963 if (EFI_ERROR (Status
)) {
1968 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1969 // Base Address with a 64-bit address allocated at step 8.
1971 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1972 if (EFI_ERROR (Status
)) {
1976 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1977 if (EFI_ERROR (Status
)) {
1981 Private
->UtpTrlBase
= CmdDescHost
;
1982 Private
->Nutrs
= Nutrs
;
1983 Private
->TrlMapping
= CmdDescMapping
;
1986 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1987 // RunStop Register (UTRLRSR) to '1'.
1989 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
1990 if (EFI_ERROR (Status
)) {
1998 Initialize the UFS host controller.
2000 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2002 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2003 @retval Others A device error occurred while initializing the controller.
2008 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2013 Status
= UfsEnableHostController (Private
);
2014 if (EFI_ERROR (Status
)) {
2015 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2019 Status
= UfsDeviceDetection (Private
);
2020 if (EFI_ERROR (Status
)) {
2021 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2025 Status
= UfsInitTaskManagementRequestList (Private
);
2026 if (EFI_ERROR (Status
)) {
2027 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2031 Status
= UfsInitTransferRequestList (Private
);
2032 if (EFI_ERROR (Status
)) {
2033 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2037 DEBUG ((DEBUG_INFO
, "UfsControllerInit Finished\n"));
2042 Stop the UFS host controller.
2044 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2046 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2047 @retval Others A device error occurred while stopping the controller.
2052 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2059 // Enable the UTP Task Management Request List by setting the UTP Task Management
2060 // Request List RunStop Register (UTMRLRSR) to '1'.
2062 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2063 if (EFI_ERROR (Status
)) {
2068 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2069 // RunStop Register (UTRLRSR) to '1'.
2071 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2072 if (EFI_ERROR (Status
)) {
2077 // Write a 0 to the HCE register in order to disable the host controller.
2079 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2080 if (EFI_ERROR (Status
)) {
2083 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2085 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2086 if (EFI_ERROR (Status
)) {
2091 // Wait until HCE is read as '0' before continuing.
2093 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2094 if (EFI_ERROR (Status
)) {
2095 return EFI_DEVICE_ERROR
;
2098 DEBUG ((DEBUG_INFO
, "UfsController is stopped\n"));
2105 Internal helper function which will signal the caller event and clean up
2108 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2110 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2117 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
2118 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
2121 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
2122 EFI_EVENT CallerEvent
;
2124 ASSERT ((Private
!= NULL
) && (TransReq
!= NULL
));
2126 UfsHc
= Private
->UfsHostController
;
2127 CallerEvent
= TransReq
->CallerEvent
;
2129 RemoveEntryList (&TransReq
->TransferList
);
2131 UfsHc
->Flush (UfsHc
);
2133 UfsStopExecCmd (Private
, TransReq
->Slot
);
2135 if (TransReq
->DataBufMapping
!= NULL
) {
2136 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
2139 if (TransReq
->CmdDescMapping
!= NULL
) {
2140 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
2142 if (TransReq
->CmdDescHost
!= NULL
) {
2145 EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
),
2146 TransReq
->CmdDescHost
2150 FreePool (TransReq
);
2152 gBS
->SignalEvent (CallerEvent
);
2157 Call back function when the timer event is signaled.
2159 @param[in] Event The Event this notify function registered to.
2160 @param[in] Context Pointer to the context data registered to the Event.
2165 ProcessAsyncTaskList (
2170 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2172 LIST_ENTRY
*NextEntry
;
2173 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
2174 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
;
2175 UTP_RESPONSE_UPIU
*Response
;
2176 UINT16 SenseDataLen
;
2177 UINT32 ResTranCount
;
2182 Private
= (UFS_PASS_THRU_PRIVATE_DATA
*) Context
;
2186 // Check the entries in the async I/O queue are done or not.
2188 if (!IsListEmpty(&Private
->Queue
)) {
2189 EFI_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
2190 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
2191 Packet
= TransReq
->Packet
;
2193 if ((SlotsMap
& (BIT0
<< TransReq
->Slot
)) != 0) {
2196 SlotsMap
|= BIT0
<< TransReq
->Slot
;
2198 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Value
);
2199 if (EFI_ERROR (Status
)) {
2201 // TODO: Should find/add a proper host adapter return status for this
2204 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
2205 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq
->CallerEvent
));
2206 SignalCallerEvent (Private
, TransReq
);
2210 if ((Value
& (BIT0
<< TransReq
->Slot
)) != 0) {
2212 // Scsi cmd not finished yet.
2214 if (TransReq
->TimeoutRemain
> UFS_HC_ASYNC_TIMER
) {
2215 TransReq
->TimeoutRemain
-= UFS_HC_ASYNC_TIMER
;
2221 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
2222 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq
->CallerEvent
));
2223 SignalCallerEvent (Private
, TransReq
);
2228 // Scsi cmd finished.
2230 // Get sense data if exists
2232 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
2233 ASSERT (Response
!= NULL
);
2234 SenseDataLen
= Response
->SenseDataLen
;
2235 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
2237 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
2239 // Make sure the hardware device does not return more data than expected.
2241 if (SenseDataLen
<= Packet
->SenseDataLength
) {
2242 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
2243 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
2245 Packet
->SenseDataLength
= 0;
2250 // Check the transfer request result.
2252 Packet
->TargetStatus
= Response
->Status
;
2253 if (Response
->Response
!= 0) {
2254 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq
->CallerEvent
));
2255 SignalCallerEvent (Private
, TransReq
);
2259 if (TransReq
->Trd
->Ocs
== 0) {
2260 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2261 if ((Response
->Flags
& BIT5
) == BIT5
) {
2262 ResTranCount
= Response
->ResTranCount
;
2263 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2264 Packet
->InTransferLength
-= ResTranCount
;
2267 if ((Response
->Flags
& BIT5
) == BIT5
) {
2268 ResTranCount
= Response
->ResTranCount
;
2269 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2270 Packet
->OutTransferLength
-= ResTranCount
;
2274 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq
->CallerEvent
));
2275 SignalCallerEvent (Private
, TransReq
);
2279 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq
->CallerEvent
));
2280 SignalCallerEvent (Private
, TransReq
);