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 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
;
758 Start specified slot in transfer list of a UFS device.
760 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
761 @param[in] Slot The slot to be started.
766 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
773 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLRSR_OFFSET
, &Data
);
774 if (EFI_ERROR (Status
)) {
778 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
779 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
780 if (EFI_ERROR (Status
)) {
785 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
);
786 if (EFI_ERROR (Status
)) {
794 Stop specified slot in transfer list of a UFS device.
796 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
797 @param[in] Slot The slot to be stop.
802 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
809 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
810 if (EFI_ERROR (Status
)) {
814 if ((Data
& (BIT0
<< Slot
)) != 0) {
815 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLCLR_OFFSET
, &Data
);
816 if (EFI_ERROR (Status
)) {
820 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLCLR_OFFSET
, Data
& ~(BIT0
<< Slot
));
821 if (EFI_ERROR (Status
)) {
830 Extracts return data from query response upiu.
832 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
833 @param[in] QueryResp Pointer to the query response.
835 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.
836 @retval EFI_SUCCESS Data extracted.
840 UfsGetReturnDataFromQueryResponse (
841 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
842 IN UTP_QUERY_RESP_UPIU
*QueryResp
845 UINT16 ReturnDataSize
;
848 if (Packet
== NULL
|| QueryResp
== NULL
) {
849 return EFI_INVALID_PARAMETER
;
852 switch (Packet
->Opcode
) {
853 case UtpQueryFuncOpcodeRdDesc
:
854 ReturnDataSize
= QueryResp
->Tsf
.Length
;
855 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
856 CopyMem (Packet
->DataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
857 Packet
->TransferLength
= ReturnDataSize
;
859 case UtpQueryFuncOpcodeWrDesc
:
860 ReturnDataSize
= QueryResp
->Tsf
.Length
;
861 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
862 Packet
->TransferLength
= ReturnDataSize
;
864 case UtpQueryFuncOpcodeRdFlag
:
865 case UtpQueryFuncOpcodeSetFlag
:
866 case UtpQueryFuncOpcodeClrFlag
:
867 case UtpQueryFuncOpcodeTogFlag
:
868 CopyMem (Packet
->DataBuffer
, &QueryResp
->Tsf
.Value
, sizeof (UINT8
));
870 case UtpQueryFuncOpcodeRdAttr
:
871 case UtpQueryFuncOpcodeWrAttr
:
872 ReturnData
= QueryResp
->Tsf
.Value
;
873 SwapLittleEndianToBigEndian ((UINT8
*) &ReturnData
, sizeof (UINT32
));
874 CopyMem (Packet
->DataBuffer
, &ReturnData
, sizeof (UINT32
));
877 return EFI_INVALID_PARAMETER
;
884 Creates Transfer Request descriptor and sends Query Request to the device.
886 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
887 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
889 @retval EFI_SUCCESS The device descriptor was read/written successfully.
890 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
891 combination to point to a type of UFS device descriptor.
892 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
893 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
897 UfsSendDmRequestRetry (
898 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
899 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
905 VOID
*CmdDescMapping
;
907 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
908 UTP_QUERY_RESP_UPIU
*QueryResp
;
912 // Find out which slot of transfer request list is available.
914 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
915 if (EFI_ERROR (Status
)) {
919 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
921 // Fill transfer request descriptor to this slot.
923 Status
= UfsCreateDMCommandDesc (Private
, Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
924 if (EFI_ERROR (Status
)) {
925 DEBUG ((DEBUG_ERROR
, "Failed to create DM command descriptor\n"));
929 UfsHc
= Private
->UfsHostController
;
930 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
931 ASSERT (QueryResp
!= NULL
);
932 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
935 // Start to execute the transfer request.
937 UfsStartExecCmd (Private
, Slot
);
940 // Wait for the completion of the transfer request.
942 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
, 0, Packet
->Timeout
);
943 if (EFI_ERROR (Status
)) {
947 if (Trd
->Ocs
!= 0 || QueryResp
->QueryResp
!= UfsUtpQueryResponseSuccess
) {
948 DEBUG ((DEBUG_ERROR
, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd
->Ocs
, QueryResp
->QueryResp
));
949 DumpQueryResponseResult (QueryResp
->QueryResp
);
951 if ((QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidSelector
) ||
952 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIndex
) ||
953 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIdn
)) {
954 Status
= EFI_INVALID_PARAMETER
;
956 Status
= EFI_DEVICE_ERROR
;
961 Status
= UfsGetReturnDataFromQueryResponse (Packet
, QueryResp
);
962 if (EFI_ERROR (Status
)) {
963 DEBUG ((DEBUG_ERROR
, "Failed to get return data from query response\n"));
968 UfsHc
->Flush (UfsHc
);
970 UfsStopExecCmd (Private
, Slot
);
972 if (CmdDescMapping
!= NULL
) {
973 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
975 if (CmdDescHost
!= NULL
) {
976 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
983 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
985 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
986 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.
988 @retval EFI_SUCCESS The device responded correctly to the Query request.
989 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
990 combination to point to a type of UFS device descriptor.
991 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
992 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
997 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
998 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
1004 Status
= EFI_SUCCESS
;
1006 for (Retry
= 0; Retry
< 5; Retry
++) {
1007 Status
= UfsSendDmRequestRetry (Private
, Packet
);
1008 if (!EFI_ERROR (Status
)) {
1013 DEBUG ((DEBUG_ERROR
, "Failed to get response from the device after %d retries\n", Retry
));
1018 Read or write specified device descriptor of a UFS device.
1020 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1021 @param[in] Read The boolean variable to show r/w direction.
1022 @param[in] DescId The ID of device descriptor.
1023 @param[in] Index The Index of device descriptor.
1024 @param[in] Selector The Selector of device descriptor.
1025 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
1026 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
1027 of the data buffer specified by Descriptor. On output, the number
1028 of bytes that were actually transferred.
1030 @retval EFI_SUCCESS The device descriptor was read/written successfully.
1031 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a
1032 type of UFS device descriptor.
1033 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
1034 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
1039 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1044 IN OUT VOID
*Descriptor
,
1045 IN OUT UINT32
*DescSize
1048 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1051 if (DescSize
== NULL
) {
1052 return EFI_INVALID_PARAMETER
;
1055 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1058 Packet
.DataDirection
= UfsDataIn
;
1059 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
1061 Packet
.DataDirection
= UfsDataOut
;
1062 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
1064 Packet
.DataBuffer
= Descriptor
;
1065 Packet
.TransferLength
= *DescSize
;
1066 Packet
.DescId
= DescId
;
1067 Packet
.Index
= Index
;
1068 Packet
.Selector
= Selector
;
1069 Packet
.Timeout
= UFS_TIMEOUT
;
1071 Status
= UfsSendDmRequest (Private
, &Packet
);
1072 if (EFI_ERROR (Status
)) {
1075 *DescSize
= Packet
.TransferLength
;
1082 Read or write specified attribute of a UFS device.
1084 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1085 @param[in] Read The boolean variable to show r/w direction.
1086 @param[in] AttrId The ID of Attribute.
1087 @param[in] Index The Index of Attribute.
1088 @param[in] Selector The Selector of Attribute.
1089 @param[in, out] Attributes The value of Attribute to be read or written.
1091 @retval EFI_SUCCESS The Attribute was read/written successfully.
1092 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a
1093 type of UFS device descriptor.
1094 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
1095 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
1100 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1105 IN OUT UINT32
*Attributes
1108 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1110 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1113 Packet
.DataDirection
= UfsDataIn
;
1114 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
1116 Packet
.DataDirection
= UfsDataOut
;
1117 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
1119 Packet
.DataBuffer
= Attributes
;
1120 Packet
.DescId
= AttrId
;
1121 Packet
.Index
= Index
;
1122 Packet
.Selector
= Selector
;
1123 Packet
.Timeout
= UFS_TIMEOUT
;
1125 return UfsSendDmRequest (Private
, &Packet
);
1129 Read or write specified flag of a UFS device.
1131 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1132 @param[in] Read The boolean variable to show r/w direction.
1133 @param[in] FlagId The ID of flag to be read or written.
1134 @param[in, out] Value The value to set or clear flag.
1136 @retval EFI_SUCCESS The flag was read/written successfully.
1137 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.
1138 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1139 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1144 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1150 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1152 if (Value
== NULL
) {
1153 return EFI_INVALID_PARAMETER
;
1156 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1159 ASSERT (Value
!= NULL
);
1160 Packet
.DataDirection
= UfsDataIn
;
1161 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1163 Packet
.DataDirection
= UfsDataOut
;
1165 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1166 } else if (*Value
== 0) {
1167 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1169 return EFI_INVALID_PARAMETER
;
1172 Packet
.DataBuffer
= Value
;
1173 Packet
.DescId
= FlagId
;
1175 Packet
.Selector
= 0;
1176 Packet
.Timeout
= UFS_TIMEOUT
;
1178 return UfsSendDmRequest (Private
, &Packet
);
1182 Set specified flag to 1 on a UFS device.
1184 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1185 @param[in] FlagId The ID of flag to be set.
1187 @retval EFI_SUCCESS The flag was set successfully.
1188 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1189 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1194 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1202 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1210 Read specified flag from a UFS device.
1212 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1213 @param[in] FlagId The ID of flag to be read.
1214 @param[out] Value The flag's value.
1216 @retval EFI_SUCCESS The flag was read successfully.
1217 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1218 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1223 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1230 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1236 Sends NOP IN cmd to a UFS device for initialization process request.
1237 For more details, please refer to UFS 2.0 spec Figure 13.3.
1239 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1241 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1242 received successfully.
1243 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1244 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1245 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1250 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1256 UTP_NOP_IN_UPIU
*NopInUpiu
;
1259 VOID
*CmdDescMapping
;
1260 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1263 // Find out which slot of transfer request list is available.
1265 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1266 if (EFI_ERROR (Status
)) {
1270 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1271 Status
= UfsCreateNopCommandDesc (Private
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1272 if (EFI_ERROR (Status
)) {
1277 // Check the transfer request result.
1279 UfsHc
= Private
->UfsHostController
;
1280 NopInUpiu
= (UTP_NOP_IN_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1281 ASSERT (NopInUpiu
!= NULL
);
1282 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1285 // Start to execute the transfer request.
1287 UfsStartExecCmd (Private
, Slot
);
1290 // Wait for the completion of the transfer request.
1292 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1293 if (EFI_ERROR (Status
)) {
1297 if (NopInUpiu
->Resp
!= 0) {
1298 Status
= EFI_DEVICE_ERROR
;
1300 Status
= EFI_SUCCESS
;
1304 UfsHc
->Flush (UfsHc
);
1306 UfsStopExecCmd (Private
, Slot
);
1308 if (CmdDescMapping
!= NULL
) {
1309 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1311 if (CmdDescHost
!= NULL
) {
1312 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1319 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1321 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1322 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1323 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1325 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1326 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1327 Event is not NULL and non blocking I/O is supported, then
1328 nonblocking I/O is performed, and Event will be signaled when the
1329 SCSI Request Packet completes.
1331 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1332 commands, InTransferLength bytes were transferred from
1333 InDataBuffer. For write and bi-directional commands,
1334 OutTransferLength bytes were transferred by
1336 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1338 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1339 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1344 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1346 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
1347 IN EFI_EVENT Event OPTIONAL
1351 UTP_RESPONSE_UPIU
*Response
;
1352 UINT16 SenseDataLen
;
1353 UINT32 ResTranCount
;
1355 EFI_PHYSICAL_ADDRESS DataBufPhyAddr
;
1358 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1359 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag
;
1360 UTP_TR_PRD
*PrdtBase
;
1362 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
1364 TransReq
= AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ
));
1365 if (TransReq
== NULL
) {
1366 return EFI_OUT_OF_RESOURCES
;
1369 TransReq
->Signature
= UFS_PASS_THRU_TRANS_REQ_SIG
;
1370 TransReq
->TimeoutRemain
= Packet
->Timeout
;
1372 UfsHc
= Private
->UfsHostController
;
1374 // Find out which slot of transfer request list is available.
1376 Status
= UfsFindAvailableSlotInTrl (Private
, &TransReq
->Slot
);
1377 if (EFI_ERROR (Status
)) {
1381 TransReq
->Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + TransReq
->Slot
;
1384 // Fill transfer request descriptor to this slot.
1386 Status
= UfsCreateScsiCommandDesc (
1391 &TransReq
->CmdDescHost
,
1392 &TransReq
->CmdDescMapping
1394 if (EFI_ERROR (Status
)) {
1398 TransReq
->CmdDescSize
= TransReq
->Trd
->PrdtO
* sizeof (UINT32
) + TransReq
->Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1400 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1401 DataBuf
= Packet
->InDataBuffer
;
1402 DataLen
= Packet
->InTransferLength
;
1403 Flag
= EdkiiUfsHcOperationBusMasterWrite
;
1405 DataBuf
= Packet
->OutDataBuffer
;
1406 DataLen
= Packet
->OutTransferLength
;
1407 Flag
= EdkiiUfsHcOperationBusMasterRead
;
1411 MapLength
= DataLen
;
1412 Status
= UfsHc
->Map (
1418 &TransReq
->DataBufMapping
1421 if (EFI_ERROR (Status
) || (DataLen
!= MapLength
)) {
1426 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1428 PrdtBase
= (UTP_TR_PRD
*)((UINT8
*)TransReq
->CmdDescHost
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
1429 ASSERT (PrdtBase
!= NULL
);
1430 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)DataBufPhyAddr
, DataLen
);
1433 // Insert the async SCSI cmd to the Async I/O list
1435 if (Event
!= NULL
) {
1436 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1437 TransReq
->Packet
= Packet
;
1438 TransReq
->CallerEvent
= Event
;
1439 InsertTailList (&Private
->Queue
, &TransReq
->TransferList
);
1440 gBS
->RestoreTPL (OldTpl
);
1444 // Start to execute the transfer request.
1446 UfsStartExecCmd (Private
, TransReq
->Slot
);
1449 // Immediately return for async I/O.
1451 if (Event
!= NULL
) {
1456 // Wait for the completion of the transfer request.
1458 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< TransReq
->Slot
, 0, Packet
->Timeout
);
1459 if (EFI_ERROR (Status
)) {
1464 // Get sense data if exists
1466 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
1467 ASSERT (Response
!= NULL
);
1468 SenseDataLen
= Response
->SenseDataLen
;
1469 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1471 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1472 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1473 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1477 // Check the transfer request result.
1479 Packet
->TargetStatus
= Response
->Status
;
1480 if (Response
->Response
!= 0) {
1481 DEBUG ((DEBUG_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1482 Status
= EFI_DEVICE_ERROR
;
1486 if (TransReq
->Trd
->Ocs
== 0) {
1487 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1488 if ((Response
->Flags
& BIT5
) == BIT5
) {
1489 ResTranCount
= Response
->ResTranCount
;
1490 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1491 Packet
->InTransferLength
-= ResTranCount
;
1494 if ((Response
->Flags
& BIT5
) == BIT5
) {
1495 ResTranCount
= Response
->ResTranCount
;
1496 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1497 Packet
->OutTransferLength
-= ResTranCount
;
1501 Status
= EFI_DEVICE_ERROR
;
1505 UfsHc
->Flush (UfsHc
);
1507 UfsStopExecCmd (Private
, TransReq
->Slot
);
1509 if (TransReq
->DataBufMapping
!= NULL
) {
1510 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
1514 if (TransReq
->CmdDescMapping
!= NULL
) {
1515 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
1517 if (TransReq
->CmdDescHost
!= NULL
) {
1518 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
), TransReq
->CmdDescHost
);
1520 if (TransReq
!= NULL
) {
1521 FreePool (TransReq
);
1528 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1530 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1531 @param[in] UicOpcode The opcode of the UIC command.
1532 @param[in] Arg1 The value for 1st argument of the UIC command.
1533 @param[in] Arg2 The value for 2nd argument of the UIC command.
1534 @param[in] Arg3 The value for 3rd argument of the UIC command.
1536 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1537 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1538 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1542 UfsExecUicCommands (
1543 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1553 Status
= UfsMmioRead32 (Private
, UFS_HC_IS_OFFSET
, &Data
);
1554 if (EFI_ERROR (Status
)) {
1558 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1560 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1562 Status
= UfsMmioWrite32 (Private
, UFS_HC_IS_OFFSET
, Data
);
1563 if (EFI_ERROR (Status
)) {
1569 // When programming UIC command registers, host software shall set the register UICCMD
1570 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1573 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG1_OFFSET
, Arg1
);
1574 if (EFI_ERROR (Status
)) {
1578 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, Arg2
);
1579 if (EFI_ERROR (Status
)) {
1583 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, Arg3
);
1584 if (EFI_ERROR (Status
)) {
1589 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1591 Status
= UfsWaitMemSet (Private
, UFS_HC_STATUS_OFFSET
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1592 if (EFI_ERROR (Status
)) {
1596 Status
= UfsMmioWrite32 (Private
, UFS_HC_UIC_CMD_OFFSET
, (UINT32
)UicOpcode
);
1597 if (EFI_ERROR (Status
)) {
1602 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1603 // This bit is set to '1' by the host controller upon completion of a UIC command.
1605 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1606 if (EFI_ERROR (Status
)) {
1610 if (UicOpcode
!= UfsUicDmeReset
) {
1611 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, &Data
);
1612 if (EFI_ERROR (Status
)) {
1615 if ((Data
& 0xFF) != 0) {
1617 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1619 return EFI_DEVICE_ERROR
;
1624 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1626 Status
= UfsMmioRead32 (Private
, UFS_HC_STATUS_OFFSET
, &Data
);
1627 if (EFI_ERROR (Status
)) {
1631 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1632 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1633 if (EFI_ERROR (Status
)) {
1634 return EFI_DEVICE_ERROR
;
1636 return EFI_NOT_FOUND
;
1639 DEBUG ((DEBUG_INFO
, "UfsPassThruDxe: found a attached UFS device\n"));
1645 Allocate common buffer for host and UFS bus master access simultaneously.
1647 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1648 @param[in] Size The length of buffer to be allocated.
1649 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1650 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1651 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1653 @retval EFI_SUCCESS The common buffer was allocated successfully.
1654 @retval EFI_DEVICE_ERROR The allocation fails.
1655 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1659 UfsAllocateAlignCommonBuffer (
1660 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1662 OUT VOID
**CmdDescHost
,
1663 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1664 OUT VOID
**CmdDescMapping
1669 BOOLEAN Is32BitAddr
;
1670 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1672 if ((Private
->Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1673 Is32BitAddr
= FALSE
;
1678 UfsHc
= Private
->UfsHostController
;
1679 Status
= UfsHc
->AllocateBuffer (
1682 EfiBootServicesData
,
1683 EFI_SIZE_TO_PAGES (Size
),
1687 if (EFI_ERROR (Status
)) {
1688 *CmdDescMapping
= NULL
;
1689 *CmdDescHost
= NULL
;
1690 *CmdDescPhyAddr
= 0;
1691 return EFI_OUT_OF_RESOURCES
;
1694 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1695 Status
= UfsHc
->Map (
1697 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1704 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1707 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1710 *CmdDescHost
= NULL
;
1711 return EFI_OUT_OF_RESOURCES
;
1714 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1716 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1724 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1727 *CmdDescMapping
= NULL
;
1728 *CmdDescHost
= NULL
;
1729 return EFI_DEVICE_ERROR
;
1732 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1737 Enable the UFS host controller for accessing.
1739 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1741 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1742 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1746 UfsEnableHostController (
1747 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1754 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1756 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1758 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
1759 if (EFI_ERROR (Status
)) {
1763 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1765 // Write a 0 to the HCE register at first to disable the host controller.
1767 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
1768 if (EFI_ERROR (Status
)) {
1772 // Wait until HCE is read as '0' before continuing.
1774 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1775 if (EFI_ERROR (Status
)) {
1776 return EFI_DEVICE_ERROR
;
1781 // Write a 1 to the HCE register to enable the UFS host controller.
1783 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
);
1784 if (EFI_ERROR (Status
)) {
1789 // Wait until HCE is read as '1' before continuing.
1791 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1792 if (EFI_ERROR (Status
)) {
1793 return EFI_DEVICE_ERROR
;
1800 Detect if a UFS device attached.
1802 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1804 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1805 @retval EFI_NOT_FOUND Not found a UFS device attached.
1806 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1810 UfsDeviceDetection (
1811 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1818 // Start UFS device detection.
1819 // Try up to 3 times for establishing data link with device.
1821 for (Retry
= 0; Retry
< 3; Retry
++) {
1822 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1823 if (!EFI_ERROR (Status
)) {
1827 if (Status
== EFI_NOT_FOUND
) {
1831 return EFI_DEVICE_ERROR
;
1835 return EFI_NOT_FOUND
;
1842 Initialize UFS task management request list related h/w context.
1844 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1846 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1847 @retval EFI_DEVICE_ERROR The initialization fails.
1851 UfsInitTaskManagementRequestList (
1852 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1858 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1859 VOID
*CmdDescMapping
;
1863 // Initial h/w and s/w context for future operations.
1866 CmdDescMapping
= NULL
;
1869 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1870 if (EFI_ERROR (Status
)) {
1874 Private
->Capabilities
= Data
;
1877 // Allocate and initialize UTP Task Management Request List.
1879 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1880 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1881 if (EFI_ERROR (Status
)) {
1886 // Program the UTP Task Management Request List Base Address and UTP Task Management
1887 // Request List Base Address with a 64-bit address allocated at step 6.
1889 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1890 if (EFI_ERROR (Status
)) {
1894 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1895 if (EFI_ERROR (Status
)) {
1898 Private
->UtpTmrlBase
= CmdDescHost
;
1899 Private
->Nutmrs
= Nutmrs
;
1900 Private
->TmrlMapping
= CmdDescMapping
;
1903 // Enable the UTP Task Management Request List by setting the UTP Task Management
1904 // Request List RunStop Register (UTMRLRSR) to '1'.
1906 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
1907 if (EFI_ERROR (Status
)) {
1915 Initialize UFS transfer request list related h/w context.
1917 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1919 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1920 @retval EFI_DEVICE_ERROR The initialization fails.
1924 UfsInitTransferRequestList (
1925 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1931 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1932 VOID
*CmdDescMapping
;
1936 // Initial h/w and s/w context for future operations.
1939 CmdDescMapping
= NULL
;
1942 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1943 if (EFI_ERROR (Status
)) {
1947 Private
->Capabilities
= Data
;
1950 // Allocate and initialize UTP Transfer Request List.
1952 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1953 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1954 if (EFI_ERROR (Status
)) {
1959 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1960 // Base Address with a 64-bit address allocated at step 8.
1962 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1963 if (EFI_ERROR (Status
)) {
1967 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1968 if (EFI_ERROR (Status
)) {
1972 Private
->UtpTrlBase
= CmdDescHost
;
1973 Private
->Nutrs
= Nutrs
;
1974 Private
->TrlMapping
= CmdDescMapping
;
1977 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1978 // RunStop Register (UTRLRSR) to '1'.
1980 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
1981 if (EFI_ERROR (Status
)) {
1989 Initialize the UFS host controller.
1991 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1993 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1994 @retval Others A device error occurred while initializing the controller.
1999 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2004 Status
= UfsEnableHostController (Private
);
2005 if (EFI_ERROR (Status
)) {
2006 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2010 Status
= UfsDeviceDetection (Private
);
2011 if (EFI_ERROR (Status
)) {
2012 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2016 Status
= UfsInitTaskManagementRequestList (Private
);
2017 if (EFI_ERROR (Status
)) {
2018 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2022 Status
= UfsInitTransferRequestList (Private
);
2023 if (EFI_ERROR (Status
)) {
2024 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2028 DEBUG ((DEBUG_INFO
, "UfsControllerInit Finished\n"));
2033 Stop the UFS host controller.
2035 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2037 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2038 @retval Others A device error occurred while stopping the controller.
2043 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2050 // Enable the UTP Task Management Request List by setting the UTP Task Management
2051 // Request List RunStop Register (UTMRLRSR) to '1'.
2053 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2054 if (EFI_ERROR (Status
)) {
2059 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2060 // RunStop Register (UTRLRSR) to '1'.
2062 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2063 if (EFI_ERROR (Status
)) {
2068 // Write a 0 to the HCE register in order to disable the host controller.
2070 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2071 if (EFI_ERROR (Status
)) {
2074 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2076 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2077 if (EFI_ERROR (Status
)) {
2082 // Wait until HCE is read as '0' before continuing.
2084 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2085 if (EFI_ERROR (Status
)) {
2086 return EFI_DEVICE_ERROR
;
2089 DEBUG ((DEBUG_INFO
, "UfsController is stopped\n"));
2096 Internal helper function which will signal the caller event and clean up
2099 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2101 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2108 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
2109 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
2112 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
2113 EFI_EVENT CallerEvent
;
2115 ASSERT ((Private
!= NULL
) && (TransReq
!= NULL
));
2117 UfsHc
= Private
->UfsHostController
;
2118 CallerEvent
= TransReq
->CallerEvent
;
2120 RemoveEntryList (&TransReq
->TransferList
);
2122 UfsHc
->Flush (UfsHc
);
2124 UfsStopExecCmd (Private
, TransReq
->Slot
);
2126 if (TransReq
->DataBufMapping
!= NULL
) {
2127 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
2130 if (TransReq
->CmdDescMapping
!= NULL
) {
2131 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
2133 if (TransReq
->CmdDescHost
!= NULL
) {
2136 EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
),
2137 TransReq
->CmdDescHost
2141 FreePool (TransReq
);
2143 gBS
->SignalEvent (CallerEvent
);
2148 Call back function when the timer event is signaled.
2150 @param[in] Event The Event this notify function registered to.
2151 @param[in] Context Pointer to the context data registered to the Event.
2156 ProcessAsyncTaskList (
2161 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2163 LIST_ENTRY
*NextEntry
;
2164 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
2165 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
;
2166 UTP_RESPONSE_UPIU
*Response
;
2167 UINT16 SenseDataLen
;
2168 UINT32 ResTranCount
;
2173 Private
= (UFS_PASS_THRU_PRIVATE_DATA
*) Context
;
2177 // Check the entries in the async I/O queue are done or not.
2179 if (!IsListEmpty(&Private
->Queue
)) {
2180 EFI_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
2181 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
2182 Packet
= TransReq
->Packet
;
2184 if ((SlotsMap
& (BIT0
<< TransReq
->Slot
)) != 0) {
2187 SlotsMap
|= BIT0
<< TransReq
->Slot
;
2189 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Value
);
2190 if (EFI_ERROR (Status
)) {
2192 // TODO: Should find/add a proper host adapter return status for this
2195 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
2196 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq
->CallerEvent
));
2197 SignalCallerEvent (Private
, TransReq
);
2201 if ((Value
& (BIT0
<< TransReq
->Slot
)) != 0) {
2203 // Scsi cmd not finished yet.
2205 if (TransReq
->TimeoutRemain
> UFS_HC_ASYNC_TIMER
) {
2206 TransReq
->TimeoutRemain
-= UFS_HC_ASYNC_TIMER
;
2212 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
2213 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq
->CallerEvent
));
2214 SignalCallerEvent (Private
, TransReq
);
2219 // Scsi cmd finished.
2221 // Get sense data if exists
2223 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
2224 ASSERT (Response
!= NULL
);
2225 SenseDataLen
= Response
->SenseDataLen
;
2226 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
2228 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
2229 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
2230 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
2234 // Check the transfer request result.
2236 Packet
->TargetStatus
= Response
->Status
;
2237 if (Response
->Response
!= 0) {
2238 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq
->CallerEvent
));
2239 SignalCallerEvent (Private
, TransReq
);
2243 if (TransReq
->Trd
->Ocs
== 0) {
2244 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2245 if ((Response
->Flags
& BIT5
) == BIT5
) {
2246 ResTranCount
= Response
->ResTranCount
;
2247 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2248 Packet
->InTransferLength
-= ResTranCount
;
2251 if ((Response
->Flags
& BIT5
) == BIT5
) {
2252 ResTranCount
= Response
->ResTranCount
;
2253 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2254 Packet
->OutTransferLength
-= ResTranCount
;
2258 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq
->CallerEvent
));
2259 SignalCallerEvent (Private
, TransReq
);
2263 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq
->CallerEvent
));
2264 SignalCallerEvent (Private
, TransReq
);