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
);
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.
1550 UfsExecUicCommands (
1551 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1561 Status
= UfsMmioRead32 (Private
, UFS_HC_IS_OFFSET
, &Data
);
1562 if (EFI_ERROR (Status
)) {
1566 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1568 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1570 Status
= UfsMmioWrite32 (Private
, UFS_HC_IS_OFFSET
, Data
);
1571 if (EFI_ERROR (Status
)) {
1577 // When programming UIC command registers, host software shall set the register UICCMD
1578 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1581 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG1_OFFSET
, Arg1
);
1582 if (EFI_ERROR (Status
)) {
1586 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, Arg2
);
1587 if (EFI_ERROR (Status
)) {
1591 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, Arg3
);
1592 if (EFI_ERROR (Status
)) {
1597 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1599 Status
= UfsWaitMemSet (Private
, UFS_HC_STATUS_OFFSET
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1600 if (EFI_ERROR (Status
)) {
1604 Status
= UfsMmioWrite32 (Private
, UFS_HC_UIC_CMD_OFFSET
, (UINT32
)UicOpcode
);
1605 if (EFI_ERROR (Status
)) {
1610 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1611 // This bit is set to '1' by the host controller upon completion of a UIC command.
1613 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1614 if (EFI_ERROR (Status
)) {
1618 if (UicOpcode
!= UfsUicDmeReset
) {
1619 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, &Data
);
1620 if (EFI_ERROR (Status
)) {
1623 if ((Data
& 0xFF) != 0) {
1625 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1627 return EFI_DEVICE_ERROR
;
1635 Allocate common buffer for host and UFS bus master access simultaneously.
1637 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1638 @param[in] Size The length of buffer to be allocated.
1639 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1640 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1641 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1643 @retval EFI_SUCCESS The common buffer was allocated successfully.
1644 @retval EFI_DEVICE_ERROR The allocation fails.
1645 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1649 UfsAllocateAlignCommonBuffer (
1650 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1652 OUT VOID
**CmdDescHost
,
1653 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1654 OUT VOID
**CmdDescMapping
1659 BOOLEAN Is32BitAddr
;
1660 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1662 if ((Private
->Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1663 Is32BitAddr
= FALSE
;
1668 UfsHc
= Private
->UfsHostController
;
1669 Status
= UfsHc
->AllocateBuffer (
1672 EfiBootServicesData
,
1673 EFI_SIZE_TO_PAGES (Size
),
1677 if (EFI_ERROR (Status
)) {
1678 *CmdDescMapping
= NULL
;
1679 *CmdDescHost
= NULL
;
1680 *CmdDescPhyAddr
= 0;
1681 return EFI_OUT_OF_RESOURCES
;
1684 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1685 Status
= UfsHc
->Map (
1687 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1694 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1697 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1700 *CmdDescHost
= NULL
;
1701 return EFI_OUT_OF_RESOURCES
;
1704 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1706 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1714 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1717 *CmdDescMapping
= NULL
;
1718 *CmdDescHost
= NULL
;
1719 return EFI_DEVICE_ERROR
;
1722 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1727 Enable the UFS host controller for accessing.
1729 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1731 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1732 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1736 UfsEnableHostController (
1737 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1744 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1746 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1748 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
1749 if (EFI_ERROR (Status
)) {
1753 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1755 // Write a 0 to the HCE register at first to disable the host controller.
1757 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
1758 if (EFI_ERROR (Status
)) {
1762 // Wait until HCE is read as '0' before continuing.
1764 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1765 if (EFI_ERROR (Status
)) {
1766 return EFI_DEVICE_ERROR
;
1771 // Write a 1 to the HCE register to enable the UFS host controller.
1773 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
);
1774 if (EFI_ERROR (Status
)) {
1779 // Wait until HCE is read as '1' before continuing.
1781 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1782 if (EFI_ERROR (Status
)) {
1783 return EFI_DEVICE_ERROR
;
1790 Detect if a UFS device attached.
1792 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1794 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1795 @retval EFI_NOT_FOUND Not found a UFS device attached.
1796 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1800 UfsDeviceDetection (
1801 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1809 // Start UFS device detection.
1810 // Try up to 3 times for establishing data link with device.
1812 for (Retry
= 0; Retry
< 3; Retry
++) {
1813 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1814 if (EFI_ERROR (Status
)) {
1815 return EFI_DEVICE_ERROR
;
1818 Status
= UfsMmioRead32 (Private
, UFS_HC_STATUS_OFFSET
, &Data
);
1819 if (EFI_ERROR (Status
)) {
1820 return EFI_DEVICE_ERROR
;
1823 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1824 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1825 if (EFI_ERROR (Status
)) {
1826 return EFI_DEVICE_ERROR
;
1833 return EFI_NOT_FOUND
;
1837 Initialize UFS task management request list related h/w context.
1839 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1841 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1842 @retval EFI_DEVICE_ERROR The initialization fails.
1846 UfsInitTaskManagementRequestList (
1847 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1853 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1854 VOID
*CmdDescMapping
;
1858 // Initial h/w and s/w context for future operations.
1861 CmdDescMapping
= NULL
;
1864 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1865 if (EFI_ERROR (Status
)) {
1869 Private
->Capabilities
= Data
;
1872 // Allocate and initialize UTP Task Management Request List.
1874 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1875 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1876 if (EFI_ERROR (Status
)) {
1881 // Program the UTP Task Management Request List Base Address and UTP Task Management
1882 // Request List Base Address with a 64-bit address allocated at step 6.
1884 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1885 if (EFI_ERROR (Status
)) {
1889 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1890 if (EFI_ERROR (Status
)) {
1893 Private
->UtpTmrlBase
= CmdDescHost
;
1894 Private
->Nutmrs
= Nutmrs
;
1895 Private
->TmrlMapping
= CmdDescMapping
;
1898 // Enable the UTP Task Management Request List by setting the UTP Task Management
1899 // Request List RunStop Register (UTMRLRSR) to '1'.
1901 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
1902 if (EFI_ERROR (Status
)) {
1910 Initialize UFS transfer request list related h/w context.
1912 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1914 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1915 @retval EFI_DEVICE_ERROR The initialization fails.
1919 UfsInitTransferRequestList (
1920 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1926 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1927 VOID
*CmdDescMapping
;
1931 // Initial h/w and s/w context for future operations.
1934 CmdDescMapping
= NULL
;
1937 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1938 if (EFI_ERROR (Status
)) {
1942 Private
->Capabilities
= Data
;
1945 // Allocate and initialize UTP Transfer Request List.
1947 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1948 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1949 if (EFI_ERROR (Status
)) {
1954 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1955 // Base Address with a 64-bit address allocated at step 8.
1957 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1958 if (EFI_ERROR (Status
)) {
1962 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1963 if (EFI_ERROR (Status
)) {
1967 Private
->UtpTrlBase
= CmdDescHost
;
1968 Private
->Nutrs
= Nutrs
;
1969 Private
->TrlMapping
= CmdDescMapping
;
1972 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1973 // RunStop Register (UTRLRSR) to '1'.
1975 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
1976 if (EFI_ERROR (Status
)) {
1984 Initialize the UFS host controller.
1986 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1988 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1989 @retval Others A device error occurred while initializing the controller.
1994 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1999 Status
= UfsEnableHostController (Private
);
2000 if (EFI_ERROR (Status
)) {
2001 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2005 Status
= UfsDeviceDetection (Private
);
2006 if (EFI_ERROR (Status
)) {
2007 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2011 Status
= UfsInitTaskManagementRequestList (Private
);
2012 if (EFI_ERROR (Status
)) {
2013 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2017 Status
= UfsInitTransferRequestList (Private
);
2018 if (EFI_ERROR (Status
)) {
2019 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2023 DEBUG ((DEBUG_INFO
, "UfsControllerInit Finished\n"));
2028 Stop the UFS host controller.
2030 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2032 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2033 @retval Others A device error occurred while stopping the controller.
2038 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2045 // Enable the UTP Task Management Request List by setting the UTP Task Management
2046 // Request List RunStop Register (UTMRLRSR) to '1'.
2048 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2049 if (EFI_ERROR (Status
)) {
2054 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2055 // RunStop Register (UTRLRSR) to '1'.
2057 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2058 if (EFI_ERROR (Status
)) {
2063 // Write a 0 to the HCE register in order to disable the host controller.
2065 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2066 if (EFI_ERROR (Status
)) {
2069 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2071 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2072 if (EFI_ERROR (Status
)) {
2077 // Wait until HCE is read as '0' before continuing.
2079 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2080 if (EFI_ERROR (Status
)) {
2081 return EFI_DEVICE_ERROR
;
2084 DEBUG ((DEBUG_INFO
, "UfsController is stopped\n"));
2091 Internal helper function which will signal the caller event and clean up
2094 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2096 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2103 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
2104 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
2107 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
2108 EFI_EVENT CallerEvent
;
2110 ASSERT ((Private
!= NULL
) && (TransReq
!= NULL
));
2112 UfsHc
= Private
->UfsHostController
;
2113 CallerEvent
= TransReq
->CallerEvent
;
2115 RemoveEntryList (&TransReq
->TransferList
);
2117 UfsHc
->Flush (UfsHc
);
2119 UfsStopExecCmd (Private
, TransReq
->Slot
);
2121 if (TransReq
->DataBufMapping
!= NULL
) {
2122 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
2125 if (TransReq
->CmdDescMapping
!= NULL
) {
2126 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
2128 if (TransReq
->CmdDescHost
!= NULL
) {
2131 EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
),
2132 TransReq
->CmdDescHost
2136 FreePool (TransReq
);
2138 gBS
->SignalEvent (CallerEvent
);
2143 Call back function when the timer event is signaled.
2145 @param[in] Event The Event this notify function registered to.
2146 @param[in] Context Pointer to the context data registered to the Event.
2151 ProcessAsyncTaskList (
2156 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2158 LIST_ENTRY
*NextEntry
;
2159 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
2160 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
;
2161 UTP_RESPONSE_UPIU
*Response
;
2162 UINT16 SenseDataLen
;
2163 UINT32 ResTranCount
;
2168 Private
= (UFS_PASS_THRU_PRIVATE_DATA
*) Context
;
2172 // Check the entries in the async I/O queue are done or not.
2174 if (!IsListEmpty(&Private
->Queue
)) {
2175 EFI_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
2176 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
2177 Packet
= TransReq
->Packet
;
2179 if ((SlotsMap
& (BIT0
<< TransReq
->Slot
)) != 0) {
2182 SlotsMap
|= BIT0
<< TransReq
->Slot
;
2184 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Value
);
2185 if (EFI_ERROR (Status
)) {
2187 // TODO: Should find/add a proper host adapter return status for this
2190 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
2191 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq
->CallerEvent
));
2192 SignalCallerEvent (Private
, TransReq
);
2196 if ((Value
& (BIT0
<< TransReq
->Slot
)) != 0) {
2198 // Scsi cmd not finished yet.
2200 if (TransReq
->TimeoutRemain
> UFS_HC_ASYNC_TIMER
) {
2201 TransReq
->TimeoutRemain
-= UFS_HC_ASYNC_TIMER
;
2207 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
2208 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq
->CallerEvent
));
2209 SignalCallerEvent (Private
, TransReq
);
2214 // Scsi cmd finished.
2216 // Get sense data if exists
2218 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
2219 ASSERT (Response
!= NULL
);
2220 SenseDataLen
= Response
->SenseDataLen
;
2221 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
2223 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
2225 // Make sure the hardware device does not return more data than expected.
2227 if (SenseDataLen
<= Packet
->SenseDataLength
) {
2228 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
2229 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
2231 Packet
->SenseDataLength
= 0;
2236 // Check the transfer request result.
2238 Packet
->TargetStatus
= Response
->Status
;
2239 if (Response
->Response
!= 0) {
2240 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq
->CallerEvent
));
2241 SignalCallerEvent (Private
, TransReq
);
2245 if (TransReq
->Trd
->Ocs
== 0) {
2246 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2247 if ((Response
->Flags
& BIT5
) == BIT5
) {
2248 ResTranCount
= Response
->ResTranCount
;
2249 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2250 Packet
->InTransferLength
-= ResTranCount
;
2253 if ((Response
->Flags
& BIT5
) == BIT5
) {
2254 ResTranCount
= Response
->ResTranCount
;
2255 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2256 Packet
->OutTransferLength
-= ResTranCount
;
2260 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq
->CallerEvent
));
2261 SignalCallerEvent (Private
, TransReq
);
2265 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq
->CallerEvent
));
2266 SignalCallerEvent (Private
, TransReq
);