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, 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 Wait for the value of the specified system memory set to the test value.
21 @param Address The system memory address to test.
22 @param MaskValue The mask value of memory.
23 @param TestValue The test value of memory.
24 @param Timeout The time out value for wait memory set, uses 100ns as a unit.
26 @retval EFI_TIMEOUT The system memory setting is time out.
27 @retval EFI_SUCCESS The system memory is correct set.
49 Delay
= DivU64x32 (Timeout
, 10) + 1;
53 // Access PCI MMIO space to see if the value is the tested one.
55 Value
= MmioRead32 (Address
) & MaskValue
;
57 if (Value
== TestValue
) {
62 // Stall for 1 microseconds.
68 } while (InfiniteWait
|| (Delay
> 0));
74 Dump UIC command execution result for debugging.
76 @param[in] UicOpcode The executed UIC opcode.
77 @param[in] Result The result to be parsed.
81 DumpUicCmdExecResult (
86 if (UicOpcode
<= UfsUicDmePeerSet
) {
91 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));
94 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));
97 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));
100 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));
103 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BAD_INDEX\n"));
106 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));
109 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));
112 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));
115 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - BUSY\n"));
118 DEBUG ((EFI_D_VERBOSE
, "UIC configuration command fails - DME_FAILURE\n"));
129 DEBUG ((EFI_D_VERBOSE
, "UIC control command fails - FAILURE\n"));
139 Dump QUERY RESPONSE UPIU result for debugging.
141 @param[in] Result The result to be parsed.
145 DumpQueryResponseResult (
151 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Not Readable\n"));
154 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Not Writeable\n"));
157 DEBUG ((EFI_D_VERBOSE
, "Query Response with Parameter Already Written\n"));
160 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Length\n"));
163 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Value\n"));
166 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Selector\n"));
169 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Index\n"));
172 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Idn\n"));
175 DEBUG ((EFI_D_VERBOSE
, "Query Response with Invalid Opcode\n"));
178 DEBUG ((EFI_D_VERBOSE
, "Query Response with General Failure\n"));
187 Swap little endian to big endian.
189 @param[in, out] Buffer The data buffer. In input, it contains little endian data.
190 In output, it will become big endian.
191 @param[in] BufferSize The length of converted data.
195 SwapLittleEndianToBigEndian (
196 IN OUT UINT8
*Buffer
,
204 SwapCount
= BufferSize
/ 2;
205 for (Index
= 0; Index
< SwapCount
; Index
++) {
206 Temp
= Buffer
[Index
];
207 Buffer
[Index
] = Buffer
[BufferSize
- 1 - Index
];
208 Buffer
[BufferSize
- 1 - Index
] = Temp
;
213 Fill TSF field of QUERY REQUEST UPIU.
215 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.
216 @param[in] Opcode The opcode of request.
217 @param[in] DescId The descriptor ID of request.
218 @param[in] Index The index of request.
219 @param[in] Selector The selector of request.
220 @param[in] Length The length of transferred data. The maximum is 4.
221 @param[in] Value The value of transferred data.
225 UfsFillTsfOfQueryReqUpiu (
226 IN OUT UTP_UPIU_TSF
*TsfBase
,
228 IN UINT8 DescId OPTIONAL
,
229 IN UINT8 Index OPTIONAL
,
230 IN UINT8 Selector OPTIONAL
,
231 IN UINT16 Length OPTIONAL
,
232 IN UINT32 Value OPTIONAL
235 ASSERT (TsfBase
!= NULL
);
236 ASSERT (Opcode
<= UtpQueryFuncOpcodeTogFlag
);
238 TsfBase
->Opcode
= Opcode
;
239 if (Opcode
!= UtpQueryFuncOpcodeNop
) {
240 TsfBase
->DescId
= DescId
;
241 TsfBase
->Index
= Index
;
242 TsfBase
->Selector
= Selector
;
244 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
245 SwapLittleEndianToBigEndian ((UINT8
*)&Length
, sizeof (Length
));
246 TsfBase
->Length
= Length
;
249 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
250 SwapLittleEndianToBigEndian ((UINT8
*)&Value
, sizeof (Value
));
251 TsfBase
->Value
= Value
;
257 Initialize COMMAND UPIU.
259 @param[in, out] Command The base address of COMMAND UPIU.
260 @param[in] Lun The Lun on which the SCSI command is executed.
261 @param[in] TaskTag The task tag of request.
262 @param[in] Cdb The cdb buffer containing SCSI command.
263 @param[in] CdbLength The cdb length.
264 @param[in] DataDirection The direction of data transfer.
265 @param[in] ExpDataTranLen The expected transfer data length.
267 @retval EFI_SUCCESS The initialization succeed.
272 IN OUT UTP_COMMAND_UPIU
*Command
,
277 IN UFS_DATA_DIRECTION DataDirection
,
278 IN UINT32 ExpDataTranLen
283 ASSERT ((Command
!= NULL
) && (Cdb
!= NULL
));
286 // Task attribute is hard-coded to Ordered.
288 if (DataDirection
== UfsDataIn
) {
290 } else if (DataDirection
== UfsDataOut
) {
297 // Fill UTP COMMAND UPIU associated fields.
299 Command
->TransCode
= 0x01;
300 Command
->Flags
= Flags
;
302 Command
->TaskTag
= TaskTag
;
303 Command
->CmdSet
= 0x00;
304 SwapLittleEndianToBigEndian ((UINT8
*)&ExpDataTranLen
, sizeof (ExpDataTranLen
));
305 Command
->ExpDataTranLen
= ExpDataTranLen
;
307 CopyMem (Command
->Cdb
, Cdb
, CdbLength
);
313 Initialize UTP PRDT for data transfer.
315 @param[in] Prdt The base address of PRDT.
316 @param[in] Buffer The buffer to be read or written.
317 @param[in] BufferSize The data size to be read or written.
319 @retval EFI_SUCCESS The initialization succeed.
334 if (BufferSize
== 0) {
338 ASSERT (((UINTN
)Buffer
& (BIT0
| BIT1
)) == 0);
340 RemainingLen
= BufferSize
;
342 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)BufferSize
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
344 for (PrdtIndex
= 0; PrdtIndex
< PrdtNumber
; PrdtIndex
++) {
345 if (RemainingLen
< UFS_MAX_DATA_LEN_PER_PRD
) {
346 Prdt
[PrdtIndex
].DbCount
= (UINT32
)RemainingLen
- 1;
348 Prdt
[PrdtIndex
].DbCount
= UFS_MAX_DATA_LEN_PER_PRD
- 1;
351 Prdt
[PrdtIndex
].DbAddr
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 2);
352 Prdt
[PrdtIndex
].DbAddrU
= (UINT32
)RShiftU64 ((UINT64
)(UINTN
)Remaining
, 32);
353 RemainingLen
-= UFS_MAX_DATA_LEN_PER_PRD
;
354 Remaining
+= UFS_MAX_DATA_LEN_PER_PRD
;
361 Initialize QUERY REQUEST UPIU.
363 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.
364 @param[in] TaskTag The task tag of request.
365 @param[in] Opcode The opcode of request.
366 @param[in] DescId The descriptor ID of request.
367 @param[in] Index The index of request.
368 @param[in] Selector The selector of request.
369 @param[in] DataSize The data size to be read or written.
370 @param[in] Data The buffer to be read or written.
372 @retval EFI_SUCCESS The initialization succeed.
376 UfsInitQueryRequestUpiu (
377 IN OUT UTP_QUERY_REQ_UPIU
*QueryReq
,
383 IN UINTN DataSize OPTIONAL
,
384 IN UINT8
*Data OPTIONAL
387 ASSERT (QueryReq
!= NULL
);
389 QueryReq
->TransCode
= 0x16;
390 QueryReq
->TaskTag
= TaskTag
;
391 if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeRdFlag
) || (Opcode
== UtpQueryFuncOpcodeRdAttr
)) {
392 QueryReq
->QueryFunc
= QUERY_FUNC_STD_READ_REQ
;
394 QueryReq
->QueryFunc
= QUERY_FUNC_STD_WRITE_REQ
;
397 if (Opcode
== UtpQueryFuncOpcodeWrAttr
) {
398 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, *(UINT32
*)Data
);
399 } else if ((Opcode
== UtpQueryFuncOpcodeRdDesc
) || (Opcode
== UtpQueryFuncOpcodeWrDesc
)) {
400 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, (UINT16
)DataSize
, 0);
402 UfsFillTsfOfQueryReqUpiu (&QueryReq
->Tsf
, Opcode
, DescId
, Index
, Selector
, 0, 0);
405 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
406 CopyMem (QueryReq
+ 1, Data
, DataSize
);
413 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.
415 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
416 @param[in] Lun The Lun on which the SCSI command is executed.
417 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.
418 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
419 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
420 @param[out] CmdDescMapping A resulting value to pass to Unmap().
422 @retval EFI_SUCCESS The creation succeed.
423 @retval EFI_DEVICE_ERROR The creation failed.
424 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
428 UfsCreateScsiCommandDesc (
429 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
431 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
,
433 OUT VOID
**CmdDescHost
,
434 OUT VOID
**CmdDescMapping
439 UTP_COMMAND_UPIU
*CommandUpiu
;
440 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
443 UFS_DATA_DIRECTION DataDirection
;
445 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
447 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
448 DataLen
= Packet
->InTransferLength
;
449 DataDirection
= UfsDataIn
;
451 DataLen
= Packet
->OutTransferLength
;
452 DataDirection
= UfsDataOut
;
456 DataDirection
= UfsNoData
;
459 PrdtNumber
= (UINTN
)DivU64x32 ((UINT64
)DataLen
+ UFS_MAX_DATA_LEN_PER_PRD
- 1, UFS_MAX_DATA_LEN_PER_PRD
);
461 TotalLen
= ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)) + PrdtNumber
* sizeof (UTP_TR_PRD
);
463 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
464 if (EFI_ERROR (Status
)) {
468 CommandUpiu
= (UTP_COMMAND_UPIU
*)*CmdDescHost
;
470 UfsInitCommandUpiu (CommandUpiu
, Lun
, Private
->TaskTag
++, Packet
->Cdb
, Packet
->CdbLength
, DataDirection
, DataLen
);
473 // Fill UTP_TRD associated fields
474 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table
475 // *MUST* be located at a 64-bit aligned boundary.
477 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
478 Trd
->Dd
= DataDirection
;
479 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
480 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
481 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
482 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)), sizeof (UINT32
));
483 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)), sizeof (UINT32
));
484 Trd
->PrdtL
= (UINT16
)PrdtNumber
;
485 Trd
->PrdtO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
))), sizeof (UINT32
));
490 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.
492 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
493 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.
494 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
495 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
496 @param[out] CmdDescMapping A resulting value to pass to Unmap().
498 @retval EFI_SUCCESS The creation succeed.
499 @retval EFI_DEVICE_ERROR The creation failed.
500 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
501 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.
505 UfsCreateDMCommandDesc (
506 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
507 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
*Packet
,
509 OUT VOID
**CmdDescHost
,
510 OUT VOID
**CmdDescMapping
514 UTP_QUERY_REQ_UPIU
*QueryReqUpiu
;
519 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
522 ASSERT ((Private
!= NULL
) && (Packet
!= NULL
) && (Trd
!= NULL
));
524 Opcode
= Packet
->Opcode
;
525 if ((Opcode
> UtpQueryFuncOpcodeTogFlag
) || (Opcode
== UtpQueryFuncOpcodeNop
)) {
526 return EFI_INVALID_PARAMETER
;
529 DataDirection
= Packet
->DataDirection
;
530 if (DataDirection
== UfsDataIn
) {
531 DataSize
= Packet
->InTransferLength
;
532 Data
= Packet
->InDataBuffer
;
533 } else if (DataDirection
== UfsDataOut
) {
534 DataSize
= Packet
->OutTransferLength
;
535 Data
= Packet
->OutDataBuffer
;
541 if (((Opcode
!= UtpQueryFuncOpcodeSetFlag
) && (Opcode
!= UtpQueryFuncOpcodeClrFlag
) && (Opcode
!= UtpQueryFuncOpcodeTogFlag
))
542 && ((DataSize
== 0) || (Data
== NULL
))) {
543 return EFI_INVALID_PARAMETER
;
546 if (((Opcode
== UtpQueryFuncOpcodeSetFlag
) || (Opcode
== UtpQueryFuncOpcodeClrFlag
) || (Opcode
== UtpQueryFuncOpcodeTogFlag
))
547 && ((DataSize
!= 0) || (Data
!= NULL
))) {
548 return EFI_INVALID_PARAMETER
;
551 if ((Opcode
== UtpQueryFuncOpcodeWrAttr
) && (DataSize
!= sizeof (UINT32
))) {
552 return EFI_INVALID_PARAMETER
;
555 if ((Opcode
== UtpQueryFuncOpcodeWrDesc
) || (Opcode
== UtpQueryFuncOpcodeRdDesc
)) {
556 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
);
558 TotalLen
= ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
));
561 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
562 if (EFI_ERROR (Status
)) {
567 // Initialize UTP QUERY REQUEST UPIU
569 QueryReqUpiu
= (UTP_QUERY_REQ_UPIU
*)*CmdDescHost
;
570 ASSERT (QueryReqUpiu
!= NULL
);
571 UfsInitQueryRequestUpiu (
583 // Fill UTP_TRD associated fields
584 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.
586 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
587 Trd
->Dd
= DataDirection
;
588 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
590 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
591 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
592 if (Opcode
== UtpQueryFuncOpcodeWrDesc
) {
593 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)), sizeof (UINT32
));
594 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)) + ROUNDUP8 (DataSize
)), sizeof (UINT32
));
596 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)(ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU
)) + ROUNDUP8 (DataSize
)), sizeof (UINT32
));
597 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU
)), sizeof (UINT32
));
604 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.
606 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
607 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.
608 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
609 @param[out] CmdDescMapping A resulting value to pass to Unmap().
611 @retval EFI_SUCCESS The creation succeed.
612 @retval EFI_DEVICE_ERROR The creation failed.
613 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
617 UfsCreateNopCommandDesc (
618 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
620 OUT VOID
**CmdDescHost
,
621 OUT VOID
**CmdDescMapping
625 UTP_NOP_OUT_UPIU
*NopOutUpiu
;
627 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
629 ASSERT ((Private
!= NULL
) && (Trd
!= NULL
));
631 TotalLen
= ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
));
632 Status
= UfsAllocateAlignCommonBuffer (Private
, TotalLen
, CmdDescHost
, &CmdDescPhyAddr
, CmdDescMapping
);
633 if (EFI_ERROR (Status
)) {
637 NopOutUpiu
= (UTP_NOP_OUT_UPIU
*)*CmdDescHost
;
638 ASSERT (NopOutUpiu
!= NULL
);
639 NopOutUpiu
->TaskTag
= Private
->TaskTag
++;
642 // Fill UTP_TRD associated fields
643 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.
645 Trd
->Int
= UFS_INTERRUPT_COMMAND
;
647 Trd
->Ct
= UFS_STORAGE_COMMAND_TYPE
;
648 Trd
->UcdBa
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 7);
649 Trd
->UcdBaU
= (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32);
650 Trd
->RuL
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU
)), sizeof (UINT32
));
651 Trd
->RuO
= (UINT16
)DivU64x32 ((UINT64
)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU
)), sizeof (UINT32
));
657 Find out available slot in transfer list of a UFS device.
659 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
660 @param[out] Slot The available slot.
662 @retval EFI_SUCCESS The available slot was found successfully.
666 UfsFindAvailableSlotInTrl (
667 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
671 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
674 // The simplest algo to always use slot 0.
675 // TODO: enhance it to support async transfer with multiple slot.
683 Find out available slot in task management transfer list of a UFS device.
685 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
686 @param[out] Slot The available slot.
688 @retval EFI_SUCCESS The available slot was found successfully.
692 UfsFindAvailableSlotInTmrl (
693 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
697 ASSERT ((Private
!= NULL
) && (Slot
!= NULL
));
700 // The simplest algo to always use slot 0.
701 // TODO: enhance it to support async transfer with multiple slot.
709 Start specified slot in transfer list of a UFS device.
711 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
712 @param[in] Slot The slot to be started.
717 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
725 UfsHcBase
= Private
->UfsHcBase
;
727 Address
= UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
728 Data
= MmioRead32 (Address
);
729 if ((Data
& UFS_HC_UTRLRSR
) != UFS_HC_UTRLRSR
) {
730 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
733 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
734 MmioWrite32 (Address
, BIT0
<< Slot
);
738 Stop specified slot in transfer list of a UFS device.
740 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
741 @param[in] Slot The slot to be stop.
746 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
754 UfsHcBase
= Private
->UfsHcBase
;
756 Address
= UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
757 Data
= MmioRead32 (Address
);
758 if ((Data
& (BIT0
<< Slot
)) != 0) {
759 Address
= UfsHcBase
+ UFS_HC_UTRLCLR_OFFSET
;
760 Data
= MmioRead32 (Address
);
761 MmioWrite32 (Address
, (Data
& ~(BIT0
<< Slot
)));
766 Read or write specified device descriptor of a UFS device.
768 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
769 @param[in] Read The boolean variable to show r/w direction.
770 @param[in] DescId The ID of device descriptor.
771 @param[in] Index The Index of device descriptor.
772 @param[in] Selector The Selector of device descriptor.
773 @param[in, out] Descriptor The buffer of device descriptor to be read or written.
774 @param[in] DescSize The size of device descriptor buffer.
776 @retval EFI_SUCCESS The device descriptor was read/written successfully.
777 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.
778 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.
783 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
788 IN OUT VOID
*Descriptor
,
793 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
797 UTP_QUERY_RESP_UPIU
*QueryResp
;
799 UINT16 ReturnDataSize
;
801 VOID
*CmdDescMapping
;
802 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
804 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
807 Packet
.DataDirection
= UfsDataIn
;
808 Packet
.InDataBuffer
= Descriptor
;
809 Packet
.InTransferLength
= DescSize
;
810 Packet
.Opcode
= UtpQueryFuncOpcodeRdDesc
;
812 Packet
.DataDirection
= UfsDataOut
;
813 Packet
.OutDataBuffer
= Descriptor
;
814 Packet
.OutTransferLength
= DescSize
;
815 Packet
.Opcode
= UtpQueryFuncOpcodeWrDesc
;
817 Packet
.DescId
= DescId
;
818 Packet
.Index
= Index
;
819 Packet
.Selector
= Selector
;
820 Packet
.Timeout
= UFS_TIMEOUT
;
823 // Find out which slot of transfer request list is available.
825 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
826 if (EFI_ERROR (Status
)) {
830 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
832 // Fill transfer request descriptor to this slot.
834 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
835 if (EFI_ERROR (Status
)) {
840 // Check the transfer request result.
842 UfsHc
= Private
->UfsHostController
;
843 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
844 ASSERT (QueryResp
!= NULL
);
845 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
848 // Start to execute the transfer request.
850 UfsStartExecCmd (Private
, Slot
);
853 // Wait for the completion of the transfer request.
855 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
856 Status
= UfsWaitMemSet (Address
, BIT0
, 0, Packet
.Timeout
);
857 if (EFI_ERROR (Status
)) {
861 if (QueryResp
->QueryResp
!= 0) {
862 DumpQueryResponseResult (QueryResp
->QueryResp
);
863 Status
= EFI_DEVICE_ERROR
;
868 ReturnDataSize
= QueryResp
->Tsf
.Length
;
869 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnDataSize
, sizeof (UINT16
));
872 CopyMem (Packet
.InDataBuffer
, (QueryResp
+ 1), ReturnDataSize
);
873 Packet
.InTransferLength
= ReturnDataSize
;
875 Packet
.OutTransferLength
= ReturnDataSize
;
878 Status
= EFI_DEVICE_ERROR
;
882 UfsHc
->Flush (UfsHc
);
884 UfsStopExecCmd (Private
, Slot
);
886 if (CmdDescMapping
!= NULL
) {
887 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
889 if (CmdDescHost
!= NULL
) {
890 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
897 Read or write specified attribute of a UFS device.
899 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
900 @param[in] Read The boolean variable to show r/w direction.
901 @param[in] AttrId The ID of Attribute.
902 @param[in] Index The Index of Attribute.
903 @param[in] Selector The Selector of Attribute.
904 @param[in, out] Attributes The value of Attribute to be read or written.
906 @retval EFI_SUCCESS The Attribute was read/written successfully.
907 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.
908 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.
913 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
918 IN OUT UINT32
*Attributes
922 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
926 UTP_QUERY_RESP_UPIU
*QueryResp
;
930 VOID
*CmdDescMapping
;
931 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
933 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
936 Packet
.DataDirection
= UfsDataIn
;
937 Packet
.Opcode
= UtpQueryFuncOpcodeRdAttr
;
939 Packet
.DataDirection
= UfsDataOut
;
940 Packet
.Opcode
= UtpQueryFuncOpcodeWrAttr
;
942 Packet
.DescId
= AttrId
;
943 Packet
.Index
= Index
;
944 Packet
.Selector
= Selector
;
945 Packet
.Timeout
= UFS_TIMEOUT
;
948 // Find out which slot of transfer request list is available.
950 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
951 if (EFI_ERROR (Status
)) {
955 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
957 // Fill transfer request descriptor to this slot.
959 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
960 if (EFI_ERROR (Status
)) {
965 // Check the transfer request result.
967 UfsHc
= Private
->UfsHostController
;
968 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
969 ASSERT (QueryResp
!= NULL
);
970 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
973 // Start to execute the transfer request.
975 UfsStartExecCmd (Private
, Slot
);
978 // Wait for the completion of the transfer request.
980 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
981 Status
= UfsWaitMemSet (Address
, BIT0
, 0, Packet
.Timeout
);
982 if (EFI_ERROR (Status
)) {
986 if (QueryResp
->QueryResp
!= 0) {
987 DumpQueryResponseResult (QueryResp
->QueryResp
);
988 Status
= EFI_DEVICE_ERROR
;
993 ReturnData
= QueryResp
->Tsf
.Value
;
994 SwapLittleEndianToBigEndian ((UINT8
*)&ReturnData
, sizeof (UINT32
));
995 *Attributes
= ReturnData
;
997 Status
= EFI_DEVICE_ERROR
;
1001 UfsHc
->Flush (UfsHc
);
1003 UfsStopExecCmd (Private
, Slot
);
1005 if (CmdDescMapping
!= NULL
) {
1006 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1009 if (CmdDescHost
!= NULL
) {
1010 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1017 Read or write specified flag of a UFS device.
1019 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1020 @param[in] Read The boolean variable to show r/w direction.
1021 @param[in] FlagId The ID of flag to be read or written.
1022 @param[in, out] Value The value to set or clear flag.
1024 @retval EFI_SUCCESS The flag was read/written successfully.
1025 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.
1026 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.
1031 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1038 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet
;
1042 UTP_QUERY_RESP_UPIU
*QueryResp
;
1045 VOID
*CmdDescMapping
;
1046 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1048 if (Value
== NULL
) {
1049 return EFI_INVALID_PARAMETER
;
1052 ZeroMem (&Packet
, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET
));
1055 ASSERT (Value
!= NULL
);
1056 Packet
.DataDirection
= UfsDataIn
;
1057 Packet
.Opcode
= UtpQueryFuncOpcodeRdFlag
;
1059 Packet
.DataDirection
= UfsDataOut
;
1061 Packet
.Opcode
= UtpQueryFuncOpcodeSetFlag
;
1062 } else if (*Value
== 0) {
1063 Packet
.Opcode
= UtpQueryFuncOpcodeClrFlag
;
1065 return EFI_INVALID_PARAMETER
;
1068 Packet
.DescId
= FlagId
;
1070 Packet
.Selector
= 0;
1071 Packet
.Timeout
= UFS_TIMEOUT
;
1074 // Find out which slot of transfer request list is available.
1076 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1077 if (EFI_ERROR (Status
)) {
1082 // Fill transfer request descriptor to this slot.
1084 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1085 Status
= UfsCreateDMCommandDesc (Private
, &Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1086 if (EFI_ERROR (Status
)) {
1091 // Check the transfer request result.
1093 UfsHc
= Private
->UfsHostController
;
1094 QueryResp
= (UTP_QUERY_RESP_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1095 ASSERT (QueryResp
!= NULL
);
1096 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1099 // Start to execute the transfer request.
1101 UfsStartExecCmd (Private
, Slot
);
1104 // Wait for the completion of the transfer request.
1106 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1107 Status
= UfsWaitMemSet (Address
, BIT0
, 0, Packet
.Timeout
);
1108 if (EFI_ERROR (Status
)) {
1112 if (QueryResp
->QueryResp
!= 0) {
1113 DumpQueryResponseResult (QueryResp
->QueryResp
);
1114 Status
= EFI_DEVICE_ERROR
;
1118 if (Trd
->Ocs
== 0) {
1119 *Value
= (UINT8
)QueryResp
->Tsf
.Value
;
1121 Status
= EFI_DEVICE_ERROR
;
1125 UfsHc
->Flush (UfsHc
);
1127 UfsStopExecCmd (Private
, Slot
);
1129 if (CmdDescMapping
!= NULL
) {
1130 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1132 if (CmdDescHost
!= NULL
) {
1133 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1140 Set specified flag to 1 on a UFS device.
1142 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1143 @param[in] FlagId The ID of flag to be set.
1145 @retval EFI_SUCCESS The flag was set successfully.
1146 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.
1147 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.
1152 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1160 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1166 Clear specified flag to 0 on a UFS device.
1168 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1169 @param[in] FlagId The ID of flag to be cleared.
1171 @retval EFI_SUCCESS The flag was cleared successfully.
1172 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.
1173 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.
1178 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1186 Status
= UfsRwFlags (Private
, FALSE
, FlagId
, &Value
);
1192 Read specified flag from a UFS device.
1194 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1195 @param[in] FlagId The ID of flag to be read.
1196 @param[out] Value The flag's value.
1198 @retval EFI_SUCCESS The flag was read successfully.
1199 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.
1200 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.
1205 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1212 Status
= UfsRwFlags (Private
, TRUE
, FlagId
, Value
);
1218 Sends NOP IN cmd to a UFS device for initialization process request.
1219 For more details, please refer to UFS 2.0 spec Figure 13.3.
1221 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1223 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was
1224 received successfully.
1225 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.
1226 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1227 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.
1232 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1238 UTP_NOP_IN_UPIU
*NopInUpiu
;
1242 VOID
*CmdDescMapping
;
1243 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1246 // Find out which slot of transfer request list is available.
1248 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1249 if (EFI_ERROR (Status
)) {
1253 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1254 Status
= UfsCreateNopCommandDesc (Private
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1255 if (EFI_ERROR (Status
)) {
1260 // Check the transfer request result.
1262 UfsHc
= Private
->UfsHostController
;
1263 NopInUpiu
= (UTP_NOP_IN_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1264 ASSERT (NopInUpiu
!= NULL
);
1265 CmdDescSize
= Trd
->RuO
* sizeof (UINT32
) + Trd
->RuL
* sizeof (UINT32
);
1268 // Start to execute the transfer request.
1270 UfsStartExecCmd (Private
, Slot
);
1273 // Wait for the completion of the transfer request.
1275 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1276 Status
= UfsWaitMemSet (Address
, BIT0
, 0, UFS_TIMEOUT
);
1277 if (EFI_ERROR (Status
)) {
1281 if (NopInUpiu
->Resp
!= 0) {
1282 Status
= EFI_DEVICE_ERROR
;
1284 Status
= EFI_SUCCESS
;
1288 UfsHc
->Flush (UfsHc
);
1290 UfsStopExecCmd (Private
, Slot
);
1292 if (CmdDescMapping
!= NULL
) {
1293 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1295 if (CmdDescHost
!= NULL
) {
1296 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1303 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.
1305 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1306 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.
1307 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the
1310 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional
1311 commands, InTransferLength bytes were transferred from
1312 InDataBuffer. For write and bi-directional commands,
1313 OutTransferLength bytes were transferred by
1315 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request
1317 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.
1318 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
1323 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1325 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*Packet
1333 UTP_RESPONSE_UPIU
*Response
;
1334 UINT16 SenseDataLen
;
1335 UINT32 ResTranCount
;
1337 VOID
*CmdDescMapping
;
1338 VOID
*DataBufMapping
;
1340 EFI_PHYSICAL_ADDRESS DataBufPhyAddr
;
1343 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1344 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag
;
1345 UFS_DATA_DIRECTION DataDirection
;
1346 UTP_TR_PRD
*PrdtBase
;
1350 CmdDescMapping
= NULL
;
1351 DataBufMapping
= NULL
;
1353 UfsHc
= Private
->UfsHostController
;
1355 // Find out which slot of transfer request list is available.
1357 Status
= UfsFindAvailableSlotInTrl (Private
, &Slot
);
1358 if (EFI_ERROR (Status
)) {
1362 Trd
= ((UTP_TRD
*)Private
->UtpTrlBase
) + Slot
;
1365 // Fill transfer request descriptor to this slot.
1367 Status
= UfsCreateScsiCommandDesc (Private
, Lun
, Packet
, Trd
, &CmdDescHost
, &CmdDescMapping
);
1368 if (EFI_ERROR (Status
)) {
1372 CmdDescSize
= Trd
->PrdtO
* sizeof (UINT32
) + Trd
->PrdtL
* sizeof (UTP_TR_PRD
);
1374 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1375 DataBuf
= Packet
->InDataBuffer
;
1376 DataLen
= Packet
->InTransferLength
;
1377 DataDirection
= UfsDataIn
;
1378 Flag
= EdkiiUfsHcOperationBusMasterWrite
;
1380 DataBuf
= Packet
->OutDataBuffer
;
1381 DataLen
= Packet
->OutTransferLength
;
1382 DataDirection
= UfsDataOut
;
1383 Flag
= EdkiiUfsHcOperationBusMasterRead
;
1387 DataDirection
= UfsNoData
;
1389 MapLength
= DataLen
;
1390 Status
= UfsHc
->Map (
1399 if (EFI_ERROR (Status
) || (DataLen
!= MapLength
)) {
1404 // Fill PRDT table of Command UPIU for executed SCSI cmd.
1406 PrdtBase
= (UTP_TR_PRD
*)((UINT8
*)CmdDescHost
+ ROUNDUP8 (sizeof (UTP_COMMAND_UPIU
)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU
)));
1407 ASSERT (PrdtBase
!= NULL
);
1408 UfsInitUtpPrdt (PrdtBase
, (VOID
*)(UINTN
)DataBufPhyAddr
, DataLen
);
1411 // Start to execute the transfer request.
1413 UfsStartExecCmd (Private
, Slot
);
1416 // Wait for the completion of the transfer request.
1418 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLDBR_OFFSET
;
1419 Status
= UfsWaitMemSet (Address
, BIT0
, 0, Packet
->Timeout
);
1420 if (EFI_ERROR (Status
)) {
1425 // Get sense data if exists
1427 Response
= (UTP_RESPONSE_UPIU
*)((UINT8
*)CmdDescHost
+ Trd
->RuO
* sizeof (UINT32
));
1428 ASSERT (Response
!= NULL
);
1429 SenseDataLen
= Response
->SenseDataLen
;
1430 SwapLittleEndianToBigEndian ((UINT8
*)&SenseDataLen
, sizeof (UINT16
));
1432 if ((Packet
->SenseDataLength
!= 0) && (Packet
->SenseData
!= NULL
)) {
1433 CopyMem (Packet
->SenseData
, Response
->SenseData
, SenseDataLen
);
1434 Packet
->SenseDataLength
= (UINT8
)SenseDataLen
;
1438 // Check the transfer request result.
1440 Packet
->TargetStatus
= Response
->Status
;
1441 if (Response
->Response
!= 0) {
1442 DEBUG ((EFI_D_ERROR
, "UfsExecScsiCmds() fails with Target Failure\n"));
1443 Status
= EFI_DEVICE_ERROR
;
1447 if (Trd
->Ocs
== 0) {
1448 if (Packet
->DataDirection
== EFI_EXT_SCSI_DATA_DIRECTION_READ
) {
1449 if ((Response
->Flags
& BIT5
) == BIT5
) {
1450 ResTranCount
= Response
->ResTranCount
;
1451 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1452 Packet
->InTransferLength
-= ResTranCount
;
1455 if ((Response
->Flags
& BIT5
) == BIT5
) {
1456 ResTranCount
= Response
->ResTranCount
;
1457 SwapLittleEndianToBigEndian ((UINT8
*)&ResTranCount
, sizeof (UINT32
));
1458 Packet
->OutTransferLength
-= ResTranCount
;
1462 Status
= EFI_DEVICE_ERROR
;
1466 UfsHc
->Flush (UfsHc
);
1468 UfsStopExecCmd (Private
, Slot
);
1470 if (DataBufMapping
!= NULL
) {
1471 UfsHc
->Unmap (UfsHc
, DataBufMapping
);
1475 if (CmdDescMapping
!= NULL
) {
1476 UfsHc
->Unmap (UfsHc
, CmdDescMapping
);
1478 if (CmdDescHost
!= NULL
) {
1479 UfsHc
->FreeBuffer (UfsHc
, EFI_SIZE_TO_PAGES (CmdDescSize
), CmdDescHost
);
1486 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
1488 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1489 @param[in] UicOpcode The opcode of the UIC command.
1490 @param[in] Arg1 The value for 1st argument of the UIC command.
1491 @param[in] Arg2 The value for 2nd argument of the UIC command.
1492 @param[in] Arg3 The value for 3rd argument of the UIC command.
1494 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.
1495 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.
1496 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.
1500 UfsExecUicCommands (
1501 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1513 UfsHcBase
= Private
->UfsHcBase
;
1514 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1515 Data
= MmioRead32 (Address
);
1516 if ((Data
& UFS_HC_IS_UCCS
) == UFS_HC_IS_UCCS
) {
1518 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.
1520 MmioWrite32 (Address
, Data
);
1524 // When programming UIC command registers, host software shall set the register UICCMD
1525 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)
1528 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG1_OFFSET
;
1529 MmioWrite32 (Address
, Arg1
);
1531 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1532 MmioWrite32 (Address
, Arg2
);
1534 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG3_OFFSET
;
1535 MmioWrite32 (Address
, Arg3
);
1538 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.
1540 Address
= Private
->UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1541 Status
= UfsWaitMemSet (Address
, UFS_HC_HCS_UCRDY
, UFS_HC_HCS_UCRDY
, UFS_TIMEOUT
);
1542 if (EFI_ERROR (Status
)) {
1546 Address
= UfsHcBase
+ UFS_HC_UIC_CMD_OFFSET
;
1547 MmioWrite32 (Address
, (UINT32
)UicOpcode
);
1550 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)
1551 // This bit is set to '1' by the host controller upon completion of a UIC command.
1553 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1554 Data
= MmioRead32 (Address
);
1555 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_UCCS
, UFS_HC_IS_UCCS
, UFS_TIMEOUT
);
1556 if (EFI_ERROR (Status
)) {
1560 if (UicOpcode
!= UfsUicDmeReset
) {
1561 Address
= UfsHcBase
+ UFS_HC_UCMD_ARG2_OFFSET
;
1562 Data
= MmioRead32 (Address
);
1563 if ((Data
& 0xFF) != 0) {
1565 DumpUicCmdExecResult (UicOpcode
, (UINT8
)(Data
& 0xFF));
1567 return EFI_DEVICE_ERROR
;
1572 // Check value of HCS.DP and make sure that there is a device attached to the Link.
1574 Address
= UfsHcBase
+ UFS_HC_STATUS_OFFSET
;
1575 Data
= MmioRead32 (Address
);
1576 if ((Data
& UFS_HC_HCS_DP
) == 0) {
1577 Address
= UfsHcBase
+ UFS_HC_IS_OFFSET
;
1578 Status
= UfsWaitMemSet (Address
, UFS_HC_IS_ULSS
, UFS_HC_IS_ULSS
, UFS_TIMEOUT
);
1579 if (EFI_ERROR (Status
)) {
1580 return EFI_DEVICE_ERROR
;
1582 return EFI_NOT_FOUND
;
1585 DEBUG ((EFI_D_INFO
, "UfsPassThruDxe: found a attached UFS device\n"));
1591 Allocate common buffer for host and UFS bus master access simultaneously.
1593 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1594 @param[in] Size The length of buffer to be allocated.
1595 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.
1596 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.
1597 @param[out] CmdDescMapping A resulting value to pass to Unmap().
1599 @retval EFI_SUCCESS The common buffer was allocated successfully.
1600 @retval EFI_DEVICE_ERROR The allocation fails.
1601 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.
1605 UfsAllocateAlignCommonBuffer (
1606 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
,
1608 OUT VOID
**CmdDescHost
,
1609 OUT EFI_PHYSICAL_ADDRESS
*CmdDescPhyAddr
,
1610 OUT VOID
**CmdDescMapping
1615 BOOLEAN Is32BitAddr
;
1616 EDKII_UFS_HOST_CONTROLLER_PROTOCOL
*UfsHc
;
1618 if ((Private
->Capabilities
& UFS_HC_CAP_64ADDR
) == UFS_HC_CAP_64ADDR
) {
1621 Is32BitAddr
= FALSE
;
1624 UfsHc
= Private
->UfsHostController
;
1625 Status
= UfsHc
->AllocateBuffer (
1628 EfiBootServicesData
,
1629 EFI_SIZE_TO_PAGES (Size
),
1633 if (EFI_ERROR (Status
)) {
1634 *CmdDescMapping
= NULL
;
1635 *CmdDescHost
= NULL
;
1636 *CmdDescPhyAddr
= 0;
1637 return EFI_OUT_OF_RESOURCES
;
1640 Bytes
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
));
1641 Status
= UfsHc
->Map (
1643 EdkiiUfsHcOperationBusMasterCommonBuffer
,
1650 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)))) {
1653 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1656 *CmdDescHost
= NULL
;
1657 return EFI_OUT_OF_RESOURCES
;
1660 if (Is32BitAddr
&& ((*CmdDescPhyAddr
) > 0x100000000ULL
)) {
1662 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.
1670 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)),
1673 *CmdDescMapping
= NULL
;
1674 *CmdDescHost
= NULL
;
1675 return EFI_DEVICE_ERROR
;
1678 ZeroMem (*CmdDescHost
, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size
)));
1683 Enable the UFS host controller for accessing.
1685 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1687 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.
1688 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.
1692 UfsEnableHostController (
1693 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1701 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization
1703 // Reinitialize the UFS host controller if HCE bit of HC register is set.
1705 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1706 Data
= MmioRead32 (Address
);
1707 if ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
) {
1709 // Write a 0 to the HCE register at first to disable the host controller.
1711 MmioWrite32 (Address
, 0);
1713 // Wait until HCE is read as '0' before continuing.
1715 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1716 if (EFI_ERROR (Status
)) {
1717 return EFI_DEVICE_ERROR
;
1722 // Write a 1 to the HCE register to enable the UFS host controller.
1724 MmioWrite32 (Address
, UFS_HC_HCE_EN
);
1726 // Wait until HCE is read as '1' before continuing.
1728 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, UFS_HC_HCE_EN
, UFS_TIMEOUT
);
1729 if (EFI_ERROR (Status
)) {
1730 return EFI_DEVICE_ERROR
;
1737 Detect if a UFS device attached.
1739 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1741 @retval EFI_SUCCESS The UFS device detection was executed successfully.
1742 @retval EFI_NOT_FOUND Not found a UFS device attached.
1743 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.
1747 UfsDeviceDetection (
1748 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1755 // Start UFS device detection.
1756 // Try up to 3 times for establishing data link with device.
1758 for (Retry
= 0; Retry
< 3; Retry
++) {
1759 Status
= UfsExecUicCommands (Private
, UfsUicDmeLinkStartup
, 0, 0, 0);
1760 if (!EFI_ERROR (Status
)) {
1764 if (Status
== EFI_NOT_FOUND
) {
1768 return EFI_DEVICE_ERROR
;
1772 return EFI_NOT_FOUND
;
1779 Initialize UFS task management request list related h/w context.
1781 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1783 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.
1784 @retval EFI_DEVICE_ERROR The initialization fails.
1788 UfsInitTaskManagementRequestList (
1789 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1796 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1797 VOID
*CmdDescMapping
;
1801 // Initial h/w and s/w context for future operations.
1804 CmdDescMapping
= NULL
;
1806 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1807 Data
= MmioRead32 (Address
);
1808 Private
->Capabilities
= Data
;
1811 // Allocate and initialize UTP Task Management Request List.
1813 Nutmrs
= (UINT8
) (RShiftU64 ((Private
->Capabilities
& UFS_HC_CAP_NUTMRS
), 16) + 1);
1814 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutmrs
* sizeof (UTP_TMRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1815 if (EFI_ERROR (Status
)) {
1820 // Program the UTP Task Management Request List Base Address and UTP Task Management
1821 // Request List Base Address with a 64-bit address allocated at step 6.
1823 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBA_OFFSET
;
1824 MmioWrite32 (Address
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1825 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLBAU_OFFSET
;
1826 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1827 Private
->UtpTmrlBase
= CmdDescHost
;
1828 Private
->Nutmrs
= Nutmrs
;
1829 Private
->TmrlMapping
= CmdDescMapping
;
1832 // Enable the UTP Task Management Request List by setting the UTP Task Management
1833 // Request List RunStop Register (UTMRLRSR) to '1'.
1835 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1836 MmioWrite32 (Address
, UFS_HC_UTMRLRSR
);
1842 Initialize UFS transfer request list related h/w context.
1844 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1846 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.
1847 @retval EFI_DEVICE_ERROR The initialization fails.
1851 UfsInitTransferRequestList (
1852 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1859 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr
;
1860 VOID
*CmdDescMapping
;
1864 // Initial h/w and s/w context for future operations.
1867 CmdDescMapping
= NULL
;
1869 Address
= Private
->UfsHcBase
+ UFS_HC_CAP_OFFSET
;
1870 Data
= MmioRead32 (Address
);
1871 Private
->Capabilities
= Data
;
1874 // Allocate and initialize UTP Transfer Request List.
1876 Nutrs
= (UINT8
)((Private
->Capabilities
& UFS_HC_CAP_NUTRS
) + 1);
1877 Status
= UfsAllocateAlignCommonBuffer (Private
, Nutrs
* sizeof (UTP_TRD
), &CmdDescHost
, &CmdDescPhyAddr
, &CmdDescMapping
);
1878 if (EFI_ERROR (Status
)) {
1883 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List
1884 // Base Address with a 64-bit address allocated at step 8.
1886 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBA_OFFSET
;
1887 MmioWrite32 (Address
, (UINT32
)(UINTN
)CmdDescPhyAddr
);
1888 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLBAU_OFFSET
;
1889 MmioWrite32 (Address
, (UINT32
)RShiftU64 ((UINT64
)CmdDescPhyAddr
, 32));
1890 Private
->UtpTrlBase
= CmdDescHost
;
1891 Private
->Nutrs
= Nutrs
;
1892 Private
->TrlMapping
= CmdDescMapping
;
1895 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1896 // RunStop Register (UTRLRSR) to '1'.
1898 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1899 MmioWrite32 (Address
, UFS_HC_UTRLRSR
);
1905 Initialize the UFS host controller.
1907 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1909 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.
1910 @retval Others A device error occurred while initializing the controller.
1915 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1920 Status
= UfsEnableHostController (Private
);
1921 if (EFI_ERROR (Status
)) {
1922 DEBUG ((EFI_D_ERROR
, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status
));
1926 Status
= UfsDeviceDetection (Private
);
1927 if (EFI_ERROR (Status
)) {
1928 DEBUG ((EFI_D_ERROR
, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status
));
1932 Status
= UfsInitTaskManagementRequestList (Private
);
1933 if (EFI_ERROR (Status
)) {
1934 DEBUG ((EFI_D_ERROR
, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status
));
1938 Status
= UfsInitTransferRequestList (Private
);
1939 if (EFI_ERROR (Status
)) {
1940 DEBUG ((EFI_D_ERROR
, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status
));
1944 DEBUG ((EFI_D_INFO
, "UfsControllerInit Finished\n"));
1949 Stop the UFS host controller.
1951 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.
1953 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.
1954 @retval Others A device error occurred while stopping the controller.
1959 IN UFS_PASS_THRU_PRIVATE_DATA
*Private
1967 // Enable the UTP Task Management Request List by setting the UTP Task Management
1968 // Request List RunStop Register (UTMRLRSR) to '1'.
1970 Address
= Private
->UfsHcBase
+ UFS_HC_UTMRLRSR_OFFSET
;
1971 MmioWrite32 (Address
, 0);
1974 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List
1975 // RunStop Register (UTRLRSR) to '1'.
1977 Address
= Private
->UfsHcBase
+ UFS_HC_UTRLRSR_OFFSET
;
1978 MmioWrite32 (Address
, 0);
1981 // Write a 0 to the HCE register in order to disable the host controller.
1983 Address
= Private
->UfsHcBase
+ UFS_HC_ENABLE_OFFSET
;
1984 Data
= MmioRead32 (Address
);
1985 ASSERT ((Data
& UFS_HC_HCE_EN
) == UFS_HC_HCE_EN
);
1986 MmioWrite32 (Address
, 0);
1989 // Wait until HCE is read as '0' before continuing.
1991 Status
= UfsWaitMemSet (Address
, UFS_HC_HCE_EN
, 0, UFS_TIMEOUT
);
1992 if (EFI_ERROR (Status
)) {
1993 return EFI_DEVICE_ERROR
;
1996 DEBUG ((EFI_D_INFO
, "UfsController is stopped\n"));