2 UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface
3 for upper layer application to execute UFS-supported SCSI cmds.
5 Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "UfsPassThru.h"
19 Read 32bits data from specified UFS MMIO register.
21 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
22 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
24 @param[out] Value The data buffer to store.
26 @retval EFI_TIMEOUT The operation is time out.
27 @retval EFI_SUCCESS The operation succeeds.
28 @retval Others The operation fails.
33 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
38 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
41 UfsHc
= Private
->UfsHostController
;
43 Status
= UfsHc
->Read (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, Value
);
49 Write 32bits data to specified UFS MMIO register.
51 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
52 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
54 @param[in] Value The data to write.
56 @retval EFI_TIMEOUT The operation is time out.
57 @retval EFI_SUCCESS The operation succeeds.
58 @retval Others The operation fails.
63 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
68 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
71 UfsHc
= Private
->UfsHostController
;
73 Status
= UfsHc
->Write (UfsHc
, EfiUfsHcWidthUint32
, Offset
, 1, &Value
);
79 Wait for the value of the specified system memory set to the test value.
81 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
82 @param[in] Offset The offset within the UFS Host Controller MMIO space to start
84 @param[in] MaskValue The mask value of memory.
85 @param[in] TestValue The test value of memory.
86 @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.
88 @retval EFI_TIMEOUT The system memory setting is time out.
89 @retval EFI_SUCCESS The system memory is correct set.
90 @retval Others The operation fails.
95 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
104 BOOLEAN InfiniteWait
;
110 InfiniteWait
= FALSE
;
113 Delay
= DivU64x32 (Timeout
, 10) + 1;
117 // Access PCI MMIO space to see if the value is the tested one.
119 Status
= UfsMmioRead32 (Private
, Offset
, &Value
);
120 if (EFI_ERROR (Status
)) {
126 if (Value
== TestValue
) {
131 // Stall for 1 microseconds.
133 MicroSecondDelay (1);
137 } while (InfiniteWait
|| (Delay
> 0));
143 Dump UIC command execution result for debugging.
145 @param[in] UicOpcode The executed UIC opcode.
146 @param[in] Result The result to be parsed.
150 DumpUicCmdExecResult (
155 if (UicOpcode
<= UfsUicDmePeerSet
) {
160 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
163 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
166 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
169 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
172 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BAD_INDEX\n"));
175 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
178 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
181 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
184 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - BUSY\n"));
187 DEBUG ((DEBUG_VERBOSE
, "UIC configuration command fails - DME_FAILURE\n"));
198 DEBUG ((DEBUG_VERBOSE
, "UIC control command fails - FAILURE\n"));
208 Dump QUERY RESPONSE UPIU result for debugging.
210 @param[in] Result The result to be parsed.
214 DumpQueryResponseResult (
220 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Not Readable\n"));
223 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Not Writeable\n"));
226 DEBUG ((DEBUG_VERBOSE
, "Query Response with Parameter Already Written\n"));
229 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Length\n"));
232 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Value\n"));
235 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Selector\n"));
238 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Index\n"));
241 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Idn\n"));
244 DEBUG ((DEBUG_VERBOSE
, "Query Response with Invalid Opcode\n"));
247 DEBUG ((DEBUG_VERBOSE
, "Query Response with General Failure\n"));
256 Swap little endian to big endian.
258 @param[in, out] Buffer The data buffer. In input, it contains little endian data.
259 In output, it will become big endian.
260 @param[in] BufferSize The length of converted data.
264 SwapLittleEndianToBigEndian (
265 IN OUT UINT8
*Buffer
,
273 SwapCount
= BufferSize
/ 2;
274 for (Index
= 0; Index
< SwapCount
; Index
++) {
275 Temp
= Buffer
[Index
];
276 Buffer
[Index
] = Buffer
[BufferSize
- 1 - Index
];
277 Buffer
[BufferSize
- 1 - Index
] = Temp
;
282 Fill TSF field of QUERY REQUEST UPIU.
284 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
285 @param[in] Opcode The opcode of request.
286 @param[in] DescId The descriptor ID of request.
287 @param[in] Index The index of request.
288 @param[in] Selector The selector of request.
289 @param[in] Length The length of transferred data. The maximum is 4.
290 @param[in] Value The value of transferred data.
294 UfsFillTsfOfQueryReqUpiu (
295 IN OUT UTP_UPIU_TSF
*TsfBase
,
297 IN UINT8 DescId OPTIONAL
,
298 IN UINT8 Index OPTIONAL
,
299 IN UINT8 Selector OPTIONAL
,
300 IN UINT16 Length OPTIONAL
,
301 IN UINT32 Value OPTIONAL
304 ASSERT (TsfBase
!= NULL
);
305 ASSERT (Opcode
<= UtpQueryFuncOpcodeTogFlag
);
307 TsfBase
->Opcode
= Opcode
;
308 if (Opcode
!= UtpQueryFuncOpcodeNop
) {
309 TsfBase
->DescId
= DescId
;
310 TsfBase
->Index
= Index
;
311 TsfBase
->Selector
= Selector
;
313 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
314 SwapLittleEndianToBigEndian ((UINT8
*)&Length
, sizeof (Length
));
315 TsfBase
->Length
= Length
;
318 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
319 SwapLittleEndianToBigEndian ((UINT8
*)&Value
, sizeof (Value
));
320 TsfBase
->Value
= Value
;
326 Initialize COMMAND UPIU.
328 @param[in, out] Command The base address of COMMAND UPIU.
329 @param[in] Lun The Lun on which the SCSI command is executed.
330 @param[in] TaskTag The task tag of request.
331 @param[in] Cdb The cdb buffer containing SCSI command.
332 @param[in] CdbLength The cdb length.
333 @param[in] DataDirection The direction of data transfer.
334 @param[in] ExpDataTranLen The expected transfer data length.
336 @retval EFI_SUCCESS The initialization succeed.
341 IN OUT UTP_COMMAND_UPIU
*Command
,
346 IN UFS_DATA_DIRECTION DataDirection
,
347 IN UINT32 ExpDataTranLen
352 ASSERT ((Command
!= NULL
) && (Cdb
!= NULL
));
355 // Task attribute is hard-coded to Ordered.
357 if (DataDirection
== UfsDataIn
) {
359 } else if (DataDirection
== UfsDataOut
) {
366 // Fill UTP COMMAND UPIU associated fields.
368 Command
->TransCode
= 0x01;
369 Command
->Flags
= Flags
;
371 Command
->TaskTag
= TaskTag
;
372 Command
->CmdSet
= 0x00;
373 SwapLittleEndianToBigEndian ((UINT8
*)&ExpDataTranLen
, sizeof (ExpDataTranLen
));
374 Command
->ExpDataTranLen
= ExpDataTranLen
;
376 CopyMem (Command
->Cdb
, Cdb
, CdbLength
);
382 Initialize UTP PRDT for data transfer.
384 @param[in] Prdt The base address of PRDT.
385 @param[in] Buffer The buffer to be read or written.
386 @param[in] BufferSize The data size to be read or written.
388 @retval EFI_SUCCESS The initialization succeed.
403 if ((BufferSize
& (BIT0
| BIT1
)) != 0) {
404 BufferSize
&= ~(BIT0
| BIT1
);
405 DEBUG ((DEBUG_WARN
, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize
));
408 if (BufferSize
== 0) {
412 ASSERT (((UINTN
)Buffer
& (BIT0
| BIT1
)) == 0);
414 RemainingLen
= BufferSize
;
416 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)BufferSize
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
418 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
419 if (RemainingLen
< UFS_MAX_DATA_LEN_PER_PRD
) {
420 Prdt
[PrdtIndex
].DbCount
= (UINT32
)RemainingLen
- 1;
422 Prdt
[PrdtIndex
].DbCount
= UFS_MAX_DATA_LEN_PER_PRD
- 1;
425 Prdt
[PrdtIndex
].DbAddr
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 2);
426 Prdt
[PrdtIndex
].DbAddrU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 32);
427 RemainingLen
-= UFS_MAX_DATA_LEN_PER_PRD
;
428 Remaining
+= UFS_MAX_DATA_LEN_PER_PRD
;
435 Initialize QUERY REQUEST UPIU.
437 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
438 @param[in] TaskTag The task tag of request.
439 @param[in] Opcode The opcode of request.
440 @param[in] DescId The descriptor ID of request.
441 @param[in] Index The index of request.
442 @param[in] Selector The selector of request.
443 @param[in] DataSize The data size to be read or written.
444 @param[in] Data The buffer to be read or written.
446 @retval EFI_SUCCESS The initialization succeed.
450 UfsInitQueryRequestUpiu (
451 IN OUT UTP_QUERY_REQ_UPIU
*QueryReq
,
457 IN UINTN DataSize OPTIONAL
,
458 IN UINT8
*Data OPTIONAL
461 ASSERT (QueryReq
!= NULL
);
463 QueryReq
->TransCode
= 0x16;
464 QueryReq
->TaskTag
= TaskTag
;
465 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeRdFlag
) || (Opcode
== UtpQueryFuncOpcodeRdAttr
)) {
466 QueryReq
->QueryFunc
= QUERY_FUNC_STD_READ_REQ
;
468 QueryReq
->QueryFunc
= QUERY_FUNC_STD_WRITE_REQ
;
471 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
472 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, *(UINT32
*)Data
);
473 } else if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
474 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, (UINT16
)DataSize
, 0);
476 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, 0);
479 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
480 CopyMem (QueryReq
+ 1, Data
, DataSize
);
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 DataSize
= Packet
->TransferLength
;
606 Data
= Packet
->DataBuffer
;
608 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
609 if (DataSize
== 0 || Data
== NULL
) {
610 return EFI_INVALID_PARAMETER
;
612 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
614 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
617 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
618 if (EFI_ERROR (Status
)) {
623 // Initialize UTP QUERY REQUEST UPIU
625 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)*CmdDescHost
;
626 ASSERT (QueryReqUpiu
!= NULL
);
627 UfsInitQueryRequestUpiu (
639 // Fill UTP_TRD associated fields
640 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
642 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
643 Trd
->Dd
= DataDirection
;
644 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
645 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
646 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
647 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
648 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
649 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
650 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
652 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
), sizeof (UINT32
));
653 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
660 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
662 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
663 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
664 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
665 @param[out] CmdDescMapping A resulting value to pass to Unmap().
667 @retval EFI_SUCCESS The creation succeed.
668 @retval EFI_DEVICE_ERROR The creation failed.
669 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
673 UfsCreateNopCommandDesc (
674 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
676 OUT VOID
**CmdDescHost
,
677 OUT VOID
**CmdDescMapping
681 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
683 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
685 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
687 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
688 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
689 if (EFI_ERROR (Status
)) {
693 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)*CmdDescHost
;
694 ASSERT (NopOutUpiu
!= NULL
);
695 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
698 // Fill UTP_TRD associated fields
699 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
701 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
703 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
704 Trd
->Ocs
= UFS_HC_TRD_OCS_INIT_VALUE
;
705 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
706 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
707 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
708 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
714 Find out available slot in transfer list of a UFS device.
716 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
717 @param[out] Slot The available slot.
719 @retval EFI_SUCCESS The available slot was found successfully.
720 @retval EFI_NOT_READY No slot is available at this moment.
724 UfsFindAvailableSlotInTrl (
725 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
734 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
736 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
737 if (EFI_ERROR (Status
)) {
741 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
743 for (Index
= 0; Index
< Nutrs
; Index
++) {
744 if ((Data
& (BIT0
<< Index
)) == 0) {
750 return EFI_NOT_READY
;
754 Find out available slot in task management transfer list of a UFS device.
756 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
757 @param[out] Slot The available slot.
759 @retval EFI_SUCCESS The available slot was found successfully.
763 UfsFindAvailableSlotInTmrl (
764 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
768 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
771 // The simplest algo to always use slot 0.
772 // TODO: enhance it to support async transfer with multiple slot.
780 Start specified slot in transfer list of a UFS device.
782 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
783 @param[in] Slot The slot to be started.
788 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
795 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLRSR_OFFSET
, &Data
);
796 if (EFI_ERROR (Status
)) {
800 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
801 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
802 if (EFI_ERROR (Status
)) {
807 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
);
808 if (EFI_ERROR (Status
)) {
816 Stop specified slot in transfer list of a UFS device.
818 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
819 @param[in] Slot The slot to be stop.
824 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
831 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Data
);
832 if (EFI_ERROR (Status
)) {
836 if ((Data
& (BIT0
<< Slot
)) != 0) {
837 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLCLR_OFFSET
, &Data
);
838 if (EFI_ERROR (Status
)) {
842 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLCLR_OFFSET
, Data
& ~(BIT0
<< Slot
));
843 if (EFI_ERROR (Status
)) {
852 Extracts return data from query response upiu.
854 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
855 @param[in] QueryResp Pointer to the query response.
857 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.
858 @retval EFI_SUCCESS Data extracted.
862 UfsGetReturnDataFromQueryResponse (
863 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
864 IN UTP_QUERY_RESP_UPIU
*QueryResp
867 UINT16 ReturnDataSize
;
870 if (Packet
== NULL
|| QueryResp
== NULL
) {
871 return EFI_INVALID_PARAMETER
;
874 switch (Packet
->Opcode
) {
875 case UtpQueryFuncOpcodeRdDesc
:
876 ReturnDataSize
= QueryResp
->Tsf
.Length
;
877 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
878 CopyMem (Packet
->DataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
879 Packet
->TransferLength
= ReturnDataSize
;
881 case UtpQueryFuncOpcodeWrDesc
:
882 ReturnDataSize
= QueryResp
->Tsf
.Length
;
883 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
884 Packet
->TransferLength
= ReturnDataSize
;
886 case UtpQueryFuncOpcodeRdFlag
:
887 case UtpQueryFuncOpcodeSetFlag
:
888 case UtpQueryFuncOpcodeClrFlag
:
889 case UtpQueryFuncOpcodeTogFlag
:
890 CopyMem (Packet
->DataBuffer
, &QueryResp
->Tsf
.Value
, sizeof (UINT8
));
892 case UtpQueryFuncOpcodeRdAttr
:
893 case UtpQueryFuncOpcodeWrAttr
:
894 ReturnData
= QueryResp
->Tsf
.Value
;
895 SwapLittleEndianToBigEndian ((UINT8
*) &ReturnData
, sizeof (UINT32
));
896 CopyMem (Packet
->DataBuffer
, &ReturnData
, sizeof (UINT32
));
899 return EFI_INVALID_PARAMETER
;
906 Creates Transfer Request descriptor and sends Query Request to the device.
908 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
909 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.
911 @retval EFI_SUCCESS The device descriptor was read/written successfully.
912 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
913 combination to point to a type of UFS device descriptor.
914 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
915 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
919 UfsSendDmRequestRetry (
920 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
921 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
927 VOID
*CmdDescMapping
;
929 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
930 UTP_QUERY_RESP_UPIU
*QueryResp
;
934 // Find out which slot of transfer request list is available.
936 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
937 if (EFI_ERROR (Status
)) {
941 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
943 // Fill transfer request descriptor to this slot.
945 Status
= UfsCreateDMCommandDesc (Private
, Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
946 if (EFI_ERROR (Status
)) {
947 DEBUG ((DEBUG_ERROR
, "Failed to create DM command descriptor\n"));
951 UfsHc
= Private
->UfsHostController
;
952 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
953 ASSERT (QueryResp
!= NULL
);
954 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
957 // Start to execute the transfer request.
959 UfsStartExecCmd (Private
, Slot
);
962 // Wait for the completion of the transfer request.
964 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
, 0, Packet
->Timeout
);
965 if (EFI_ERROR (Status
)) {
969 if (Trd
->Ocs
!= 0 || QueryResp
->QueryResp
!= UfsUtpQueryResponseSuccess
) {
970 DEBUG ((DEBUG_ERROR
, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd
->Ocs
, QueryResp
->QueryResp
));
971 DumpQueryResponseResult (QueryResp
->QueryResp
);
973 if ((QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidSelector
) ||
974 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIndex
) ||
975 (QueryResp
->QueryResp
== UfsUtpQueryResponseInvalidIdn
)) {
976 Status
= EFI_INVALID_PARAMETER
;
978 Status
= EFI_DEVICE_ERROR
;
983 Status
= UfsGetReturnDataFromQueryResponse (Packet
, QueryResp
);
984 if (EFI_ERROR (Status
)) {
985 DEBUG ((DEBUG_ERROR
, "Failed to get return data from query response\n"));
990 UfsHc
->Flush (UfsHc
);
992 UfsStopExecCmd (Private
, Slot
);
994 if (CmdDescMapping
!= NULL
) {
995 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
997 if (CmdDescHost
!= NULL
) {
998 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1005 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.
1007 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.
1008 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.
1010 @retval EFI_SUCCESS The device responded correctly to the Query request.
1011 @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid
1012 combination to point to a type of UFS device descriptor.
1013 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.
1014 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.
1019 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1020 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
1026 Status
= EFI_SUCCESS
;
1028 for (Retry
= 0; Retry
< 5; Retry
++) {
1029 Status
= UfsSendDmRequestRetry (Private
, Packet
);
1030 if (!EFI_ERROR (Status
)) {
1035 DEBUG ((DEBUG_ERROR
, "Failed to get response from the device after %d retries\n", Retry
));
1040 Read or write specified device descriptor of a UFS device.
1042 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1043 @param[in] Read The boolean variable to show r/w direction.
1044 @param[in] DescId The ID of device descriptor.
1045 @param[in] Index The Index of device descriptor.
1046 @param[in] Selector The Selector of device descriptor.
1047 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
1048 @param[in, out] DescSize The size of device descriptor buffer. On input, the size, in bytes,
1049 of the data buffer specified by Descriptor. On output, the number
1050 of bytes that were actually transferred.
1052 @retval EFI_SUCCESS The device descriptor was read/written successfully.
1053 @retval EFI_INVALID_PARAMETER DescId, Index and Selector are invalid combination to point to a
1054 type of UFS device descriptor.
1055 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
1056 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
1061 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1066 IN OUT VOID
*Descriptor
,
1067 IN OUT UINT32
*DescSize
1070 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1073 if (DescSize
== NULL
) {
1074 return EFI_INVALID_PARAMETER
;
1077 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1080 Packet
.DataDirection
= UfsDataIn
;
1081 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
1083 Packet
.DataDirection
= UfsDataOut
;
1084 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
1086 Packet
.DataBuffer
= Descriptor
;
1087 Packet
.TransferLength
= *DescSize
;
1088 Packet
.DescId
= DescId
;
1089 Packet
.Index
= Index
;
1090 Packet
.Selector
= Selector
;
1091 Packet
.Timeout
= UFS_TIMEOUT
;
1093 Status
= UfsSendDmRequest (Private
, &Packet
);
1094 if (EFI_ERROR (Status
)) {
1097 *DescSize
= Packet
.TransferLength
;
1104 Read or write specified attribute of a UFS device.
1106 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1107 @param[in] Read The boolean variable to show r/w direction.
1108 @param[in] AttrId The ID of Attribute.
1109 @param[in] Index The Index of Attribute.
1110 @param[in] Selector The Selector of Attribute.
1111 @param[in, out] Attributes The value of Attribute to be read or written.
1113 @retval EFI_SUCCESS The Attribute was read/written successfully.
1114 @retval EFI_INVALID_PARAMETER AttrId, Index and Selector are invalid combination to point to a
1115 type of UFS device descriptor.
1116 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
1117 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
1122 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1127 IN OUT UINT32
*Attributes
1130 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1132 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1135 Packet
.DataDirection
= UfsDataIn
;
1136 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
1138 Packet
.DataDirection
= UfsDataOut
;
1139 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
1141 Packet
.DataBuffer
= Attributes
;
1142 Packet
.DescId
= AttrId
;
1143 Packet
.Index
= Index
;
1144 Packet
.Selector
= Selector
;
1145 Packet
.Timeout
= UFS_TIMEOUT
;
1147 return UfsSendDmRequest (Private
, &Packet
);
1151 Read or write specified flag of a UFS device.
1153 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1154 @param[in] Read The boolean variable to show r/w direction.
1155 @param[in] FlagId The ID of flag to be read or written.
1156 @param[in, out] Value The value to set or clear flag.
1158 @retval EFI_SUCCESS The flag was read/written successfully.
1159 @retval EFI_INVALID_PARAMETER FlagId is an invalid UFS flag ID.
1160 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1161 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1166 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1172 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1174 if (Value
== NULL
) {
1175 return EFI_INVALID_PARAMETER
;
1178 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1181 ASSERT (Value
!= NULL
);
1182 Packet
.DataDirection
= UfsDataIn
;
1183 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1185 Packet
.DataDirection
= UfsDataOut
;
1187 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1188 } else if (*Value
== 0) {
1189 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1191 return EFI_INVALID_PARAMETER
;
1194 Packet
.DataBuffer
= Value
;
1195 Packet
.DescId
= FlagId
;
1197 Packet
.Selector
= 0;
1198 Packet
.Timeout
= UFS_TIMEOUT
;
1200 return UfsSendDmRequest (Private
, &Packet
);
1204 Set specified flag to 1 on a UFS device.
1206 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1207 @param[in] FlagId The ID of flag to be set.
1209 @retval EFI_SUCCESS The flag was set successfully.
1210 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1211 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1216 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1224 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1230 Clear specified flag to 0 on a UFS device.
1232 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1233 @param[in] FlagId The ID of flag to be cleared.
1235 @retval EFI_SUCCESS The flag was cleared successfully.
1236 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1237 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1242 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1250 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1256 Read specified flag from a UFS device.
1258 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1259 @param[in] FlagId The ID of flag to be read.
1260 @param[out] Value The flag's value.
1262 @retval EFI_SUCCESS The flag was read successfully.
1263 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1264 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1269 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1276 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1282 Sends NOP IN cmd to a UFS device for initialization process request.
1283 For more details, please refer to UFS 2.0 spec Figure 13.3.
1285 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1287 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1288 received successfully.
1289 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1290 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1291 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1296 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1302 UTP_NOP_IN_UPIU
*NopInUpiu
;
1305 VOID
*CmdDescMapping
;
1306 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1309 // Find out which slot of transfer request list is available.
1311 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1312 if (EFI_ERROR (Status
)) {
1316 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1317 Status
= UfsCreateNopCommandDesc (Private
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1318 if (EFI_ERROR (Status
)) {
1323 // Check the transfer request result.
1325 UfsHc
= Private
->UfsHostController
;
1326 NopInUpiu
= (UTP_NOP_IN_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1327 ASSERT (NopInUpiu
!= NULL
);
1328 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1331 // Start to execute the transfer request.
1333 UfsStartExecCmd (Private
, Slot
);
1336 // Wait for the completion of the transfer request.
1338 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< Slot
, 0, UFS_TIMEOUT
);
1339 if (EFI_ERROR (Status
)) {
1343 if (NopInUpiu
->Resp
!= 0) {
1344 Status
= EFI_DEVICE_ERROR
;
1346 Status
= EFI_SUCCESS
;
1350 UfsHc
->Flush (UfsHc
);
1352 UfsStopExecCmd (Private
, Slot
);
1354 if (CmdDescMapping
!= NULL
) {
1355 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1357 if (CmdDescHost
!= NULL
) {
1358 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1365 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1367 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1368 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1369 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1371 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking
1372 I/O is performed. If Event is NULL, then blocking I/O is performed. If
1373 Event is not NULL and non blocking I/O is supported, then
1374 nonblocking I/O is performed, and Event will be signaled when the
1375 SCSI Request Packet completes.
1377 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1378 commands, InTransferLength bytes were transferred from
1379 InDataBuffer. For write and bi-directional commands,
1380 OutTransferLength bytes were transferred by
1382 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1384 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1385 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1390 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1392 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
1393 IN EFI_EVENT Event OPTIONAL
1397 UTP_RESPONSE_UPIU
*Response
;
1398 UINT16 SenseDataLen
;
1399 UINT32 ResTranCount
;
1401 EFI_PHYSICAL_ADDRESS DataBufPhyAddr
;
1404 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1405 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag
;
1406 UTP_TR_PRD
*PrdtBase
;
1408 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
1410 TransReq
= AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ
));
1411 if (TransReq
== NULL
) {
1412 return EFI_OUT_OF_RESOURCES
;
1415 TransReq
->Signature
= UFS_PASS_THRU_TRANS_REQ_SIG
;
1416 TransReq
->TimeoutRemain
= Packet
->Timeout
;
1418 UfsHc
= Private
->UfsHostController
;
1420 // Find out which slot of transfer request list is available.
1422 Status
= UfsFindAvailableSlotInTrl (Private
, &TransReq
->Slot
);
1423 if (EFI_ERROR (Status
)) {
1427 TransReq
->Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + TransReq
->Slot
;
1430 // Fill transfer request descriptor to this slot.
1432 Status
= UfsCreateScsiCommandDesc (
1437 &TransReq
->CmdDescHost
,
1438 &TransReq
->CmdDescMapping
1440 if (EFI_ERROR (Status
)) {
1444 TransReq
->CmdDescSize
= TransReq
->Trd
->PrdtO
* sizeof (UINT32
) + TransReq
->Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1446 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1447 DataBuf
= Packet
->InDataBuffer
;
1448 DataLen
= Packet
->InTransferLength
;
1449 Flag
= EdkiiUfsHcOperationBusMasterWrite
;
1451 DataBuf
= Packet
->OutDataBuffer
;
1452 DataLen
= Packet
->OutTransferLength
;
1453 Flag
= EdkiiUfsHcOperationBusMasterRead
;
1457 MapLength
= DataLen
;
1458 Status
= UfsHc
->Map (
1464 &TransReq
->DataBufMapping
1467 if (EFI_ERROR (Status
) || (DataLen
!= MapLength
)) {
1472 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1474 PrdtBase
= (UTP_TR_PRD
*)((UINT8
*)TransReq
->CmdDescHost
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
1475 ASSERT (PrdtBase
!= NULL
);
1476 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)DataBufPhyAddr
, DataLen
);
1479 // Insert the async SCSI cmd to the Async I/O list
1481 if (Event
!= NULL
) {
1482 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1483 TransReq
->Packet
= Packet
;
1484 TransReq
->CallerEvent
= Event
;
1485 InsertTailList (&Private
->Queue
, &TransReq
->TransferList
);
1486 gBS
->RestoreTPL (OldTpl
);
1490 // Start to execute the transfer request.
1492 UfsStartExecCmd (Private
, TransReq
->Slot
);
1495 // Immediately return for async I/O.
1497 if (Event
!= NULL
) {
1502 // Wait for the completion of the transfer request.
1504 Status
= UfsWaitMemSet (Private
, UFS_HC_UTRLDBR_OFFSET
, BIT0
<< TransReq
->Slot
, 0, Packet
->Timeout
);
1505 if (EFI_ERROR (Status
)) {
1510 // Get sense data if exists
1512 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
1513 ASSERT (Response
!= NULL
);
1514 SenseDataLen
= Response
->SenseDataLen
;
1515 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1517 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1518 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1519 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1523 // Check the transfer request result.
1525 Packet
->TargetStatus
= Response
->Status
;
1526 if (Response
->Response
!= 0) {
1527 DEBUG ((DEBUG_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1528 Status
= EFI_DEVICE_ERROR
;
1532 if (TransReq
->Trd
->Ocs
== 0) {
1533 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1534 if ((Response
->Flags
& BIT5
) == BIT5
) {
1535 ResTranCount
= Response
->ResTranCount
;
1536 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1537 Packet
->InTransferLength
-= ResTranCount
;
1540 if ((Response
->Flags
& BIT5
) == BIT5
) {
1541 ResTranCount
= Response
->ResTranCount
;
1542 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1543 Packet
->OutTransferLength
-= ResTranCount
;
1547 Status
= EFI_DEVICE_ERROR
;
1551 UfsHc
->Flush (UfsHc
);
1553 UfsStopExecCmd (Private
, TransReq
->Slot
);
1555 if (TransReq
->DataBufMapping
!= NULL
) {
1556 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
1560 if (TransReq
->CmdDescMapping
!= NULL
) {
1561 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
1563 if (TransReq
->CmdDescHost
!= NULL
) {
1564 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
), TransReq
->CmdDescHost
);
1566 if (TransReq
!= NULL
) {
1567 FreePool (TransReq
);
1574 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1576 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1577 @param[in] UicOpcode The opcode of the UIC command.
1578 @param[in] Arg1 The value for 1st argument of the UIC command.
1579 @param[in] Arg2 The value for 2nd argument of the UIC command.
1580 @param[in] Arg3 The value for 3rd argument of the UIC command.
1582 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1583 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1584 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1588 UfsExecUicCommands (
1589 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1599 Status
= UfsMmioRead32 (Private
, UFS_HC_IS_OFFSET
, &Data
);
1600 if (EFI_ERROR (Status
)) {
1604 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1606 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1608 Status
= UfsMmioWrite32 (Private
, UFS_HC_IS_OFFSET
, Data
);
1609 if (EFI_ERROR (Status
)) {
1615 // When programming UIC command registers, host software shall set the register UICCMD
1616 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1619 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG1_OFFSET
, Arg1
);
1620 if (EFI_ERROR (Status
)) {
1624 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, Arg2
);
1625 if (EFI_ERROR (Status
)) {
1629 Status
= UfsMmioWrite32 (Private
, UFS_HC_UCMD_ARG3_OFFSET
, Arg3
);
1630 if (EFI_ERROR (Status
)) {
1635 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1637 Status
= UfsWaitMemSet (Private
, UFS_HC_STATUS_OFFSET
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1638 if (EFI_ERROR (Status
)) {
1642 Status
= UfsMmioWrite32 (Private
, UFS_HC_UIC_CMD_OFFSET
, (UINT32
)UicOpcode
);
1643 if (EFI_ERROR (Status
)) {
1648 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1649 // This bit is set to '1' by the host controller upon completion of a UIC command.
1651 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1652 if (EFI_ERROR (Status
)) {
1656 if (UicOpcode
!= UfsUicDmeReset
) {
1657 Status
= UfsMmioRead32 (Private
, UFS_HC_UCMD_ARG2_OFFSET
, &Data
);
1658 if (EFI_ERROR (Status
)) {
1661 if ((Data
& 0xFF) != 0) {
1663 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1665 return EFI_DEVICE_ERROR
;
1670 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1672 Status
= UfsMmioRead32 (Private
, UFS_HC_STATUS_OFFSET
, &Data
);
1673 if (EFI_ERROR (Status
)) {
1677 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1678 Status
= UfsWaitMemSet (Private
, UFS_HC_IS_OFFSET
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1679 if (EFI_ERROR (Status
)) {
1680 return EFI_DEVICE_ERROR
;
1682 return EFI_NOT_FOUND
;
1685 DEBUG ((DEBUG_INFO
, "UfsPassThruDxe: found a attached UFS device\n"));
1691 Allocate common buffer for host and UFS bus master access simultaneously.
1693 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1694 @param[in] Size The length of buffer to be allocated.
1695 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1696 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1697 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1699 @retval EFI_SUCCESS The common buffer was allocated successfully.
1700 @retval EFI_DEVICE_ERROR The allocation fails.
1701 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1705 UfsAllocateAlignCommonBuffer (
1706 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1708 OUT VOID
**CmdDescHost
,
1709 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1710 OUT VOID
**CmdDescMapping
1715 BOOLEAN Is32BitAddr
;
1716 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1718 if ((Private
->Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1719 Is32BitAddr
= FALSE
;
1724 UfsHc
= Private
->UfsHostController
;
1725 Status
= UfsHc
->AllocateBuffer (
1728 EfiBootServicesData
,
1729 EFI_SIZE_TO_PAGES (Size
),
1733 if (EFI_ERROR (Status
)) {
1734 *CmdDescMapping
= NULL
;
1735 *CmdDescHost
= NULL
;
1736 *CmdDescPhyAddr
= 0;
1737 return EFI_OUT_OF_RESOURCES
;
1740 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1741 Status
= UfsHc
->Map (
1743 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1750 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1753 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1756 *CmdDescHost
= NULL
;
1757 return EFI_OUT_OF_RESOURCES
;
1760 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1762 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1770 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1773 *CmdDescMapping
= NULL
;
1774 *CmdDescHost
= NULL
;
1775 return EFI_DEVICE_ERROR
;
1778 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1783 Enable the UFS host controller for accessing.
1785 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1787 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1788 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1792 UfsEnableHostController (
1793 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1800 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1802 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1804 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
1805 if (EFI_ERROR (Status
)) {
1809 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1811 // Write a 0 to the HCE register at first to disable the host controller.
1813 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
1814 if (EFI_ERROR (Status
)) {
1818 // Wait until HCE is read as '0' before continuing.
1820 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1821 if (EFI_ERROR (Status
)) {
1822 return EFI_DEVICE_ERROR
;
1827 // Write a 1 to the HCE register to enable the UFS host controller.
1829 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
);
1830 if (EFI_ERROR (Status
)) {
1835 // Wait until HCE is read as '1' before continuing.
1837 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1838 if (EFI_ERROR (Status
)) {
1839 return EFI_DEVICE_ERROR
;
1846 Detect if a UFS device attached.
1848 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1850 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1851 @retval EFI_NOT_FOUND Not found a UFS device attached.
1852 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1856 UfsDeviceDetection (
1857 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1864 // Start UFS device detection.
1865 // Try up to 3 times for establishing data link with device.
1867 for (Retry
= 0; Retry
< 3; Retry
++) {
1868 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1869 if (!EFI_ERROR (Status
)) {
1873 if (Status
== EFI_NOT_FOUND
) {
1877 return EFI_DEVICE_ERROR
;
1881 return EFI_NOT_FOUND
;
1888 Initialize UFS task management request list related h/w context.
1890 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1892 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1893 @retval EFI_DEVICE_ERROR The initialization fails.
1897 UfsInitTaskManagementRequestList (
1898 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1904 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1905 VOID
*CmdDescMapping
;
1909 // Initial h/w and s/w context for future operations.
1912 CmdDescMapping
= NULL
;
1915 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1916 if (EFI_ERROR (Status
)) {
1920 Private
->Capabilities
= Data
;
1923 // Allocate and initialize UTP Task Management Request List.
1925 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1926 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1927 if (EFI_ERROR (Status
)) {
1932 // Program the UTP Task Management Request List Base Address and UTP Task Management
1933 // Request List Base Address with a 64-bit address allocated at step 6.
1935 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1936 if (EFI_ERROR (Status
)) {
1940 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1941 if (EFI_ERROR (Status
)) {
1944 Private
->UtpTmrlBase
= CmdDescHost
;
1945 Private
->Nutmrs
= Nutmrs
;
1946 Private
->TmrlMapping
= CmdDescMapping
;
1949 // Enable the UTP Task Management Request List by setting the UTP Task Management
1950 // Request List RunStop Register (UTMRLRSR) to '1'.
1952 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, UFS_HC_UTMRLRSR
);
1953 if (EFI_ERROR (Status
)) {
1961 Initialize UFS transfer request list related h/w context.
1963 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1965 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1966 @retval EFI_DEVICE_ERROR The initialization fails.
1970 UfsInitTransferRequestList (
1971 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1977 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1978 VOID
*CmdDescMapping
;
1982 // Initial h/w and s/w context for future operations.
1985 CmdDescMapping
= NULL
;
1988 Status
= UfsMmioRead32 (Private
, UFS_HC_CAP_OFFSET
, &Data
);
1989 if (EFI_ERROR (Status
)) {
1993 Private
->Capabilities
= Data
;
1996 // Allocate and initialize UTP Transfer Request List.
1998 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1999 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
2000 if (EFI_ERROR (Status
)) {
2005 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
2006 // Base Address with a 64-bit address allocated at step 8.
2008 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBA_OFFSET
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
2009 if (EFI_ERROR (Status
)) {
2013 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLBAU_OFFSET
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
2014 if (EFI_ERROR (Status
)) {
2018 Private
->UtpTrlBase
= CmdDescHost
;
2019 Private
->Nutrs
= Nutrs
;
2020 Private
->TrlMapping
= CmdDescMapping
;
2023 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2024 // RunStop Register (UTRLRSR) to '1'.
2026 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, UFS_HC_UTRLRSR
);
2027 if (EFI_ERROR (Status
)) {
2035 Initialize the UFS host controller.
2037 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2039 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
2040 @retval Others A device error occurred while initializing the controller.
2045 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2050 Status
= UfsEnableHostController (Private
);
2051 if (EFI_ERROR (Status
)) {
2052 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
2056 Status
= UfsDeviceDetection (Private
);
2057 if (EFI_ERROR (Status
)) {
2058 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
2062 Status
= UfsInitTaskManagementRequestList (Private
);
2063 if (EFI_ERROR (Status
)) {
2064 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
2068 Status
= UfsInitTransferRequestList (Private
);
2069 if (EFI_ERROR (Status
)) {
2070 DEBUG ((DEBUG_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
2074 DEBUG ((DEBUG_INFO
, "UfsControllerInit Finished\n"));
2079 Stop the UFS host controller.
2081 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
2083 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
2084 @retval Others A device error occurred while stopping the controller.
2089 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
2096 // Enable the UTP Task Management Request List by setting the UTP Task Management
2097 // Request List RunStop Register (UTMRLRSR) to '1'.
2099 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTMRLRSR_OFFSET
, 0);
2100 if (EFI_ERROR (Status
)) {
2105 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
2106 // RunStop Register (UTRLRSR) to '1'.
2108 Status
= UfsMmioWrite32 (Private
, UFS_HC_UTRLRSR_OFFSET
, 0);
2109 if (EFI_ERROR (Status
)) {
2114 // Write a 0 to the HCE register in order to disable the host controller.
2116 Status
= UfsMmioRead32 (Private
, UFS_HC_ENABLE_OFFSET
, &Data
);
2117 if (EFI_ERROR (Status
)) {
2120 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
2122 Status
= UfsMmioWrite32 (Private
, UFS_HC_ENABLE_OFFSET
, 0);
2123 if (EFI_ERROR (Status
)) {
2128 // Wait until HCE is read as '0' before continuing.
2130 Status
= UfsWaitMemSet (Private
, UFS_HC_ENABLE_OFFSET
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
2131 if (EFI_ERROR (Status
)) {
2132 return EFI_DEVICE_ERROR
;
2135 DEBUG ((DEBUG_INFO
, "UfsController is stopped\n"));
2142 Internal helper function which will signal the caller event and clean up
2145 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data
2147 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data
2154 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
2155 IN UFS_PASS_THRU_TRANS_REQ
*TransReq
2158 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
2159 EFI_EVENT CallerEvent
;
2161 ASSERT ((Private
!= NULL
) && (TransReq
!= NULL
));
2163 UfsHc
= Private
->UfsHostController
;
2164 CallerEvent
= TransReq
->CallerEvent
;
2166 RemoveEntryList (&TransReq
->TransferList
);
2168 UfsHc
->Flush (UfsHc
);
2170 UfsStopExecCmd (Private
, TransReq
->Slot
);
2172 if (TransReq
->DataBufMapping
!= NULL
) {
2173 UfsHc
->Unmap (UfsHc
, TransReq
->DataBufMapping
);
2176 if (TransReq
->CmdDescMapping
!= NULL
) {
2177 UfsHc
->Unmap (UfsHc
, TransReq
->CmdDescMapping
);
2179 if (TransReq
->CmdDescHost
!= NULL
) {
2182 EFI_SIZE_TO_PAGES (TransReq
->CmdDescSize
),
2183 TransReq
->CmdDescHost
2187 FreePool (TransReq
);
2189 gBS
->SignalEvent (CallerEvent
);
2194 Call back function when the timer event is signaled.
2196 @param[in] Event The Event this notify function registered to.
2197 @param[in] Context Pointer to the context data registered to the Event.
2202 ProcessAsyncTaskList (
2207 UFS_PASS_THRU_PRIVATE_DATA
*Private
;
2209 LIST_ENTRY
*NextEntry
;
2210 UFS_PASS_THRU_TRANS_REQ
*TransReq
;
2211 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
;
2212 UTP_RESPONSE_UPIU
*Response
;
2213 UINT16 SenseDataLen
;
2214 UINT32 ResTranCount
;
2219 Private
= (UFS_PASS_THRU_PRIVATE_DATA
*) Context
;
2223 // Check the entries in the async I/O queue are done or not.
2225 if (!IsListEmpty(&Private
->Queue
)) {
2226 EFI_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &Private
->Queue
) {
2227 TransReq
= UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry
);
2228 Packet
= TransReq
->Packet
;
2230 if ((SlotsMap
& (BIT0
<< TransReq
->Slot
)) != 0) {
2233 SlotsMap
|= BIT0
<< TransReq
->Slot
;
2235 Status
= UfsMmioRead32 (Private
, UFS_HC_UTRLDBR_OFFSET
, &Value
);
2236 if (EFI_ERROR (Status
)) {
2238 // TODO: Should find/add a proper host adapter return status for this
2241 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
;
2242 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq
->CallerEvent
));
2243 SignalCallerEvent (Private
, TransReq
);
2247 if ((Value
& (BIT0
<< TransReq
->Slot
)) != 0) {
2249 // Scsi cmd not finished yet.
2251 if (TransReq
->TimeoutRemain
> UFS_HC_ASYNC_TIMER
) {
2252 TransReq
->TimeoutRemain
-= UFS_HC_ASYNC_TIMER
;
2258 Packet
->HostAdapterStatus
= EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
;
2259 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq
->CallerEvent
));
2260 SignalCallerEvent (Private
, TransReq
);
2265 // Scsi cmd finished.
2267 // Get sense data if exists
2269 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)TransReq
->CmdDescHost
+ TransReq
->Trd
->RuO
* sizeof (UINT32
));
2270 ASSERT (Response
!= NULL
);
2271 SenseDataLen
= Response
->SenseDataLen
;
2272 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
2274 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
2275 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
2276 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
2280 // Check the transfer request result.
2282 Packet
->TargetStatus
= Response
->Status
;
2283 if (Response
->Response
!= 0) {
2284 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq
->CallerEvent
));
2285 SignalCallerEvent (Private
, TransReq
);
2289 if (TransReq
->Trd
->Ocs
== 0) {
2290 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
2291 if ((Response
->Flags
& BIT5
) == BIT5
) {
2292 ResTranCount
= Response
->ResTranCount
;
2293 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2294 Packet
->InTransferLength
-= ResTranCount
;
2297 if ((Response
->Flags
& BIT5
) == BIT5
) {
2298 ResTranCount
= Response
->ResTranCount
;
2299 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
2300 Packet
->OutTransferLength
-= ResTranCount
;
2304 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq
->CallerEvent
));
2305 SignalCallerEvent (Private
, TransReq
);
2309 DEBUG ((DEBUG_VERBOSE
, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq
->CallerEvent
));
2310 SignalCallerEvent (Private
, TransReq
);