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 ((EFI_D_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
163 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
166 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
169 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
172 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BAD_INDEX\n"));
175 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
178 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
181 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
184 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BUSY\n"));
187 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - DME_FAILURE\n"));
198 DEBUG ((EFI_D_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 ((EFI_D_VERBOSE
, "Query Response with Parameter Not Readable\n"));
223 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Not Writeable\n"));
226 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Already Written\n"));
229 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Length\n"));
232 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Value\n"));
235 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Selector\n"));
238 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Index\n"));
241 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Idn\n"));
244 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Opcode\n"));
247 DEBUG ((EFI_D_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 ((EFI_D_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
);
487 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
489 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
490 @param[in] Lun The Lun on which the SCSI command is executed.
491 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
492 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
493 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
494 @param[out] CmdDescMapping A resulting value to pass to Unmap().
496 @retval EFI_SUCCESS The creation succeed.
497 @retval EFI_DEVICE_ERROR The creation failed.
498 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
502 UfsCreateScsiCommandDesc (
503 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
505 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
507 OUT VOID
**CmdDescHost
,
508 OUT VOID
**CmdDescMapping
513 UTP_COMMAND_UPIU
*CommandUpiu
;
514 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
517 UFS_DATA_DIRECTION DataDirection
;
519 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
521 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
522 DataLen
= Packet
->InTransferLength
;
523 DataDirection
= UfsDataIn
;
525 DataLen
= Packet
->OutTransferLength
;
526 DataDirection
= UfsDataOut
;
530 DataDirection
= UfsNoData
;
533 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)DataLen
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
535 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
537 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
538 if (EFI_ERROR (Status
)) {
542 CommandUpiu
= (UTP_COMMAND_UPIU
*)*CmdDescHost
;
544 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, DataLen
);
547 // Fill UTP_TRD associated fields
548 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
549 // *MUST* be located at a 64-bit aligned boundary.
551 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
552 Trd
->Dd
= DataDirection
;
553 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
554 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
555 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
556 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
557 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
558 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
559 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
560 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
565 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
567 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
568 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
569 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
570 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
571 @param[out] CmdDescMapping A resulting value to pass to Unmap().
573 @retval EFI_SUCCESS The creation succeed.
574 @retval EFI_DEVICE_ERROR The creation failed.
575 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
576 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
580 UfsCreateDMCommandDesc (
581 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
582 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
584 OUT VOID
**CmdDescHost
,
585 OUT VOID
**CmdDescMapping
589 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
594 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
597 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
599 Opcode
= Packet
->Opcode
;
600 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
601 return EFI_INVALID_PARAMETER
;
604 DataDirection
= Packet
->DataDirection
;
605 if (DataDirection
== UfsDataIn
) {
606 DataSize
= Packet
->InTransferLength
;
607 Data
= Packet
->InDataBuffer
;
608 } else if (DataDirection
== UfsDataOut
) {
609 DataSize
= Packet
->OutTransferLength
;
610 Data
= Packet
->OutDataBuffer
;
616 if (((Opcode
!= UtpQueryFuncOpcodeSetFlag
) && (Opcode
!= UtpQueryFuncOpcodeClrFlag
) && (Opcode
!= UtpQueryFuncOpcodeTogFlag
))
617 && ((DataSize
== 0) || (Data
== NULL
))) {
618 return EFI_INVALID_PARAMETER
;
621 if (((Opcode
== UtpQueryFuncOpcodeSetFlag
) || (Opcode
== UtpQueryFuncOpcodeClrFlag
) || (Opcode
== UtpQueryFuncOpcodeTogFlag
))
622 && ((DataSize
!= 0) || (Data
!= NULL
))) {
623 return EFI_INVALID_PARAMETER
;
626 if ((Opcode
== UtpQueryFuncOpcodeWrAttr
) && (DataSize
!= sizeof (UINT32
))) {
627 return EFI_INVALID_PARAMETER
;
630 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
631 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
633 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
636 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
637 if (EFI_ERROR (Status
)) {
642 // Initialize UTP QUERY REQUEST UPIU
644 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)*CmdDescHost
;
645 ASSERT (QueryReqUpiu
!= NULL
);
646 UfsInitQueryRequestUpiu (
658 // Fill UTP_TRD associated fields
659 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
661 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
662 Trd
->Dd
= DataDirection
;
663 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
664 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
665 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
666 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
667 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
668 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
669 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
671 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
672 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
679 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
681 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
682 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
683 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
684 @param[out] CmdDescMapping A resulting value to pass to Unmap().
686 @retval EFI_SUCCESS The creation succeed.
687 @retval EFI_DEVICE_ERROR The creation failed.
688 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
692 UfsCreateNopCommandDesc (
693 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
695 OUT VOID
**CmdDescHost
,
696 OUT VOID
**CmdDescMapping
700 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
702 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
704 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
706 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
707 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
708 if (EFI_ERROR (Status
)) {
712 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)*CmdDescHost
;
713 ASSERT (NopOutUpiu
!= NULL
);
714 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
717 // Fill UTP_TRD associated fields
718 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
720 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
722 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
723 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
724 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
725 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
726 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
727 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
733 Find out available slot in transfer list of a UFS device.
735 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
736 @param[out] Slot The available slot.
738 @retval EFI_SUCCESS The available slot was found successfully.
739 @retval EFI_NOT_READY No slot is available at this moment.
743 UfsFindAvailableSlotInTrl (
744 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
753 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
755 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
756 if (EFI_ERROR (Status
)) {
760 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
762 for (Index
= 0; Index
< Nutrs
; Index
++) {
763 if ((Data
& (BIT0
<< Index
)) == 0) {
769 return EFI_NOT_READY
;
773 Find out available slot in task management transfer list of a UFS device.
775 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
776 @param[out] Slot The available slot.
778 @retval EFI_SUCCESS The available slot was found successfully.
782 UfsFindAvailableSlotInTmrl (
783 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
787 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
790 // The simplest algo to always use slot 0.
791 // TODO: enhance it to support async transfer with multiple slot.
799 Start specified slot in transfer list of a UFS device.
801 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
802 @param[in] Slot The slot to be started.
807 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
814 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLRSR_OFFSET
, &Data
);
815 if (EFI_ERROR (Status
)) {
819 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
820 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
821 if (EFI_ERROR (Status
)) {
826 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
);
827 if (EFI_ERROR (Status
)) {
835 Stop specified slot in transfer list of a UFS device.
837 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
838 @param[in] Slot The slot to be stop.
843 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
850 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
851 if (EFI_ERROR (Status
)) {
855 if ((Data
& (BIT0
<< Slot
)) != 0) {
856 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLCLR_OFFSET
, &Data
);
857 if (EFI_ERROR (Status
)) {
861 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLCLR_OFFSET
, Data
& ~(BIT0
<< Slot
));
862 if (EFI_ERROR (Status
)) {
871 Read or write specified device descriptor of a UFS device.
873 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
874 @param[in] Read The boolean variable to show r/w direction.
875 @param[in] DescId The ID of device descriptor.
876 @param[in] Index The Index of device descriptor.
877 @param[in] Selector The Selector of device descriptor.
878 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
879 @param[in] DescSize The size of device descriptor buffer.
881 @retval EFI_SUCCESS The device descriptor was read/written successfully.
882 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
883 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
888 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
893 IN OUT VOID
*Descriptor
,
898 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
901 UTP_QUERY_RESP_UPIU
*QueryResp
;
903 UINT16 ReturnDataSize
;
905 VOID
*CmdDescMapping
;
906 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
908 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
911 Packet
.DataDirection
= UfsDataIn
;
912 Packet
.InDataBuffer
= Descriptor
;
913 Packet
.InTransferLength
= DescSize
;
914 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
916 Packet
.DataDirection
= UfsDataOut
;
917 Packet
.OutDataBuffer
= Descriptor
;
918 Packet
.OutTransferLength
= DescSize
;
919 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
921 Packet
.DescId
= DescId
;
922 Packet
.Index
= Index
;
923 Packet
.Selector
= Selector
;
924 Packet
.Timeout
= UFS_TIMEOUT
;
927 // Find out which slot of transfer request list is available.
929 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
930 if (EFI_ERROR (Status
)) {
934 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
936 // Fill transfer request descriptor to this slot.
938 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
939 if (EFI_ERROR (Status
)) {
944 // Check the transfer request result.
946 UfsHc
= Private
->UfsHostController
;
947 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
948 ASSERT (QueryResp
!= NULL
);
949 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
952 // Start to execute the transfer request.
954 UfsStartExecCmd (Private
, Slot
);
957 // Wait for the completion of the transfer request.
959 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, Packet
.Timeout
);
960 if (EFI_ERROR (Status
)) {
964 if (QueryResp
->QueryResp
!= 0) {
965 DumpQueryResponseResult (QueryResp
->QueryResp
);
966 Status
= EFI_DEVICE_ERROR
;
971 ReturnDataSize
= QueryResp
->Tsf
.Length
;
972 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
975 CopyMem (Packet
.InDataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
976 Packet
.InTransferLength
= ReturnDataSize
;
978 Packet
.OutTransferLength
= ReturnDataSize
;
981 Status
= EFI_DEVICE_ERROR
;
985 UfsHc
->Flush (UfsHc
);
987 UfsStopExecCmd (Private
, Slot
);
989 if (CmdDescMapping
!= NULL
) {
990 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
992 if (CmdDescHost
!= NULL
) {
993 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1000 Read or write specified attribute of a UFS device.
1002 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1003 @param[in] Read The boolean variable to show r/w direction.
1004 @param[in] AttrId The ID of Attribute.
1005 @param[in] Index The Index of Attribute.
1006 @param[in] Selector The Selector of Attribute.
1007 @param[in, out] Attributes The value of Attribute to be read or written.
1009 @retval EFI_SUCCESS The Attribute was read/written successfully.
1010 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
1011 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
1016 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1021 IN OUT UINT32
*Attributes
1025 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1028 UTP_QUERY_RESP_UPIU
*QueryResp
;
1032 VOID
*CmdDescMapping
;
1033 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1035 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1038 Packet
.DataDirection
= UfsDataIn
;
1039 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
1041 Packet
.DataDirection
= UfsDataOut
;
1042 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
1044 Packet
.DescId
= AttrId
;
1045 Packet
.Index
= Index
;
1046 Packet
.Selector
= Selector
;
1047 Packet
.Timeout
= UFS_TIMEOUT
;
1050 // Find out which slot of transfer request list is available.
1052 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1053 if (EFI_ERROR (Status
)) {
1057 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1059 // Fill transfer request descriptor to this slot.
1061 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1062 if (EFI_ERROR (Status
)) {
1067 // Check the transfer request result.
1069 UfsHc
= Private
->UfsHostController
;
1070 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1071 ASSERT (QueryResp
!= NULL
);
1072 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1075 // Start to execute the transfer request.
1077 UfsStartExecCmd (Private
, Slot
);
1080 // Wait for the completion of the transfer request.
1082 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, Packet
.Timeout
);
1083 if (EFI_ERROR (Status
)) {
1087 if (QueryResp
->QueryResp
!= 0) {
1088 DumpQueryResponseResult (QueryResp
->QueryResp
);
1089 Status
= EFI_DEVICE_ERROR
;
1093 if (Trd
->Ocs
== 0) {
1094 ReturnData
= QueryResp
->Tsf
.Value
;
1095 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnData
, sizeof (UINT32
));
1096 *Attributes
= ReturnData
;
1098 Status
= EFI_DEVICE_ERROR
;
1102 UfsHc
->Flush (UfsHc
);
1104 UfsStopExecCmd (Private
, Slot
);
1106 if (CmdDescMapping
!= NULL
) {
1107 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1110 if (CmdDescHost
!= NULL
) {
1111 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1118 Read or write specified flag of a UFS device.
1120 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1121 @param[in] Read The boolean variable to show r/w direction.
1122 @param[in] FlagId The ID of flag to be read or written.
1123 @param[in, out] Value The value to set or clear flag.
1125 @retval EFI_SUCCESS The flag was read/written successfully.
1126 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1127 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1132 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1139 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1142 UTP_QUERY_RESP_UPIU
*QueryResp
;
1145 VOID
*CmdDescMapping
;
1146 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1148 if (Value
== NULL
) {
1149 return EFI_INVALID_PARAMETER
;
1152 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1155 ASSERT (Value
!= NULL
);
1156 Packet
.DataDirection
= UfsDataIn
;
1157 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1159 Packet
.DataDirection
= UfsDataOut
;
1161 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1162 } else if (*Value
== 0) {
1163 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1165 return EFI_INVALID_PARAMETER
;
1168 Packet
.DescId
= FlagId
;
1170 Packet
.Selector
= 0;
1171 Packet
.Timeout
= UFS_TIMEOUT
;
1174 // Find out which slot of transfer request list is available.
1176 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1177 if (EFI_ERROR (Status
)) {
1182 // Fill transfer request descriptor to this slot.
1184 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1185 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1186 if (EFI_ERROR (Status
)) {
1191 // Check the transfer request result.
1193 UfsHc
= Private
->UfsHostController
;
1194 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1195 ASSERT (QueryResp
!= NULL
);
1196 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1199 // Start to execute the transfer request.
1201 UfsStartExecCmd (Private
, Slot
);
1204 // Wait for the completion of the transfer request.
1206 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, Packet
.Timeout
);
1207 if (EFI_ERROR (Status
)) {
1211 if (QueryResp
->QueryResp
!= 0) {
1212 DumpQueryResponseResult (QueryResp
->QueryResp
);
1213 Status
= EFI_DEVICE_ERROR
;
1217 if (Trd
->Ocs
== 0) {
1218 *Value
= (UINT8
)QueryResp
->Tsf
.Value
;
1220 Status
= EFI_DEVICE_ERROR
;
1224 UfsHc
->Flush (UfsHc
);
1226 UfsStopExecCmd (Private
, Slot
);
1228 if (CmdDescMapping
!= NULL
) {
1229 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1231 if (CmdDescHost
!= NULL
) {
1232 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1239 Set specified flag to 1 on a UFS device.
1241 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1242 @param[in] FlagId The ID of flag to be set.
1244 @retval EFI_SUCCESS The flag was set successfully.
1245 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1246 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1251 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1259 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1265 Clear specified flag to 0 on a UFS device.
1267 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1268 @param[in] FlagId The ID of flag to be cleared.
1270 @retval EFI_SUCCESS The flag was cleared successfully.
1271 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1272 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1277 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1285 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1291 Read specified flag from a UFS device.
1293 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1294 @param[in] FlagId The ID of flag to be read.
1295 @param[out] Value The flag's value.
1297 @retval EFI_SUCCESS The flag was read successfully.
1298 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1299 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1304 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1311 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1317 Sends NOP IN cmd to a UFS device for initialization process request.
1318 For more details, please refer to UFS 2.0 spec Figure 13.3.
1320 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1322 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1323 received successfully.
1324 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1325 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1326 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1331 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1337 UTP_NOP_IN_UPIU
*NopInUpiu
;
1340 VOID
*CmdDescMapping
;
1341 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1344 // Find out which slot of transfer request list is available.
1346 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1347 if (EFI_ERROR (Status
)) {
1351 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1352 Status
= UfsCreateNopCommandDesc (Private
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1353 if (EFI_ERROR (Status
)) {
1358 // Check the transfer request result.
1360 UfsHc
= Private
->UfsHostController
;
1361 NopInUpiu
= (UTP_NOP_IN_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1362 ASSERT (NopInUpiu
!= NULL
);
1363 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1366 // Start to execute the transfer request.
1368 UfsStartExecCmd (Private
, Slot
);
1371 // Wait for the completion of the transfer request.
1373 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1374 if (EFI_ERROR (Status
)) {
1378 if (NopInUpiu
->Resp
!= 0) {
1379 Status
= EFI_DEVICE_ERROR
;
1381 Status
= EFI_SUCCESS
;
1385 UfsHc
->Flush (UfsHc
);
1387 UfsStopExecCmd (Private
, Slot
);
1389 if (CmdDescMapping
!= NULL
) {
1390 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1392 if (CmdDescHost
!= NULL
) {
1393 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1400 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1402 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1403 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1404 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1406 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1407 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1408 Event is not NULL and non blocking I/O is supported, then
1409 nonblocking I/O is performed, and Event will be signaled when the
1410 SCSI Request Packet completes.
1412 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1413 commands, InTransferLength bytes were transferred from
1414 InDataBuffer. For write and bi-directional commands,
1415 OutTransferLength bytes were transferred by
1417 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1419 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1420 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1425 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1427 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
1428 IN EFI_EVENT Event OPTIONAL
1432 UTP_RESPONSE_UPIU
*Response
;
1433 UINT16 SenseDataLen
;
1434 UINT32 ResTranCount
;
1436 EFI_PHYSICAL_ADDRESS DataBufPhyAddr
;
1439 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1440 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag
;
1441 UTP_TR_PRD
*PrdtBase
;
1443 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
1445 TransReq
= AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ
));
1446 if (TransReq
== NULL
) {
1447 return EFI_OUT_OF_RESOURCES
;
1450 TransReq
->Signature
= UFS_PASS_THRU_TRANS_REQ_SIG
;
1451 TransReq
->TimeoutRemain
= Packet
->Timeout
;
1453 UfsHc
= Private
->UfsHostController
;
1455 // Find out which slot of transfer request list is available.
1457 Status
= UfsFindAvailableSlotInTrl (Private
, &TransReq
->Slot
);
1458 if (EFI_ERROR (Status
)) {
1462 TransReq
->Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + TransReq
->Slot
;
1465 // Fill transfer request descriptor to this slot.
1467 Status
= UfsCreateScsiCommandDesc (
1472 &TransReq
->CmdDescHost
,
1473 &TransReq
->CmdDescMapping
1475 if (EFI_ERROR (Status
)) {
1479 TransReq
->CmdDescSize
= TransReq
->Trd
->PrdtO
* sizeof (UINT32
) + TransReq
->Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1481 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1482 DataBuf
= Packet
->InDataBuffer
;
1483 DataLen
= Packet
->InTransferLength
;
1484 Flag
= EdkiiUfsHcOperationBusMasterWrite
;
1486 DataBuf
= Packet
->OutDataBuffer
;
1487 DataLen
= Packet
->OutTransferLength
;
1488 Flag
= EdkiiUfsHcOperationBusMasterRead
;
1492 MapLength
= DataLen
;
1493 Status
= UfsHc
->Map (
1499 &TransReq
->DataBufMapping
1502 if (EFI_ERROR (Status
) || (DataLen
!= MapLength
)) {
1507 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1509 PrdtBase
= (UTP_TR_PRD
*)((UINT8
*)TransReq
->CmdDescHost
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
1510 ASSERT (PrdtBase
!= NULL
);
1511 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)DataBufPhyAddr
, DataLen
);
1514 // Insert the async SCSI cmd to the Async I/O list
1516 if (Event
!= NULL
) {
1517 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1518 TransReq
->Packet
= Packet
;
1519 TransReq
->CallerEvent
= Event
;
1520 InsertTailList (&Private
->Queue
, &TransReq
->TransferList
);
1521 gBS
->RestoreTPL (OldTpl
);
1525 // Start to execute the transfer request.
1527 UfsStartExecCmd (Private
, TransReq
->Slot
);
1530 // Immediately return for async I/O.
1532 if (Event
!= NULL
) {
1537 // Wait for the completion of the transfer request.
1539 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< TransReq
->Slot
, 0, Packet
->Timeout
);
1540 if (EFI_ERROR (Status
)) {
1545 // Get sense data if exists
1547 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
1548 ASSERT (Response
!= NULL
);
1549 SenseDataLen
= Response
->SenseDataLen
;
1550 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1552 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1553 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1554 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1558 // Check the transfer request result.
1560 Packet
->TargetStatus
= Response
->Status
;
1561 if (Response
->Response
!= 0) {
1562 DEBUG ((EFI_D_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1563 Status
= EFI_DEVICE_ERROR
;
1567 if (TransReq
->Trd
->Ocs
== 0) {
1568 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1569 if ((Response
->Flags
& BIT5
) == BIT5
) {
1570 ResTranCount
= Response
->ResTranCount
;
1571 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1572 Packet
->InTransferLength
-= ResTranCount
;
1575 if ((Response
->Flags
& BIT5
) == BIT5
) {
1576 ResTranCount
= Response
->ResTranCount
;
1577 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1578 Packet
->OutTransferLength
-= ResTranCount
;
1582 Status
= EFI_DEVICE_ERROR
;
1586 UfsHc
->Flush (UfsHc
);
1588 UfsStopExecCmd (Private
, TransReq
->Slot
);
1590 if (TransReq
->DataBufMapping
!= NULL
) {
1591 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
1595 if (TransReq
->CmdDescMapping
!= NULL
) {
1596 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
1598 if (TransReq
->CmdDescHost
!= NULL
) {
1599 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
), TransReq
->CmdDescHost
);
1601 if (TransReq
!= NULL
) {
1602 FreePool (TransReq
);
1609 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1611 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1612 @param[in] UicOpcode The opcode of the UIC command.
1613 @param[in] Arg1 The value for 1st argument of the UIC command.
1614 @param[in] Arg2 The value for 2nd argument of the UIC command.
1615 @param[in] Arg3 The value for 3rd argument of the UIC command.
1617 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1618 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1619 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1623 UfsExecUicCommands (
1624 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1634 Status
= UfsMmioRead32 (Private
, UFS_HC_IS_OFFSET
, &Data
);
1635 if (EFI_ERROR (Status
)) {
1639 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1641 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1643 Status
= UfsMmioWrite32 (Private
, UFS_HC_IS_OFFSET
, Data
);
1644 if (EFI_ERROR (Status
)) {
1650 // When programming UIC command registers, host software shall set the register UICCMD
1651 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1654 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG1_OFFSET
, Arg1
);
1655 if (EFI_ERROR (Status
)) {
1659 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, Arg2
);
1660 if (EFI_ERROR (Status
)) {
1664 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, Arg3
);
1665 if (EFI_ERROR (Status
)) {
1670 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1672 Status
= UfsWaitMemSet (Private
, UFS_HC_STATUS_OFFSET
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1673 if (EFI_ERROR (Status
)) {
1677 Status
= UfsMmioWrite32 (Private
, UFS_HC_UIC_CMD_OFFSET
, (UINT32
)UicOpcode
);
1678 if (EFI_ERROR (Status
)) {
1683 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1684 // This bit is set to '1' by the host controller upon completion of a UIC command.
1686 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1687 if (EFI_ERROR (Status
)) {
1691 if (UicOpcode
!= UfsUicDmeReset
) {
1692 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, &Data
);
1693 if (EFI_ERROR (Status
)) {
1696 if ((Data
& 0xFF) != 0) {
1698 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1700 return EFI_DEVICE_ERROR
;
1705 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1707 Status
= UfsMmioRead32 (Private
, UFS_HC_STATUS_OFFSET
, &Data
);
1708 if (EFI_ERROR (Status
)) {
1712 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1713 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1714 if (EFI_ERROR (Status
)) {
1715 return EFI_DEVICE_ERROR
;
1717 return EFI_NOT_FOUND
;
1720 DEBUG ((EFI_D_INFO
, "UfsPassThruDxe: found a attached UFS device\n"));
1726 Allocate common buffer for host and UFS bus master access simultaneously.
1728 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1729 @param[in] Size The length of buffer to be allocated.
1730 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1731 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1732 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1734 @retval EFI_SUCCESS The common buffer was allocated successfully.
1735 @retval EFI_DEVICE_ERROR The allocation fails.
1736 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1740 UfsAllocateAlignCommonBuffer (
1741 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1743 OUT VOID
**CmdDescHost
,
1744 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1745 OUT VOID
**CmdDescMapping
1750 BOOLEAN Is32BitAddr
;
1751 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1753 if ((Private
->Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1754 Is32BitAddr
= FALSE
;
1759 UfsHc
= Private
->UfsHostController
;
1760 Status
= UfsHc
->AllocateBuffer (
1763 EfiBootServicesData
,
1764 EFI_SIZE_TO_PAGES (Size
),
1768 if (EFI_ERROR (Status
)) {
1769 *CmdDescMapping
= NULL
;
1770 *CmdDescHost
= NULL
;
1771 *CmdDescPhyAddr
= 0;
1772 return EFI_OUT_OF_RESOURCES
;
1775 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1776 Status
= UfsHc
->Map (
1778 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1785 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1788 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1791 *CmdDescHost
= NULL
;
1792 return EFI_OUT_OF_RESOURCES
;
1795 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1797 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1805 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1808 *CmdDescMapping
= NULL
;
1809 *CmdDescHost
= NULL
;
1810 return EFI_DEVICE_ERROR
;
1813 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1818 Enable the UFS host controller for accessing.
1820 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1822 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1823 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1827 UfsEnableHostController (
1828 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1835 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1837 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1839 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
1840 if (EFI_ERROR (Status
)) {
1844 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1846 // Write a 0 to the HCE register at first to disable the host controller.
1848 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
1849 if (EFI_ERROR (Status
)) {
1853 // Wait until HCE is read as '0' before continuing.
1855 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1856 if (EFI_ERROR (Status
)) {
1857 return EFI_DEVICE_ERROR
;
1862 // Write a 1 to the HCE register to enable the UFS host controller.
1864 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
);
1865 if (EFI_ERROR (Status
)) {
1870 // Wait until HCE is read as '1' before continuing.
1872 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1873 if (EFI_ERROR (Status
)) {
1874 return EFI_DEVICE_ERROR
;
1881 Detect if a UFS device attached.
1883 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1885 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1886 @retval EFI_NOT_FOUND Not found a UFS device attached.
1887 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1891 UfsDeviceDetection (
1892 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1899 // Start UFS device detection.
1900 // Try up to 3 times for establishing data link with device.
1902 for (Retry
= 0; Retry
< 3; Retry
++) {
1903 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1904 if (!EFI_ERROR (Status
)) {
1908 if (Status
== EFI_NOT_FOUND
) {
1912 return EFI_DEVICE_ERROR
;
1916 return EFI_NOT_FOUND
;
1923 Initialize UFS task management request list related h/w context.
1925 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1927 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1928 @retval EFI_DEVICE_ERROR The initialization fails.
1932 UfsInitTaskManagementRequestList (
1933 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1939 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1940 VOID
*CmdDescMapping
;
1944 // Initial h/w and s/w context for future operations.
1947 CmdDescMapping
= NULL
;
1950 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1951 if (EFI_ERROR (Status
)) {
1955 Private
->Capabilities
= Data
;
1958 // Allocate and initialize UTP Task Management Request List.
1960 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1961 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1962 if (EFI_ERROR (Status
)) {
1967 // Program the UTP Task Management Request List Base Address and UTP Task Management
1968 // Request List Base Address with a 64-bit address allocated at step 6.
1970 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1971 if (EFI_ERROR (Status
)) {
1975 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1976 if (EFI_ERROR (Status
)) {
1979 Private
->UtpTmrlBase
= CmdDescHost
;
1980 Private
->Nutmrs
= Nutmrs
;
1981 Private
->TmrlMapping
= CmdDescMapping
;
1984 // Enable the UTP Task Management Request List by setting the UTP Task Management
1985 // Request List RunStop Register (UTMRLRSR) to '1'.
1987 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
1988 if (EFI_ERROR (Status
)) {
1996 Initialize UFS transfer request list related h/w context.
1998 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2000 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
2001 @retval EFI_DEVICE_ERROR The initialization fails.
2005 UfsInitTransferRequestList (
2006 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2012 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
2013 VOID
*CmdDescMapping
;
2017 // Initial h/w and s/w context for future operations.
2020 CmdDescMapping
= NULL
;
2023 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
2024 if (EFI_ERROR (Status
)) {
2028 Private
->Capabilities
= Data
;
2031 // Allocate and initialize UTP Transfer Request List.
2033 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
2034 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
2035 if (EFI_ERROR (Status
)) {
2040 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
2041 // Base Address with a 64-bit address allocated at step 8.
2043 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
2044 if (EFI_ERROR (Status
)) {
2048 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
2049 if (EFI_ERROR (Status
)) {
2053 Private
->UtpTrlBase
= CmdDescHost
;
2054 Private
->Nutrs
= Nutrs
;
2055 Private
->TrlMapping
= CmdDescMapping
;
2058 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2059 // RunStop Register (UTRLRSR) to '1'.
2061 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
2062 if (EFI_ERROR (Status
)) {
2070 Initialize the UFS host controller.
2072 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2074 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2075 @retval Others A device error occurred while initializing the controller.
2080 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2085 Status
= UfsEnableHostController (Private
);
2086 if (EFI_ERROR (Status
)) {
2087 DEBUG ((EFI_D_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2091 Status
= UfsDeviceDetection (Private
);
2092 if (EFI_ERROR (Status
)) {
2093 DEBUG ((EFI_D_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2097 Status
= UfsInitTaskManagementRequestList (Private
);
2098 if (EFI_ERROR (Status
)) {
2099 DEBUG ((EFI_D_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2103 Status
= UfsInitTransferRequestList (Private
);
2104 if (EFI_ERROR (Status
)) {
2105 DEBUG ((EFI_D_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2109 DEBUG ((EFI_D_INFO
, "UfsControllerInit Finished\n"));
2114 Stop the UFS host controller.
2116 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2118 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2119 @retval Others A device error occurred while stopping the controller.
2124 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2131 // Enable the UTP Task Management Request List by setting the UTP Task Management
2132 // Request List RunStop Register (UTMRLRSR) to '1'.
2134 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2135 if (EFI_ERROR (Status
)) {
2140 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2141 // RunStop Register (UTRLRSR) to '1'.
2143 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2144 if (EFI_ERROR (Status
)) {
2149 // Write a 0 to the HCE register in order to disable the host controller.
2151 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2152 if (EFI_ERROR (Status
)) {
2155 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2157 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2158 if (EFI_ERROR (Status
)) {
2163 // Wait until HCE is read as '0' before continuing.
2165 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2166 if (EFI_ERROR (Status
)) {
2167 return EFI_DEVICE_ERROR
;
2170 DEBUG ((EFI_D_INFO
, "UfsController is stopped\n"));
2177 Internal helper function which will signal the caller event and clean up
2180 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2182 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2189 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
2190 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
2193 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
2194 EFI_EVENT CallerEvent
;
2196 ASSERT ((Private
!= NULL
) && (TransReq
!= NULL
));
2198 UfsHc
= Private
->UfsHostController
;
2199 CallerEvent
= TransReq
->CallerEvent
;
2201 RemoveEntryList (&TransReq
->TransferList
);
2203 UfsHc
->Flush (UfsHc
);
2205 UfsStopExecCmd (Private
, TransReq
->Slot
);
2207 if (TransReq
->DataBufMapping
!= NULL
) {
2208 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
2211 if (TransReq
->CmdDescMapping
!= NULL
) {
2212 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
2214 if (TransReq
->CmdDescHost
!= NULL
) {
2217 EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
),
2218 TransReq
->CmdDescHost
2222 FreePool (TransReq
);
2224 gBS
->SignalEvent (CallerEvent
);
2229 Call back function when the timer event is signaled.
2231 @param[in] Event The Event this notify function registered to.
2232 @param[in] Context Pointer to the context data registered to the Event.
2237 ProcessAsyncTaskList (
2242 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2244 LIST_ENTRY
*NextEntry
;
2245 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
2246 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
;
2247 UTP_RESPONSE_UPIU
*Response
;
2248 UINT16 SenseDataLen
;
2249 UINT32 ResTranCount
;
2254 Private
= (UFS_PASS_THRU_PRIVATE_DATA
*) Context
;
2258 // Check the entries in the async I/O queue are done or not.
2260 if (!IsListEmpty(&Private
->Queue
)) {
2261 EFI_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
2262 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
2263 Packet
= TransReq
->Packet
;
2265 if ((SlotsMap
& (BIT0
<< TransReq
->Slot
)) != 0) {
2268 SlotsMap
|= BIT0
<< TransReq
->Slot
;
2270 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Value
);
2271 if (EFI_ERROR (Status
)) {
2273 // TODO: Should find/add a proper host adapter return status for this
2276 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
2277 DEBUG ((EFI_D_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq
->CallerEvent
));
2278 SignalCallerEvent (Private
, TransReq
);
2282 if ((Value
& (BIT0
<< TransReq
->Slot
)) != 0) {
2284 // Scsi cmd not finished yet.
2286 if (TransReq
->TimeoutRemain
> UFS_HC_ASYNC_TIMER
) {
2287 TransReq
->TimeoutRemain
-= UFS_HC_ASYNC_TIMER
;
2293 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
2294 DEBUG ((EFI_D_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq
->CallerEvent
));
2295 SignalCallerEvent (Private
, TransReq
);
2300 // Scsi cmd finished.
2302 // Get sense data if exists
2304 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
2305 ASSERT (Response
!= NULL
);
2306 SenseDataLen
= Response
->SenseDataLen
;
2307 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
2309 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
2310 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
2311 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
2315 // Check the transfer request result.
2317 Packet
->TargetStatus
= Response
->Status
;
2318 if (Response
->Response
!= 0) {
2319 DEBUG ((EFI_D_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq
->CallerEvent
));
2320 SignalCallerEvent (Private
, TransReq
);
2324 if (TransReq
->Trd
->Ocs
== 0) {
2325 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2326 if ((Response
->Flags
& BIT5
) == BIT5
) {
2327 ResTranCount
= Response
->ResTranCount
;
2328 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2329 Packet
->InTransferLength
-= ResTranCount
;
2332 if ((Response
->Flags
& BIT5
) == BIT5
) {
2333 ResTranCount
= Response
->ResTranCount
;
2334 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2335 Packet
->OutTransferLength
-= ResTranCount
;
2339 DEBUG ((EFI_D_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq
->CallerEvent
));
2340 SignalCallerEvent (Private
, TransReq
);
2344 DEBUG ((EFI_D_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq
->CallerEvent
));
2345 SignalCallerEvent (Private
, TransReq
);