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 - 2017, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "UfsPassThru.h"
19 Read 32bits data from specified UFS MMIO register.
21 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
22 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
24 @param[out] Value The data buffer to store.
26 @retval EFI_TIMEOUT The operation is time out.
27 @retval EFI_SUCCESS The operation succeeds.
28 @retval Others The operation fails.
33 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
38 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
41 UfsHc
= Private
->UfsHostController
;
43 Status
= UfsHc
->Read (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, Value
);
49 Write 32bits data to specified UFS MMIO register.
51 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
52 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
54 @param[in] Value The data to write.
56 @retval EFI_TIMEOUT The operation is time out.
57 @retval EFI_SUCCESS The operation succeeds.
58 @retval Others The operation fails.
63 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
68 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
71 UfsHc
= Private
->UfsHostController
;
73 Status
= UfsHc
->Write (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, &Value
);
79 Wait for the value of the specified system memory set to the test value.
81 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
82 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
84 @param[in] MaskValue The mask value of memory.
85 @param[in] TestValue The test value of memory.
86 @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.
88 @retval EFI_TIMEOUT The system memory setting is time out.
89 @retval EFI_SUCCESS The system memory is correct set.
90 @retval Others The operation fails.
95 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
104 BOOLEAN InfiniteWait
;
110 InfiniteWait
= FALSE
;
113 Delay
= DivU64x32 (Timeout
, 10) + 1;
117 // Access PCI MMIO space to see if the value is the tested one.
119 Status
= UfsMmioRead32 (Private
, Offset
, &Value
);
120 if (EFI_ERROR (Status
)) {
126 if (Value
== TestValue
) {
131 // Stall for 1 microseconds.
133 MicroSecondDelay (1);
137 } while (InfiniteWait
|| (Delay
> 0));
143 Dump UIC command execution result for debugging.
145 @param[in] UicOpcode The executed UIC opcode.
146 @param[in] Result The result to be parsed.
150 DumpUicCmdExecResult (
155 if (UicOpcode
<= UfsUicDmePeerSet
) {
160 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
163 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
166 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
169 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
172 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BAD_INDEX\n"));
175 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
178 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
181 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
184 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BUSY\n"));
187 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - DME_FAILURE\n"));
198 DEBUG ((DEBUG_VERBOSE
, "UIC control command fails - FAILURE\n"));
208 Dump QUERY RESPONSE UPIU result for debugging.
210 @param[in] Result The result to be parsed.
214 DumpQueryResponseResult (
220 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Not Readable\n"));
223 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Not Writeable\n"));
226 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Already Written\n"));
229 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Length\n"));
232 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Value\n"));
235 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Selector\n"));
238 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Index\n"));
241 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Idn\n"));
244 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Opcode\n"));
247 DEBUG ((DEBUG_VERBOSE
, "Query Response with General Failure\n"));
256 Swap little endian to big endian.
258 @param[in, out] Buffer The data buffer. In input, it contains little endian data.
259 In output, it will become big endian.
260 @param[in] BufferSize The length of converted data.
264 SwapLittleEndianToBigEndian (
265 IN OUT UINT8
*Buffer
,
273 SwapCount
= BufferSize
/ 2;
274 for (Index
= 0; Index
< SwapCount
; Index
++) {
275 Temp
= Buffer
[Index
];
276 Buffer
[Index
] = Buffer
[BufferSize
- 1 - Index
];
277 Buffer
[BufferSize
- 1 - Index
] = Temp
;
282 Fill TSF field of QUERY REQUEST UPIU.
284 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
285 @param[in] Opcode The opcode of request.
286 @param[in] DescId The descriptor ID of request.
287 @param[in] Index The index of request.
288 @param[in] Selector The selector of request.
289 @param[in] Length The length of transferred data. The maximum is 4.
290 @param[in] Value The value of transferred data.
294 UfsFillTsfOfQueryReqUpiu (
295 IN OUT UTP_UPIU_TSF
*TsfBase
,
297 IN UINT8 DescId OPTIONAL
,
298 IN UINT8 Index OPTIONAL
,
299 IN UINT8 Selector OPTIONAL
,
300 IN UINT16 Length OPTIONAL
,
301 IN UINT32 Value OPTIONAL
304 ASSERT (TsfBase
!= NULL
);
305 ASSERT (Opcode
<= UtpQueryFuncOpcodeTogFlag
);
307 TsfBase
->Opcode
= Opcode
;
308 if (Opcode
!= UtpQueryFuncOpcodeNop
) {
309 TsfBase
->DescId
= DescId
;
310 TsfBase
->Index
= Index
;
311 TsfBase
->Selector
= Selector
;
313 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
314 SwapLittleEndianToBigEndian ((UINT8
*)&Length
, sizeof (Length
));
315 TsfBase
->Length
= Length
;
318 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
319 SwapLittleEndianToBigEndian ((UINT8
*)&Value
, sizeof (Value
));
320 TsfBase
->Value
= Value
;
326 Initialize COMMAND UPIU.
328 @param[in, out] Command The base address of COMMAND UPIU.
329 @param[in] Lun The Lun on which the SCSI command is executed.
330 @param[in] TaskTag The task tag of request.
331 @param[in] Cdb The cdb buffer containing SCSI command.
332 @param[in] CdbLength The cdb length.
333 @param[in] DataDirection The direction of data transfer.
334 @param[in] ExpDataTranLen The expected transfer data length.
336 @retval EFI_SUCCESS The initialization succeed.
341 IN OUT UTP_COMMAND_UPIU
*Command
,
346 IN UFS_DATA_DIRECTION DataDirection
,
347 IN UINT32 ExpDataTranLen
352 ASSERT ((Command
!= NULL
) && (Cdb
!= NULL
));
355 // Task attribute is hard-coded to Ordered.
357 if (DataDirection
== UfsDataIn
) {
359 } else if (DataDirection
== UfsDataOut
) {
366 // Fill UTP COMMAND UPIU associated fields.
368 Command
->TransCode
= 0x01;
369 Command
->Flags
= Flags
;
371 Command
->TaskTag
= TaskTag
;
372 Command
->CmdSet
= 0x00;
373 SwapLittleEndianToBigEndian ((UINT8
*)&ExpDataTranLen
, sizeof (ExpDataTranLen
));
374 Command
->ExpDataTranLen
= ExpDataTranLen
;
376 CopyMem (Command
->Cdb
, Cdb
, CdbLength
);
382 Initialize UTP PRDT for data transfer.
384 @param[in] Prdt The base address of PRDT.
385 @param[in] Buffer The buffer to be read or written.
386 @param[in] BufferSize The data size to be read or written.
388 @retval EFI_SUCCESS The initialization succeed.
403 if ((BufferSize
& (BIT0
| BIT1
)) != 0) {
404 BufferSize
&= ~(BIT0
| BIT1
);
405 DEBUG ((DEBUG_WARN
, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize
));
408 if (BufferSize
== 0) {
412 ASSERT (((UINTN
)Buffer
& (BIT0
| BIT1
)) == 0);
414 RemainingLen
= BufferSize
;
416 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)BufferSize
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
418 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
419 if (RemainingLen
< UFS_MAX_DATA_LEN_PER_PRD
) {
420 Prdt
[PrdtIndex
].DbCount
= (UINT32
)RemainingLen
- 1;
422 Prdt
[PrdtIndex
].DbCount
= UFS_MAX_DATA_LEN_PER_PRD
- 1;
425 Prdt
[PrdtIndex
].DbAddr
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 2);
426 Prdt
[PrdtIndex
].DbAddrU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 32);
427 RemainingLen
-= UFS_MAX_DATA_LEN_PER_PRD
;
428 Remaining
+= UFS_MAX_DATA_LEN_PER_PRD
;
435 Initialize QUERY REQUEST UPIU.
437 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
438 @param[in] TaskTag The task tag of request.
439 @param[in] Opcode The opcode of request.
440 @param[in] DescId The descriptor ID of request.
441 @param[in] Index The index of request.
442 @param[in] Selector The selector of request.
443 @param[in] DataSize The data size to be read or written.
444 @param[in] Data The buffer to be read or written.
446 @retval EFI_SUCCESS The initialization succeed.
450 UfsInitQueryRequestUpiu (
451 IN OUT UTP_QUERY_REQ_UPIU
*QueryReq
,
457 IN UINTN DataSize OPTIONAL
,
458 IN UINT8
*Data OPTIONAL
461 ASSERT (QueryReq
!= NULL
);
463 QueryReq
->TransCode
= 0x16;
464 QueryReq
->TaskTag
= TaskTag
;
465 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeRdFlag
) || (Opcode
== UtpQueryFuncOpcodeRdAttr
)) {
466 QueryReq
->QueryFunc
= QUERY_FUNC_STD_READ_REQ
;
468 QueryReq
->QueryFunc
= QUERY_FUNC_STD_WRITE_REQ
;
471 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
472 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, *(UINT32
*)Data
);
473 } else if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
474 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, (UINT16
)DataSize
, 0);
476 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, 0);
479 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
480 CopyMem (QueryReq
+ 1, Data
, DataSize
);
482 SwapLittleEndianToBigEndian ((UINT8
*)&DataSize
, sizeof (UINT16
));
483 QueryReq
->DataSegLen
= (UINT16
)DataSize
;
490 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
492 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
493 @param[in] Lun The Lun on which the SCSI command is executed.
494 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
495 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
496 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
497 @param[out] CmdDescMapping A resulting value to pass to Unmap().
499 @retval EFI_SUCCESS The creation succeed.
500 @retval EFI_DEVICE_ERROR The creation failed.
501 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
505 UfsCreateScsiCommandDesc (
506 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
508 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
510 OUT VOID
**CmdDescHost
,
511 OUT VOID
**CmdDescMapping
516 UTP_COMMAND_UPIU
*CommandUpiu
;
517 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
520 UFS_DATA_DIRECTION DataDirection
;
522 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
524 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
525 DataLen
= Packet
->InTransferLength
;
526 DataDirection
= UfsDataIn
;
528 DataLen
= Packet
->OutTransferLength
;
529 DataDirection
= UfsDataOut
;
533 DataDirection
= UfsNoData
;
536 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)DataLen
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
538 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
540 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
541 if (EFI_ERROR (Status
)) {
545 CommandUpiu
= (UTP_COMMAND_UPIU
*)*CmdDescHost
;
547 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, DataLen
);
550 // Fill UTP_TRD associated fields
551 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
552 // *MUST* be located at a 64-bit aligned boundary.
554 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
555 Trd
->Dd
= DataDirection
;
556 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
557 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
558 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
559 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
560 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
561 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
562 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
563 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
568 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
570 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
571 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
572 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
573 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
574 @param[out] CmdDescMapping A resulting value to pass to Unmap().
576 @retval EFI_SUCCESS The creation succeed.
577 @retval EFI_DEVICE_ERROR The creation failed.
578 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
579 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
583 UfsCreateDMCommandDesc (
584 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
585 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
587 OUT VOID
**CmdDescHost
,
588 OUT VOID
**CmdDescMapping
592 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
597 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
600 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
602 Opcode
= Packet
->Opcode
;
603 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
604 return EFI_INVALID_PARAMETER
;
607 DataDirection
= Packet
->DataDirection
;
608 DataSize
= Packet
->TransferLength
;
609 Data
= Packet
->DataBuffer
;
611 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
612 if (DataSize
== 0 || Data
== NULL
) {
613 return EFI_INVALID_PARAMETER
;
615 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
617 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
620 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
621 if (EFI_ERROR (Status
)) {
626 // Initialize UTP QUERY REQUEST UPIU
628 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)*CmdDescHost
;
629 ASSERT (QueryReqUpiu
!= NULL
);
630 UfsInitQueryRequestUpiu (
642 // Fill UTP_TRD associated fields
643 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
645 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
646 Trd
->Dd
= DataDirection
;
647 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
648 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
649 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
650 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
651 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
652 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
653 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
655 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
656 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
663 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
665 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
666 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
667 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
668 @param[out] CmdDescMapping A resulting value to pass to Unmap().
670 @retval EFI_SUCCESS The creation succeed.
671 @retval EFI_DEVICE_ERROR The creation failed.
672 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
676 UfsCreateNopCommandDesc (
677 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
679 OUT VOID
**CmdDescHost
,
680 OUT VOID
**CmdDescMapping
684 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
686 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
688 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
690 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
691 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
692 if (EFI_ERROR (Status
)) {
696 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)*CmdDescHost
;
697 ASSERT (NopOutUpiu
!= NULL
);
698 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
701 // Fill UTP_TRD associated fields
702 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
704 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
706 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
707 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
708 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
709 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
710 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
711 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
717 Find out available slot in transfer list of a UFS device.
719 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
720 @param[out] Slot The available slot.
722 @retval EFI_SUCCESS The available slot was found successfully.
723 @retval EFI_NOT_READY No slot is available at this moment.
727 UfsFindAvailableSlotInTrl (
728 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
737 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
739 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
740 if (EFI_ERROR (Status
)) {
744 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
746 for (Index
= 0; Index
< Nutrs
; Index
++) {
747 if ((Data
& (BIT0
<< Index
)) == 0) {
753 return EFI_NOT_READY
;
757 Find out available slot in task management transfer list of a UFS device.
759 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
760 @param[out] Slot The available slot.
762 @retval EFI_SUCCESS The available slot was found successfully.
766 UfsFindAvailableSlotInTmrl (
767 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
771 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
774 // The simplest algo to always use slot 0.
775 // TODO: enhance it to support async transfer with multiple slot.
783 Start specified slot in transfer list of a UFS device.
785 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
786 @param[in] Slot The slot to be started.
791 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
798 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLRSR_OFFSET
, &Data
);
799 if (EFI_ERROR (Status
)) {
803 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
804 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
805 if (EFI_ERROR (Status
)) {
810 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
);
811 if (EFI_ERROR (Status
)) {
819 Stop specified slot in transfer list of a UFS device.
821 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
822 @param[in] Slot The slot to be stop.
827 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
834 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
835 if (EFI_ERROR (Status
)) {
839 if ((Data
& (BIT0
<< Slot
)) != 0) {
840 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLCLR_OFFSET
, &Data
);
841 if (EFI_ERROR (Status
)) {
845 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLCLR_OFFSET
, Data
& ~(BIT0
<< Slot
));
846 if (EFI_ERROR (Status
)) {
855 Extracts return data from query response upiu.
857 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
858 @param[in] QueryResp Pointer to the query response.
860 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.
861 @retval EFI_SUCCESS Data extracted.
865 UfsGetReturnDataFromQueryResponse (
866 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
867 IN UTP_QUERY_RESP_UPIU
*QueryResp
870 UINT16 ReturnDataSize
;
873 if (Packet
== NULL
|| QueryResp
== NULL
) {
874 return EFI_INVALID_PARAMETER
;
877 switch (Packet
->Opcode
) {
878 case UtpQueryFuncOpcodeRdDesc
:
879 ReturnDataSize
= QueryResp
->Tsf
.Length
;
880 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
881 CopyMem (Packet
->DataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
882 Packet
->TransferLength
= ReturnDataSize
;
884 case UtpQueryFuncOpcodeWrDesc
:
885 ReturnDataSize
= QueryResp
->Tsf
.Length
;
886 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
887 Packet
->TransferLength
= ReturnDataSize
;
889 case UtpQueryFuncOpcodeRdFlag
:
890 case UtpQueryFuncOpcodeSetFlag
:
891 case UtpQueryFuncOpcodeClrFlag
:
892 case UtpQueryFuncOpcodeTogFlag
:
893 CopyMem (Packet
->DataBuffer
, &QueryResp
->Tsf
.Value
, sizeof (UINT8
));
895 case UtpQueryFuncOpcodeRdAttr
:
896 case UtpQueryFuncOpcodeWrAttr
:
897 ReturnData
= QueryResp
->Tsf
.Value
;
898 SwapLittleEndianToBigEndian ((UINT8
*) &ReturnData
, sizeof (UINT32
));
899 CopyMem (Packet
->DataBuffer
, &ReturnData
, sizeof (UINT32
));
902 return EFI_INVALID_PARAMETER
;
909 Creates Transfer Request descriptor and sends Query Request to the device.
911 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
912 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
914 @retval EFI_SUCCESS The device descriptor was read/written successfully.
915 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
916 combination to point to a type of UFS device descriptor.
917 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
918 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
922 UfsSendDmRequestRetry (
923 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
924 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
930 VOID
*CmdDescMapping
;
932 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
933 UTP_QUERY_RESP_UPIU
*QueryResp
;
937 // Find out which slot of transfer request list is available.
939 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
940 if (EFI_ERROR (Status
)) {
944 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
946 // Fill transfer request descriptor to this slot.
948 Status
= UfsCreateDMCommandDesc (Private
, Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
949 if (EFI_ERROR (Status
)) {
950 DEBUG ((DEBUG_ERROR
, "Failed to create DM command descriptor\n"));
954 UfsHc
= Private
->UfsHostController
;
955 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
956 ASSERT (QueryResp
!= NULL
);
957 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
960 // Start to execute the transfer request.
962 UfsStartExecCmd (Private
, Slot
);
965 // Wait for the completion of the transfer request.
967 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
, 0, Packet
->Timeout
);
968 if (EFI_ERROR (Status
)) {
972 if (Trd
->Ocs
!= 0 || QueryResp
->QueryResp
!= UfsUtpQueryResponseSuccess
) {
973 DEBUG ((DEBUG_ERROR
, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd
->Ocs
, QueryResp
->QueryResp
));
974 DumpQueryResponseResult (QueryResp
->QueryResp
);
976 if ((QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidSelector
) ||
977 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIndex
) ||
978 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIdn
)) {
979 Status
= EFI_INVALID_PARAMETER
;
981 Status
= EFI_DEVICE_ERROR
;
986 Status
= UfsGetReturnDataFromQueryResponse (Packet
, QueryResp
);
987 if (EFI_ERROR (Status
)) {
988 DEBUG ((DEBUG_ERROR
, "Failed to get return data from query response\n"));
993 UfsHc
->Flush (UfsHc
);
995 UfsStopExecCmd (Private
, Slot
);
997 if (CmdDescMapping
!= NULL
) {
998 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1000 if (CmdDescHost
!= NULL
) {
1001 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1008 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
1010 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
1011 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.
1013 @retval EFI_SUCCESS The device responded correctly to the Query request.
1014 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
1015 combination to point to a type of UFS device descriptor.
1016 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
1017 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
1022 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1023 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
1029 Status
= EFI_SUCCESS
;
1031 for (Retry
= 0; Retry
< 5; Retry
++) {
1032 Status
= UfsSendDmRequestRetry (Private
, Packet
);
1033 if (!EFI_ERROR (Status
)) {
1038 DEBUG ((DEBUG_ERROR
, "Failed to get response from the device after %d retries\n", Retry
));
1043 Read or write specified device descriptor of a UFS device.
1045 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1046 @param[in] Read The boolean variable to show r/w direction.
1047 @param[in] DescId The ID of device descriptor.
1048 @param[in] Index The Index of device descriptor.
1049 @param[in] Selector The Selector of device descriptor.
1050 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
1051 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
1052 of the data buffer specified by Descriptor. On output, the number
1053 of bytes that were actually transferred.
1055 @retval EFI_SUCCESS The device descriptor was read/written successfully.
1056 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a
1057 type of UFS device descriptor.
1058 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
1059 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
1064 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1069 IN OUT VOID
*Descriptor
,
1070 IN OUT UINT32
*DescSize
1073 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1076 if (DescSize
== NULL
) {
1077 return EFI_INVALID_PARAMETER
;
1080 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1083 Packet
.DataDirection
= UfsDataIn
;
1084 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
1086 Packet
.DataDirection
= UfsDataOut
;
1087 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
1089 Packet
.DataBuffer
= Descriptor
;
1090 Packet
.TransferLength
= *DescSize
;
1091 Packet
.DescId
= DescId
;
1092 Packet
.Index
= Index
;
1093 Packet
.Selector
= Selector
;
1094 Packet
.Timeout
= UFS_TIMEOUT
;
1096 Status
= UfsSendDmRequest (Private
, &Packet
);
1097 if (EFI_ERROR (Status
)) {
1100 *DescSize
= Packet
.TransferLength
;
1107 Read or write specified attribute of a UFS device.
1109 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1110 @param[in] Read The boolean variable to show r/w direction.
1111 @param[in] AttrId The ID of Attribute.
1112 @param[in] Index The Index of Attribute.
1113 @param[in] Selector The Selector of Attribute.
1114 @param[in, out] Attributes The value of Attribute to be read or written.
1116 @retval EFI_SUCCESS The Attribute was read/written successfully.
1117 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a
1118 type of UFS device descriptor.
1119 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
1120 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
1125 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1130 IN OUT UINT32
*Attributes
1133 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1135 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1138 Packet
.DataDirection
= UfsDataIn
;
1139 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
1141 Packet
.DataDirection
= UfsDataOut
;
1142 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
1144 Packet
.DataBuffer
= Attributes
;
1145 Packet
.DescId
= AttrId
;
1146 Packet
.Index
= Index
;
1147 Packet
.Selector
= Selector
;
1148 Packet
.Timeout
= UFS_TIMEOUT
;
1150 return UfsSendDmRequest (Private
, &Packet
);
1154 Read or write specified flag of a UFS device.
1156 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1157 @param[in] Read The boolean variable to show r/w direction.
1158 @param[in] FlagId The ID of flag to be read or written.
1159 @param[in, out] Value The value to set or clear flag.
1161 @retval EFI_SUCCESS The flag was read/written successfully.
1162 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.
1163 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1164 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1169 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1175 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1177 if (Value
== NULL
) {
1178 return EFI_INVALID_PARAMETER
;
1181 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1184 ASSERT (Value
!= NULL
);
1185 Packet
.DataDirection
= UfsDataIn
;
1186 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1188 Packet
.DataDirection
= UfsDataOut
;
1190 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1191 } else if (*Value
== 0) {
1192 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1194 return EFI_INVALID_PARAMETER
;
1197 Packet
.DataBuffer
= Value
;
1198 Packet
.DescId
= FlagId
;
1200 Packet
.Selector
= 0;
1201 Packet
.Timeout
= UFS_TIMEOUT
;
1203 return UfsSendDmRequest (Private
, &Packet
);
1207 Set specified flag to 1 on a UFS device.
1209 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1210 @param[in] FlagId The ID of flag to be set.
1212 @retval EFI_SUCCESS The flag was set successfully.
1213 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1214 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1219 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1227 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1233 Clear specified flag to 0 on a UFS device.
1235 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1236 @param[in] FlagId The ID of flag to be cleared.
1238 @retval EFI_SUCCESS The flag was cleared successfully.
1239 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1240 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1245 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1253 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1259 Read specified flag from a UFS device.
1261 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1262 @param[in] FlagId The ID of flag to be read.
1263 @param[out] Value The flag's value.
1265 @retval EFI_SUCCESS The flag was read successfully.
1266 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1267 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1272 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1279 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1285 Sends NOP IN cmd to a UFS device for initialization process request.
1286 For more details, please refer to UFS 2.0 spec Figure 13.3.
1288 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1290 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1291 received successfully.
1292 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1293 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1294 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1299 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1305 UTP_NOP_IN_UPIU
*NopInUpiu
;
1308 VOID
*CmdDescMapping
;
1309 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1312 // Find out which slot of transfer request list is available.
1314 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1315 if (EFI_ERROR (Status
)) {
1319 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1320 Status
= UfsCreateNopCommandDesc (Private
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1321 if (EFI_ERROR (Status
)) {
1326 // Check the transfer request result.
1328 UfsHc
= Private
->UfsHostController
;
1329 NopInUpiu
= (UTP_NOP_IN_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1330 ASSERT (NopInUpiu
!= NULL
);
1331 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1334 // Start to execute the transfer request.
1336 UfsStartExecCmd (Private
, Slot
);
1339 // Wait for the completion of the transfer request.
1341 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1342 if (EFI_ERROR (Status
)) {
1346 if (NopInUpiu
->Resp
!= 0) {
1347 Status
= EFI_DEVICE_ERROR
;
1349 Status
= EFI_SUCCESS
;
1353 UfsHc
->Flush (UfsHc
);
1355 UfsStopExecCmd (Private
, Slot
);
1357 if (CmdDescMapping
!= NULL
) {
1358 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1360 if (CmdDescHost
!= NULL
) {
1361 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1368 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1370 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1371 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1372 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1374 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1375 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1376 Event is not NULL and non blocking I/O is supported, then
1377 nonblocking I/O is performed, and Event will be signaled when the
1378 SCSI Request Packet completes.
1380 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1381 commands, InTransferLength bytes were transferred from
1382 InDataBuffer. For write and bi-directional commands,
1383 OutTransferLength bytes were transferred by
1385 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1387 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1388 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1393 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1395 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
1396 IN EFI_EVENT Event OPTIONAL
1400 UTP_RESPONSE_UPIU
*Response
;
1401 UINT16 SenseDataLen
;
1402 UINT32 ResTranCount
;
1404 EFI_PHYSICAL_ADDRESS DataBufPhyAddr
;
1407 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1408 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag
;
1409 UTP_TR_PRD
*PrdtBase
;
1411 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
1413 TransReq
= AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ
));
1414 if (TransReq
== NULL
) {
1415 return EFI_OUT_OF_RESOURCES
;
1418 TransReq
->Signature
= UFS_PASS_THRU_TRANS_REQ_SIG
;
1419 TransReq
->TimeoutRemain
= Packet
->Timeout
;
1421 UfsHc
= Private
->UfsHostController
;
1423 // Find out which slot of transfer request list is available.
1425 Status
= UfsFindAvailableSlotInTrl (Private
, &TransReq
->Slot
);
1426 if (EFI_ERROR (Status
)) {
1430 TransReq
->Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + TransReq
->Slot
;
1433 // Fill transfer request descriptor to this slot.
1435 Status
= UfsCreateScsiCommandDesc (
1440 &TransReq
->CmdDescHost
,
1441 &TransReq
->CmdDescMapping
1443 if (EFI_ERROR (Status
)) {
1447 TransReq
->CmdDescSize
= TransReq
->Trd
->PrdtO
* sizeof (UINT32
) + TransReq
->Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1449 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1450 DataBuf
= Packet
->InDataBuffer
;
1451 DataLen
= Packet
->InTransferLength
;
1452 Flag
= EdkiiUfsHcOperationBusMasterWrite
;
1454 DataBuf
= Packet
->OutDataBuffer
;
1455 DataLen
= Packet
->OutTransferLength
;
1456 Flag
= EdkiiUfsHcOperationBusMasterRead
;
1460 MapLength
= DataLen
;
1461 Status
= UfsHc
->Map (
1467 &TransReq
->DataBufMapping
1470 if (EFI_ERROR (Status
) || (DataLen
!= MapLength
)) {
1475 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1477 PrdtBase
= (UTP_TR_PRD
*)((UINT8
*)TransReq
->CmdDescHost
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
1478 ASSERT (PrdtBase
!= NULL
);
1479 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)DataBufPhyAddr
, DataLen
);
1482 // Insert the async SCSI cmd to the Async I/O list
1484 if (Event
!= NULL
) {
1485 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1486 TransReq
->Packet
= Packet
;
1487 TransReq
->CallerEvent
= Event
;
1488 InsertTailList (&Private
->Queue
, &TransReq
->TransferList
);
1489 gBS
->RestoreTPL (OldTpl
);
1493 // Start to execute the transfer request.
1495 UfsStartExecCmd (Private
, TransReq
->Slot
);
1498 // Immediately return for async I/O.
1500 if (Event
!= NULL
) {
1505 // Wait for the completion of the transfer request.
1507 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< TransReq
->Slot
, 0, Packet
->Timeout
);
1508 if (EFI_ERROR (Status
)) {
1513 // Get sense data if exists
1515 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
1516 ASSERT (Response
!= NULL
);
1517 SenseDataLen
= Response
->SenseDataLen
;
1518 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1520 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1521 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1522 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1526 // Check the transfer request result.
1528 Packet
->TargetStatus
= Response
->Status
;
1529 if (Response
->Response
!= 0) {
1530 DEBUG ((DEBUG_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1531 Status
= EFI_DEVICE_ERROR
;
1535 if (TransReq
->Trd
->Ocs
== 0) {
1536 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1537 if ((Response
->Flags
& BIT5
) == BIT5
) {
1538 ResTranCount
= Response
->ResTranCount
;
1539 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1540 Packet
->InTransferLength
-= ResTranCount
;
1543 if ((Response
->Flags
& BIT5
) == BIT5
) {
1544 ResTranCount
= Response
->ResTranCount
;
1545 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1546 Packet
->OutTransferLength
-= ResTranCount
;
1550 Status
= EFI_DEVICE_ERROR
;
1554 UfsHc
->Flush (UfsHc
);
1556 UfsStopExecCmd (Private
, TransReq
->Slot
);
1558 if (TransReq
->DataBufMapping
!= NULL
) {
1559 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
1563 if (TransReq
->CmdDescMapping
!= NULL
) {
1564 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
1566 if (TransReq
->CmdDescHost
!= NULL
) {
1567 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
), TransReq
->CmdDescHost
);
1569 if (TransReq
!= NULL
) {
1570 FreePool (TransReq
);
1577 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1579 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1580 @param[in] UicOpcode The opcode of the UIC command.
1581 @param[in] Arg1 The value for 1st argument of the UIC command.
1582 @param[in] Arg2 The value for 2nd argument of the UIC command.
1583 @param[in] Arg3 The value for 3rd argument of the UIC command.
1585 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1586 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1587 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1591 UfsExecUicCommands (
1592 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1602 Status
= UfsMmioRead32 (Private
, UFS_HC_IS_OFFSET
, &Data
);
1603 if (EFI_ERROR (Status
)) {
1607 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1609 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1611 Status
= UfsMmioWrite32 (Private
, UFS_HC_IS_OFFSET
, Data
);
1612 if (EFI_ERROR (Status
)) {
1618 // When programming UIC command registers, host software shall set the register UICCMD
1619 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1622 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG1_OFFSET
, Arg1
);
1623 if (EFI_ERROR (Status
)) {
1627 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, Arg2
);
1628 if (EFI_ERROR (Status
)) {
1632 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, Arg3
);
1633 if (EFI_ERROR (Status
)) {
1638 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1640 Status
= UfsWaitMemSet (Private
, UFS_HC_STATUS_OFFSET
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1641 if (EFI_ERROR (Status
)) {
1645 Status
= UfsMmioWrite32 (Private
, UFS_HC_UIC_CMD_OFFSET
, (UINT32
)UicOpcode
);
1646 if (EFI_ERROR (Status
)) {
1651 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1652 // This bit is set to '1' by the host controller upon completion of a UIC command.
1654 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1655 if (EFI_ERROR (Status
)) {
1659 if (UicOpcode
!= UfsUicDmeReset
) {
1660 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, &Data
);
1661 if (EFI_ERROR (Status
)) {
1664 if ((Data
& 0xFF) != 0) {
1666 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1668 return EFI_DEVICE_ERROR
;
1673 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1675 Status
= UfsMmioRead32 (Private
, UFS_HC_STATUS_OFFSET
, &Data
);
1676 if (EFI_ERROR (Status
)) {
1680 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1681 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1682 if (EFI_ERROR (Status
)) {
1683 return EFI_DEVICE_ERROR
;
1685 return EFI_NOT_FOUND
;
1688 DEBUG ((DEBUG_INFO
, "UfsPassThruDxe: found a attached UFS device\n"));
1694 Allocate common buffer for host and UFS bus master access simultaneously.
1696 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1697 @param[in] Size The length of buffer to be allocated.
1698 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1699 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1700 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1702 @retval EFI_SUCCESS The common buffer was allocated successfully.
1703 @retval EFI_DEVICE_ERROR The allocation fails.
1704 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1708 UfsAllocateAlignCommonBuffer (
1709 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1711 OUT VOID
**CmdDescHost
,
1712 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1713 OUT VOID
**CmdDescMapping
1718 BOOLEAN Is32BitAddr
;
1719 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1721 if ((Private
->Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1722 Is32BitAddr
= FALSE
;
1727 UfsHc
= Private
->UfsHostController
;
1728 Status
= UfsHc
->AllocateBuffer (
1731 EfiBootServicesData
,
1732 EFI_SIZE_TO_PAGES (Size
),
1736 if (EFI_ERROR (Status
)) {
1737 *CmdDescMapping
= NULL
;
1738 *CmdDescHost
= NULL
;
1739 *CmdDescPhyAddr
= 0;
1740 return EFI_OUT_OF_RESOURCES
;
1743 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1744 Status
= UfsHc
->Map (
1746 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1753 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1756 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1759 *CmdDescHost
= NULL
;
1760 return EFI_OUT_OF_RESOURCES
;
1763 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1765 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1773 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1776 *CmdDescMapping
= NULL
;
1777 *CmdDescHost
= NULL
;
1778 return EFI_DEVICE_ERROR
;
1781 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1786 Enable the UFS host controller for accessing.
1788 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1790 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1791 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1795 UfsEnableHostController (
1796 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1803 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1805 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1807 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
1808 if (EFI_ERROR (Status
)) {
1812 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1814 // Write a 0 to the HCE register at first to disable the host controller.
1816 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
1817 if (EFI_ERROR (Status
)) {
1821 // Wait until HCE is read as '0' before continuing.
1823 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1824 if (EFI_ERROR (Status
)) {
1825 return EFI_DEVICE_ERROR
;
1830 // Write a 1 to the HCE register to enable the UFS host controller.
1832 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
);
1833 if (EFI_ERROR (Status
)) {
1838 // Wait until HCE is read as '1' before continuing.
1840 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1841 if (EFI_ERROR (Status
)) {
1842 return EFI_DEVICE_ERROR
;
1849 Detect if a UFS device attached.
1851 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1853 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1854 @retval EFI_NOT_FOUND Not found a UFS device attached.
1855 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1859 UfsDeviceDetection (
1860 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1867 // Start UFS device detection.
1868 // Try up to 3 times for establishing data link with device.
1870 for (Retry
= 0; Retry
< 3; Retry
++) {
1871 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1872 if (!EFI_ERROR (Status
)) {
1876 if (Status
== EFI_NOT_FOUND
) {
1880 return EFI_DEVICE_ERROR
;
1884 return EFI_NOT_FOUND
;
1891 Initialize UFS task management request list related h/w context.
1893 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1895 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1896 @retval EFI_DEVICE_ERROR The initialization fails.
1900 UfsInitTaskManagementRequestList (
1901 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1907 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1908 VOID
*CmdDescMapping
;
1912 // Initial h/w and s/w context for future operations.
1915 CmdDescMapping
= NULL
;
1918 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1919 if (EFI_ERROR (Status
)) {
1923 Private
->Capabilities
= Data
;
1926 // Allocate and initialize UTP Task Management Request List.
1928 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1929 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1930 if (EFI_ERROR (Status
)) {
1935 // Program the UTP Task Management Request List Base Address and UTP Task Management
1936 // Request List Base Address with a 64-bit address allocated at step 6.
1938 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1939 if (EFI_ERROR (Status
)) {
1943 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1944 if (EFI_ERROR (Status
)) {
1947 Private
->UtpTmrlBase
= CmdDescHost
;
1948 Private
->Nutmrs
= Nutmrs
;
1949 Private
->TmrlMapping
= CmdDescMapping
;
1952 // Enable the UTP Task Management Request List by setting the UTP Task Management
1953 // Request List RunStop Register (UTMRLRSR) to '1'.
1955 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
1956 if (EFI_ERROR (Status
)) {
1964 Initialize UFS transfer request list related h/w context.
1966 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1968 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1969 @retval EFI_DEVICE_ERROR The initialization fails.
1973 UfsInitTransferRequestList (
1974 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1980 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1981 VOID
*CmdDescMapping
;
1985 // Initial h/w and s/w context for future operations.
1988 CmdDescMapping
= NULL
;
1991 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1992 if (EFI_ERROR (Status
)) {
1996 Private
->Capabilities
= Data
;
1999 // Allocate and initialize UTP Transfer Request List.
2001 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
2002 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
2003 if (EFI_ERROR (Status
)) {
2008 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
2009 // Base Address with a 64-bit address allocated at step 8.
2011 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
2012 if (EFI_ERROR (Status
)) {
2016 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
2017 if (EFI_ERROR (Status
)) {
2021 Private
->UtpTrlBase
= CmdDescHost
;
2022 Private
->Nutrs
= Nutrs
;
2023 Private
->TrlMapping
= CmdDescMapping
;
2026 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2027 // RunStop Register (UTRLRSR) to '1'.
2029 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
2030 if (EFI_ERROR (Status
)) {
2038 Initialize the UFS host controller.
2040 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2042 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2043 @retval Others A device error occurred while initializing the controller.
2048 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2053 Status
= UfsEnableHostController (Private
);
2054 if (EFI_ERROR (Status
)) {
2055 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2059 Status
= UfsDeviceDetection (Private
);
2060 if (EFI_ERROR (Status
)) {
2061 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2065 Status
= UfsInitTaskManagementRequestList (Private
);
2066 if (EFI_ERROR (Status
)) {
2067 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2071 Status
= UfsInitTransferRequestList (Private
);
2072 if (EFI_ERROR (Status
)) {
2073 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2077 DEBUG ((DEBUG_INFO
, "UfsControllerInit Finished\n"));
2082 Stop the UFS host controller.
2084 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2086 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2087 @retval Others A device error occurred while stopping the controller.
2092 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2099 // Enable the UTP Task Management Request List by setting the UTP Task Management
2100 // Request List RunStop Register (UTMRLRSR) to '1'.
2102 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2103 if (EFI_ERROR (Status
)) {
2108 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2109 // RunStop Register (UTRLRSR) to '1'.
2111 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2112 if (EFI_ERROR (Status
)) {
2117 // Write a 0 to the HCE register in order to disable the host controller.
2119 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2120 if (EFI_ERROR (Status
)) {
2123 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2125 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2126 if (EFI_ERROR (Status
)) {
2131 // Wait until HCE is read as '0' before continuing.
2133 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2134 if (EFI_ERROR (Status
)) {
2135 return EFI_DEVICE_ERROR
;
2138 DEBUG ((DEBUG_INFO
, "UfsController is stopped\n"));
2145 Internal helper function which will signal the caller event and clean up
2148 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2150 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2157 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
2158 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
2161 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
2162 EFI_EVENT CallerEvent
;
2164 ASSERT ((Private
!= NULL
) && (TransReq
!= NULL
));
2166 UfsHc
= Private
->UfsHostController
;
2167 CallerEvent
= TransReq
->CallerEvent
;
2169 RemoveEntryList (&TransReq
->TransferList
);
2171 UfsHc
->Flush (UfsHc
);
2173 UfsStopExecCmd (Private
, TransReq
->Slot
);
2175 if (TransReq
->DataBufMapping
!= NULL
) {
2176 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
2179 if (TransReq
->CmdDescMapping
!= NULL
) {
2180 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
2182 if (TransReq
->CmdDescHost
!= NULL
) {
2185 EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
),
2186 TransReq
->CmdDescHost
2190 FreePool (TransReq
);
2192 gBS
->SignalEvent (CallerEvent
);
2197 Call back function when the timer event is signaled.
2199 @param[in] Event The Event this notify function registered to.
2200 @param[in] Context Pointer to the context data registered to the Event.
2205 ProcessAsyncTaskList (
2210 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2212 LIST_ENTRY
*NextEntry
;
2213 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
2214 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
;
2215 UTP_RESPONSE_UPIU
*Response
;
2216 UINT16 SenseDataLen
;
2217 UINT32 ResTranCount
;
2222 Private
= (UFS_PASS_THRU_PRIVATE_DATA
*) Context
;
2226 // Check the entries in the async I/O queue are done or not.
2228 if (!IsListEmpty(&Private
->Queue
)) {
2229 EFI_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
2230 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
2231 Packet
= TransReq
->Packet
;
2233 if ((SlotsMap
& (BIT0
<< TransReq
->Slot
)) != 0) {
2236 SlotsMap
|= BIT0
<< TransReq
->Slot
;
2238 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Value
);
2239 if (EFI_ERROR (Status
)) {
2241 // TODO: Should find/add a proper host adapter return status for this
2244 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
2245 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq
->CallerEvent
));
2246 SignalCallerEvent (Private
, TransReq
);
2250 if ((Value
& (BIT0
<< TransReq
->Slot
)) != 0) {
2252 // Scsi cmd not finished yet.
2254 if (TransReq
->TimeoutRemain
> UFS_HC_ASYNC_TIMER
) {
2255 TransReq
->TimeoutRemain
-= UFS_HC_ASYNC_TIMER
;
2261 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
2262 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq
->CallerEvent
));
2263 SignalCallerEvent (Private
, TransReq
);
2268 // Scsi cmd finished.
2270 // Get sense data if exists
2272 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
2273 ASSERT (Response
!= NULL
);
2274 SenseDataLen
= Response
->SenseDataLen
;
2275 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
2277 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
2278 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
2279 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
2283 // Check the transfer request result.
2285 Packet
->TargetStatus
= Response
->Status
;
2286 if (Response
->Response
!= 0) {
2287 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq
->CallerEvent
));
2288 SignalCallerEvent (Private
, TransReq
);
2292 if (TransReq
->Trd
->Ocs
== 0) {
2293 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2294 if ((Response
->Flags
& BIT5
) == BIT5
) {
2295 ResTranCount
= Response
->ResTranCount
;
2296 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2297 Packet
->InTransferLength
-= ResTranCount
;
2300 if ((Response
->Flags
& BIT5
) == BIT5
) {
2301 ResTranCount
= Response
->ResTranCount
;
2302 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2303 Packet
->OutTransferLength
-= ResTranCount
;
2307 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq
->CallerEvent
));
2308 SignalCallerEvent (Private
, TransReq
);
2312 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq
->CallerEvent
));
2313 SignalCallerEvent (Private
, TransReq
);