3 Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
8 #include "UfsBlockIoPei.h"
11 // Template for UFS HC Peim Private Data.
13 UFS_PEIM_HC_PRIVATE_DATA gUfsHcPeimTemplate
= {
14 UFS_PEIM_HC_SIG
, // Signature
18 UfsBlockIoPeimGetDeviceNo
,
19 UfsBlockIoPeimGetMediaInfo
,
20 UfsBlockIoPeimReadBlocks
23 EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION
,
24 UfsBlockIoPeimGetDeviceNo2
,
25 UfsBlockIoPeimGetMediaInfo2
,
26 UfsBlockIoPeimReadBlocks2
29 EFI_PEI_PPI_DESCRIPTOR_PPI
,
30 &gEfiPeiVirtualBlockIoPpiGuid
,
34 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
35 &gEfiPeiVirtualBlockIo2PpiGuid
,
104 { // EndOfPeiNotifyList
105 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
106 &gEfiEndOfPeiSignalPpiGuid
,
120 UFS_LUN_0
, // Ufs Common Lun 0
121 UFS_LUN_1
, // Ufs Common Lun 1
122 UFS_LUN_2
, // Ufs Common Lun 2
123 UFS_LUN_3
, // Ufs Common Lun 3
124 UFS_LUN_4
, // Ufs Common Lun 4
125 UFS_LUN_5
, // Ufs Common Lun 5
126 UFS_LUN_6
, // Ufs Common Lun 6
127 UFS_LUN_7
, // Ufs Common Lun 7
129 0x0000, // By default exposing all Luns.
135 Execute TEST UNITY READY SCSI command on a specific UFS device.
137 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
138 @param[in] Lun The lun on which the SCSI cmd executed.
139 @param[out] SenseData A pointer to output sense data.
140 @param[out] SenseDataLength The length of output sense data.
142 @retval EFI_SUCCESS The command executed successfully.
143 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
144 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
148 UfsPeimTestUnitReady (
149 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
151 OUT VOID
*SenseData OPTIONAL
,
152 OUT UINT8
*SenseDataLength
155 UFS_SCSI_REQUEST_PACKET Packet
;
156 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIX
];
159 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
160 ZeroMem (Cdb
, sizeof (Cdb
));
162 Cdb
[0] = EFI_SCSI_OP_TEST_UNIT_READY
;
164 Packet
.Timeout
= UFS_TIMEOUT
;
166 Packet
.CdbLength
= sizeof (Cdb
);
167 Packet
.DataDirection
= UfsNoData
;
168 Packet
.SenseData
= SenseData
;
169 Packet
.SenseDataLength
= *SenseDataLength
;
171 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
173 if (*SenseDataLength
!= 0) {
174 *SenseDataLength
= Packet
.SenseDataLength
;
181 Execute READ CAPACITY(10) SCSI command on a specific UFS device.
183 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
184 @param[in] Lun The lun on which the SCSI cmd executed.
185 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
186 @param[out] DataLength The length of output READ_CAPACITY data.
187 @param[out] SenseData A pointer to output sense data.
188 @param[out] SenseDataLength The length of output sense data.
190 @retval EFI_SUCCESS The command executed successfully.
191 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
192 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
196 UfsPeimReadCapacity (
197 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
199 OUT VOID
*DataBuffer
,
200 OUT UINT32
*DataLength
,
201 OUT VOID
*SenseData OPTIONAL
,
202 OUT UINT8
*SenseDataLength
205 UFS_SCSI_REQUEST_PACKET Packet
;
206 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_TEN
];
209 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
210 ZeroMem (Cdb
, sizeof (Cdb
));
212 Cdb
[0] = EFI_SCSI_OP_READ_CAPACITY
;
214 Packet
.Timeout
= UFS_TIMEOUT
;
216 Packet
.CdbLength
= sizeof (Cdb
);
217 Packet
.InDataBuffer
= DataBuffer
;
218 Packet
.InTransferLength
= *DataLength
;
219 Packet
.DataDirection
= UfsDataIn
;
220 Packet
.SenseData
= SenseData
;
221 Packet
.SenseDataLength
= *SenseDataLength
;
223 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
225 if (*SenseDataLength
!= 0) {
226 *SenseDataLength
= Packet
.SenseDataLength
;
229 if (!EFI_ERROR (Status
)) {
230 *DataLength
= Packet
.InTransferLength
;
237 Execute READ CAPACITY(16) SCSI command on a specific UFS device.
239 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
240 @param[in] Lun The lun on which the SCSI cmd executed.
241 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
242 @param[out] DataLength The length of output READ_CAPACITY data.
243 @param[out] SenseData A pointer to output sense data.
244 @param[out] SenseDataLength The length of output sense data.
246 @retval EFI_SUCCESS The command executed successfully.
247 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
248 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
252 UfsPeimReadCapacity16 (
253 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
255 OUT VOID
*DataBuffer
,
256 OUT UINT32
*DataLength
,
257 OUT VOID
*SenseData OPTIONAL
,
258 OUT UINT8
*SenseDataLength
261 UFS_SCSI_REQUEST_PACKET Packet
;
262 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIXTEEN
];
265 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
266 ZeroMem (Cdb
, sizeof (Cdb
));
268 Cdb
[0] = EFI_SCSI_OP_READ_CAPACITY16
;
269 Cdb
[1] = 0x10; // Service Action should be 0x10 for UFS device.
270 Cdb
[13] = 0x20; // The maximum number of bytes for returned data.
272 Packet
.Timeout
= UFS_TIMEOUT
;
274 Packet
.CdbLength
= sizeof (Cdb
);
275 Packet
.InDataBuffer
= DataBuffer
;
276 Packet
.InTransferLength
= *DataLength
;
277 Packet
.DataDirection
= UfsDataIn
;
278 Packet
.SenseData
= SenseData
;
279 Packet
.SenseDataLength
= *SenseDataLength
;
281 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
283 if (*SenseDataLength
!= 0) {
284 *SenseDataLength
= Packet
.SenseDataLength
;
287 if (!EFI_ERROR (Status
)) {
288 *DataLength
= Packet
.InTransferLength
;
295 Execute READ (10) SCSI command on a specific UFS device.
297 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
298 @param[in] Lun The lun on which the SCSI cmd executed.
299 @param[in] StartLba The start LBA.
300 @param[in] SectorNum The sector number to be read.
301 @param[out] DataBuffer A pointer to data buffer.
302 @param[out] DataLength The length of output data.
303 @param[out] SenseData A pointer to output sense data.
304 @param[out] SenseDataLength The length of output sense data.
306 @retval EFI_SUCCESS The command executed successfully.
307 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
308 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
313 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
317 OUT VOID
*DataBuffer
,
318 OUT UINT32
*DataLength
,
319 OUT VOID
*SenseData OPTIONAL
,
320 OUT UINT8
*SenseDataLength
323 UFS_SCSI_REQUEST_PACKET Packet
;
324 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_TEN
];
327 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
328 ZeroMem (Cdb
, sizeof (Cdb
));
330 Cdb
[0] = EFI_SCSI_OP_READ10
;
331 WriteUnaligned32 ((UINT32
*)&Cdb
[2], SwapBytes32 ((UINT32
)StartLba
));
332 WriteUnaligned16 ((UINT16
*)&Cdb
[7], SwapBytes16 ((UINT16
)SectorNum
));
334 Packet
.Timeout
= UFS_TIMEOUT
;
336 Packet
.CdbLength
= sizeof (Cdb
);
337 Packet
.InDataBuffer
= DataBuffer
;
338 Packet
.InTransferLength
= *DataLength
;
339 Packet
.DataDirection
= UfsDataIn
;
340 Packet
.SenseData
= SenseData
;
341 Packet
.SenseDataLength
= *SenseDataLength
;
343 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
345 if (*SenseDataLength
!= 0) {
346 *SenseDataLength
= Packet
.SenseDataLength
;
349 if (!EFI_ERROR (Status
)) {
350 *DataLength
= Packet
.InTransferLength
;
357 Execute READ (16) SCSI command on a specific UFS device.
359 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
360 @param[in] Lun The lun on which the SCSI cmd executed.
361 @param[in] StartLba The start LBA.
362 @param[in] SectorNum The sector number to be read.
363 @param[out] DataBuffer A pointer to data buffer.
364 @param[out] DataLength The length of output data.
365 @param[out] SenseData A pointer to output sense data.
366 @param[out] SenseDataLength The length of output sense data.
368 @retval EFI_SUCCESS The command executed successfully.
369 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
370 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
375 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
379 OUT VOID
*DataBuffer
,
380 OUT UINT32
*DataLength
,
381 OUT VOID
*SenseData OPTIONAL
,
382 OUT UINT8
*SenseDataLength
385 UFS_SCSI_REQUEST_PACKET Packet
;
386 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIXTEEN
];
389 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
390 ZeroMem (Cdb
, sizeof (Cdb
));
392 Cdb
[0] = EFI_SCSI_OP_READ16
;
393 WriteUnaligned64 ((UINT64
*)&Cdb
[2], SwapBytes64 (StartLba
));
394 WriteUnaligned32 ((UINT32
*)&Cdb
[10], SwapBytes32 (SectorNum
));
396 Packet
.Timeout
= UFS_TIMEOUT
;
398 Packet
.CdbLength
= sizeof (Cdb
);
399 Packet
.InDataBuffer
= DataBuffer
;
400 Packet
.InTransferLength
= *DataLength
;
401 Packet
.DataDirection
= UfsDataIn
;
402 Packet
.SenseData
= SenseData
;
403 Packet
.SenseDataLength
= *SenseDataLength
;
405 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
407 if (*SenseDataLength
!= 0) {
408 *SenseDataLength
= Packet
.SenseDataLength
;
411 if (!EFI_ERROR (Status
)) {
412 *DataLength
= Packet
.InTransferLength
;
419 Parsing Sense Keys from sense data.
421 @param Media The pointer of EFI_PEI_BLOCK_IO_MEDIA
422 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
423 @param NeedRetry The pointer of action which indicates what is need to retry
425 @retval EFI_DEVICE_ERROR Indicates that error occurs
426 @retval EFI_SUCCESS Successfully to complete the parsing
430 UfsPeimParsingSenseKeys (
431 IN EFI_PEI_BLOCK_IO2_MEDIA
*Media
,
432 IN EFI_SCSI_SENSE_DATA
*SenseData
,
433 OUT BOOLEAN
*NeedRetry
436 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
437 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
))
439 Media
->MediaPresent
= FALSE
;
441 DEBUG ((DEBUG_VERBOSE
, "UfsBlockIoPei: Is No Media\n"));
442 return EFI_DEVICE_ERROR
;
445 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
446 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
))
449 DEBUG ((DEBUG_VERBOSE
, "UfsBlockIoPei: Is Media Change\n"));
453 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
454 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
))
457 DEBUG ((DEBUG_VERBOSE
, "UfsBlockIoPei: Was Reset Before\n"));
461 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_MEDIUM_ERROR
) ||
462 ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
463 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
)))
466 DEBUG ((DEBUG_VERBOSE
, "UfsBlockIoPei: Media Error\n"));
467 return EFI_DEVICE_ERROR
;
470 if (SenseData
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
472 DEBUG ((DEBUG_VERBOSE
, "UfsBlockIoPei: Hardware Error\n"));
473 return EFI_DEVICE_ERROR
;
476 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
477 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_NOT_READY
) &&
478 (SenseData
->Addnl_Sense_Code_Qualifier
== EFI_SCSI_ASCQ_IN_PROGRESS
))
481 DEBUG ((DEBUG_VERBOSE
, "UfsBlockIoPei: Was Reset Before\n"));
486 DEBUG ((DEBUG_VERBOSE
, "UfsBlockIoPei: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
487 return EFI_DEVICE_ERROR
;
491 Gets the count of block I/O devices that one specific block driver detects.
493 This function is used for getting the count of block I/O devices that one
494 specific block driver detects. To the PEI ATAPI driver, it returns the number
495 of all the detected ATAPI devices it detects during the enumeration process.
496 To the PEI legacy floppy driver, it returns the number of all the legacy
497 devices it finds during its enumeration process. If no device is detected,
498 then the function will return zero.
500 @param[in] PeiServices General-purpose services that are available
502 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
504 @param[out] NumberBlockDevices The number of block I/O devices discovered.
506 @retval EFI_SUCCESS The operation performed successfully.
511 UfsBlockIoPeimGetDeviceNo (
512 IN EFI_PEI_SERVICES
**PeiServices
,
513 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
514 OUT UINTN
*NumberBlockDevices
518 // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
519 // At PEI phase, we will only expose normal Luns to user.
520 // For those disabled Lun, when user try to access it, the operation would fail.
522 *NumberBlockDevices
= UFS_PEIM_MAX_LUNS
;
527 Gets a block device's media information.
529 This function will provide the caller with the specified block device's media
530 information. If the media changes, calling this function will update the media
531 information accordingly.
533 @param[in] PeiServices General-purpose services that are available to every
535 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
536 @param[in] DeviceIndex Specifies the block device to which the function wants
537 to talk. Because the driver that implements Block I/O
538 PPIs will manage multiple block devices, the PPIs that
539 want to talk to a single device must specify the
540 device index that was assigned during the enumeration
541 process. This index is a number from one to
543 @param[out] MediaInfo The media information of the specified block media.
544 The caller is responsible for the ownership of this
548 The MediaInfo structure describes an enumeration of possible block device
549 types. This enumeration exists because no device paths are actually passed
550 across interfaces that describe the type or class of hardware that is publishing
551 the block I/O interface. This enumeration will allow for policy decisions
552 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
553 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
554 by a given device type, they should be reported in ascending order; this
555 order also applies to nested partitions, such as legacy MBR, where the
556 outermost partitions would have precedence in the reporting order. The
557 same logic applies to systems such as IDE that have precedence relationships
558 like "Master/Slave" or "Primary/Secondary". The master device should be
559 reported first, the slave second.
561 @retval EFI_SUCCESS Media information about the specified block device
562 was obtained successfully.
563 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
569 UfsBlockIoPeimGetMediaInfo (
570 IN EFI_PEI_SERVICES
**PeiServices
,
571 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
572 IN UINTN DeviceIndex
,
573 OUT EFI_PEI_BLOCK_IO_MEDIA
*MediaInfo
577 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
578 EFI_SCSI_SENSE_DATA SenseData
;
579 UINT8 SenseDataLength
;
580 EFI_SCSI_DISK_CAPACITY_DATA Capacity
;
581 EFI_SCSI_DISK_CAPACITY_DATA16 Capacity16
;
586 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
589 if ((DeviceIndex
== 0) || (DeviceIndex
> UFS_PEIM_MAX_LUNS
)) {
590 return EFI_INVALID_PARAMETER
;
593 Lun
= DeviceIndex
- 1;
594 if ((Private
->Luns
.BitMask
& (BIT0
<< Lun
)) == 0) {
595 return EFI_ACCESS_DENIED
;
598 ZeroMem (&SenseData
, sizeof (SenseData
));
599 ZeroMem (&Capacity
, sizeof (Capacity
));
600 ZeroMem (&Capacity16
, sizeof (Capacity16
));
601 SenseDataLength
= sizeof (SenseData
);
603 // First test unit ready
606 Status
= UfsPeimTestUnitReady (
612 if (!EFI_ERROR (Status
)) {
616 if (SenseDataLength
== 0) {
620 Status
= UfsPeimParsingSenseKeys (&(Private
->Media
[Lun
]), &SenseData
, &NeedRetry
);
621 if (EFI_ERROR (Status
)) {
622 return EFI_DEVICE_ERROR
;
626 DataLength
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
628 Status
= UfsPeimReadCapacity (Private
, Lun
, &Capacity
, (UINT32
*)&DataLength
, NULL
, &SenseDataLength
);
629 if (EFI_ERROR (Status
)) {
630 return EFI_DEVICE_ERROR
;
633 if ((Capacity
.LastLba3
== 0xff) && (Capacity
.LastLba2
== 0xff) &&
634 (Capacity
.LastLba1
== 0xff) && (Capacity
.LastLba0
== 0xff))
636 DataLength
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
638 Status
= UfsPeimReadCapacity16 (Private
, Lun
, &Capacity16
, (UINT32
*)&DataLength
, NULL
, &SenseDataLength
);
639 if (EFI_ERROR (Status
)) {
640 return EFI_DEVICE_ERROR
;
643 Private
->Media
[Lun
].LastBlock
= ((UINT32
)Capacity16
.LastLba3
<< 24) | (Capacity16
.LastLba2
<< 16) | (Capacity16
.LastLba1
<< 8) | Capacity16
.LastLba0
;
644 Private
->Media
[Lun
].LastBlock
|= LShiftU64 ((UINT64
)Capacity16
.LastLba7
, 56) | LShiftU64 ((UINT64
)Capacity16
.LastLba6
, 48) | LShiftU64 ((UINT64
)Capacity16
.LastLba5
, 40) | LShiftU64 ((UINT64
)Capacity16
.LastLba4
, 32);
645 Private
->Media
[Lun
].BlockSize
= (Capacity16
.BlockSize3
<< 24) | (Capacity16
.BlockSize2
<< 16) | (Capacity16
.BlockSize1
<< 8) | Capacity16
.BlockSize0
;
647 Private
->Media
[Lun
].LastBlock
= ((UINT32
)Capacity
.LastLba3
<< 24) | (Capacity
.LastLba2
<< 16) | (Capacity
.LastLba1
<< 8) | Capacity
.LastLba0
;
648 Private
->Media
[Lun
].BlockSize
= (Capacity
.BlockSize3
<< 24) | (Capacity
.BlockSize2
<< 16) | (Capacity
.BlockSize1
<< 8) | Capacity
.BlockSize0
;
651 MediaInfo
->DeviceType
= UfsDevice
;
652 MediaInfo
->MediaPresent
= Private
->Media
[Lun
].MediaPresent
;
653 MediaInfo
->LastBlock
= (UINTN
)Private
->Media
[Lun
].LastBlock
;
654 MediaInfo
->BlockSize
= Private
->Media
[Lun
].BlockSize
;
660 Reads the requested number of blocks from the specified block device.
662 The function reads the requested number of blocks from the device. All the
663 blocks are read, or an error is returned. If there is no media in the device,
664 the function returns EFI_NO_MEDIA.
666 @param[in] PeiServices General-purpose services that are available to
668 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
669 @param[in] DeviceIndex Specifies the block device to which the function wants
670 to talk. Because the driver that implements Block I/O
671 PPIs will manage multiple block devices, PPIs that
672 want to talk to a single device must specify the device
673 index that was assigned during the enumeration process.
674 This index is a number from one to NumberBlockDevices.
675 @param[in] StartLBA The starting logical block address (LBA) to read from
677 @param[in] BufferSize The size of the Buffer in bytes. This number must be
678 a multiple of the intrinsic block size of the device.
679 @param[out] Buffer A pointer to the destination buffer for the data.
680 The caller is responsible for the ownership of the
683 @retval EFI_SUCCESS The data was read correctly from the device.
684 @retval EFI_DEVICE_ERROR The device reported an error while attempting
685 to perform the read operation.
686 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
687 valid, or the buffer is not properly aligned.
688 @retval EFI_NO_MEDIA There is no media in the device.
689 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
690 the intrinsic block size of the device.
695 UfsBlockIoPeimReadBlocks (
696 IN EFI_PEI_SERVICES
**PeiServices
,
697 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
698 IN UINTN DeviceIndex
,
699 IN EFI_PEI_LBA StartLBA
,
706 UINTN NumberOfBlocks
;
707 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
708 EFI_SCSI_SENSE_DATA SenseData
;
709 UINT8 SenseDataLength
;
713 Status
= EFI_SUCCESS
;
715 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
717 ZeroMem (&SenseData
, sizeof (SenseData
));
718 SenseDataLength
= sizeof (SenseData
);
723 if (Buffer
== NULL
) {
724 return EFI_INVALID_PARAMETER
;
727 if (BufferSize
== 0) {
731 if ((DeviceIndex
== 0) || (DeviceIndex
> UFS_PEIM_MAX_LUNS
)) {
732 return EFI_INVALID_PARAMETER
;
735 Lun
= DeviceIndex
- 1;
736 if ((Private
->Luns
.BitMask
& (BIT0
<< Lun
)) == 0) {
737 return EFI_ACCESS_DENIED
;
740 BlockSize
= Private
->Media
[Lun
].BlockSize
;
742 if (BufferSize
% BlockSize
!= 0) {
743 Status
= EFI_BAD_BUFFER_SIZE
;
746 if (StartLBA
> Private
->Media
[Lun
].LastBlock
) {
747 Status
= EFI_INVALID_PARAMETER
;
750 NumberOfBlocks
= BufferSize
/ BlockSize
;
753 Status
= UfsPeimTestUnitReady (
759 if (!EFI_ERROR (Status
)) {
763 if (SenseDataLength
== 0) {
767 Status
= UfsPeimParsingSenseKeys (&(Private
->Media
[Lun
]), &SenseData
, &NeedRetry
);
768 if (EFI_ERROR (Status
)) {
769 return EFI_DEVICE_ERROR
;
774 if (Private
->Media
[Lun
].LastBlock
< 0xfffffffful
) {
775 Status
= UfsPeimRead10 (
779 (UINT32
)NumberOfBlocks
,
781 (UINT32
*)&BufferSize
,
786 Status
= UfsPeimRead16 (
790 (UINT32
)NumberOfBlocks
,
792 (UINT32
*)&BufferSize
,
802 Gets the count of block I/O devices that one specific block driver detects.
804 This function is used for getting the count of block I/O devices that one
805 specific block driver detects. To the PEI ATAPI driver, it returns the number
806 of all the detected ATAPI devices it detects during the enumeration process.
807 To the PEI legacy floppy driver, it returns the number of all the legacy
808 devices it finds during its enumeration process. If no device is detected,
809 then the function will return zero.
811 @param[in] PeiServices General-purpose services that are available
813 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
815 @param[out] NumberBlockDevices The number of block I/O devices discovered.
817 @retval EFI_SUCCESS The operation performed successfully.
822 UfsBlockIoPeimGetDeviceNo2 (
823 IN EFI_PEI_SERVICES
**PeiServices
,
824 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
825 OUT UINTN
*NumberBlockDevices
829 // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
830 // At PEI phase, we will only expose normal Luns to user.
831 // For those disabled Lun, when user try to access it, the operation would fail.
833 *NumberBlockDevices
= UFS_PEIM_MAX_LUNS
;
838 Gets a block device's media information.
840 This function will provide the caller with the specified block device's media
841 information. If the media changes, calling this function will update the media
842 information accordingly.
844 @param[in] PeiServices General-purpose services that are available to every
846 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
847 @param[in] DeviceIndex Specifies the block device to which the function wants
848 to talk. Because the driver that implements Block I/O
849 PPIs will manage multiple block devices, the PPIs that
850 want to talk to a single device must specify the
851 device index that was assigned during the enumeration
852 process. This index is a number from one to
854 @param[out] MediaInfo The media information of the specified block media.
855 The caller is responsible for the ownership of this
859 The MediaInfo structure describes an enumeration of possible block device
860 types. This enumeration exists because no device paths are actually passed
861 across interfaces that describe the type or class of hardware that is publishing
862 the block I/O interface. This enumeration will allow for policy decisions
863 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
864 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
865 by a given device type, they should be reported in ascending order; this
866 order also applies to nested partitions, such as legacy MBR, where the
867 outermost partitions would have precedence in the reporting order. The
868 same logic applies to systems such as IDE that have precedence relationships
869 like "Master/Slave" or "Primary/Secondary". The master device should be
870 reported first, the slave second.
872 @retval EFI_SUCCESS Media information about the specified block device
873 was obtained successfully.
874 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
880 UfsBlockIoPeimGetMediaInfo2 (
881 IN EFI_PEI_SERVICES
**PeiServices
,
882 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
883 IN UINTN DeviceIndex
,
884 OUT EFI_PEI_BLOCK_IO2_MEDIA
*MediaInfo
888 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
889 EFI_PEI_BLOCK_IO_MEDIA Media
;
892 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
894 Status
= UfsBlockIoPeimGetMediaInfo (
900 if (EFI_ERROR (Status
)) {
904 Lun
= DeviceIndex
- 1;
905 CopyMem (MediaInfo
, &(Private
->Media
[Lun
]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA
));
910 Reads the requested number of blocks from the specified block device.
912 The function reads the requested number of blocks from the device. All the
913 blocks are read, or an error is returned. If there is no media in the device,
914 the function returns EFI_NO_MEDIA.
916 @param[in] PeiServices General-purpose services that are available to
918 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
919 @param[in] DeviceIndex Specifies the block device to which the function wants
920 to talk. Because the driver that implements Block I/O
921 PPIs will manage multiple block devices, PPIs that
922 want to talk to a single device must specify the device
923 index that was assigned during the enumeration process.
924 This index is a number from one to NumberBlockDevices.
925 @param[in] StartLBA The starting logical block address (LBA) to read from
927 @param[in] BufferSize The size of the Buffer in bytes. This number must be
928 a multiple of the intrinsic block size of the device.
929 @param[out] Buffer A pointer to the destination buffer for the data.
930 The caller is responsible for the ownership of the
933 @retval EFI_SUCCESS The data was read correctly from the device.
934 @retval EFI_DEVICE_ERROR The device reported an error while attempting
935 to perform the read operation.
936 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
937 valid, or the buffer is not properly aligned.
938 @retval EFI_NO_MEDIA There is no media in the device.
939 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
940 the intrinsic block size of the device.
945 UfsBlockIoPeimReadBlocks2 (
946 IN EFI_PEI_SERVICES
**PeiServices
,
947 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
948 IN UINTN DeviceIndex
,
949 IN EFI_PEI_LBA StartLBA
,
955 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
957 Status
= EFI_SUCCESS
;
958 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
960 Status
= UfsBlockIoPeimReadBlocks (
972 One notified function to cleanup the allocated DMA buffers at the end of PEI.
974 @param[in] PeiServices Pointer to PEI Services Table.
975 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
976 event that caused this function to execute.
977 @param[in] Ppi Pointer to the PPI data associated with this function.
979 @retval EFI_SUCCESS The function completes successfully
985 IN EFI_PEI_SERVICES
**PeiServices
,
986 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
990 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
992 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor
);
994 if ((Private
->Pool
!= NULL
) && (Private
->Pool
->Head
!= NULL
)) {
995 UfsPeimFreeMemPool (Private
->Pool
);
998 if (Private
->UtpTmrlBase
!= NULL
) {
1000 EFI_SIZE_TO_PAGES (Private
->Nutmrs
* sizeof (UTP_TMRD
)),
1001 Private
->UtpTmrlBase
,
1002 Private
->TmrlMapping
1006 if (Private
->UtpTrlBase
!= NULL
) {
1008 EFI_SIZE_TO_PAGES (Private
->Nutrs
* sizeof (UTP_TRD
)),
1009 Private
->UtpTrlBase
,
1014 UfsControllerStop (Private
);
1020 The user code starts with this function.
1022 @param FileHandle Handle of the file being invoked.
1023 @param PeiServices Describes the list of possible PEI Services.
1025 @retval EFI_SUCCESS The driver is successfully initialized.
1026 @retval Others Can't initialize the driver.
1031 InitializeUfsBlockIoPeim (
1032 IN EFI_PEI_FILE_HANDLE FileHandle
,
1033 IN CONST EFI_PEI_SERVICES
**PeiServices
1037 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
1038 EDKII_UFS_HOST_CONTROLLER_PPI
*UfsHcPpi
;
1042 UFS_UNIT_DESC UnitDescriptor
;
1045 // Shadow this PEIM to run from memory
1047 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
1052 // locate ufs host controller PPI
1054 Status
= PeiServicesLocatePpi (
1055 &gEdkiiPeiUfsHostControllerPpiGuid
,
1060 if (EFI_ERROR (Status
)) {
1061 return EFI_DEVICE_ERROR
;
1069 Status
= UfsHcPpi
->GetUfsHcMmioBar (UfsHcPpi
, Controller
, &MmioBase
);
1071 // When status is error, meant no controller is found
1073 if (EFI_ERROR (Status
)) {
1077 Private
= AllocateCopyPool (sizeof (UFS_PEIM_HC_PRIVATE_DATA
), &gUfsHcPeimTemplate
);
1078 if (Private
== NULL
) {
1079 Status
= EFI_OUT_OF_RESOURCES
;
1083 Private
->BlkIoPpiList
.Ppi
= &Private
->BlkIoPpi
;
1084 Private
->BlkIo2PpiList
.Ppi
= &Private
->BlkIo2Ppi
;
1085 Private
->UfsHcBase
= MmioBase
;
1088 // Initialize the memory pool which will be used in all transactions.
1090 Status
= UfsPeimInitMemPool (Private
);
1091 if (EFI_ERROR (Status
)) {
1092 Status
= EFI_OUT_OF_RESOURCES
;
1097 // Initialize UFS Host Controller H/W.
1099 Status
= UfsControllerInit (Private
);
1100 if (EFI_ERROR (Status
)) {
1101 DEBUG ((DEBUG_ERROR
, "UfsDevicePei: Host Controller Initialization Error, Status = %r\n", Status
));
1107 // UFS 2.0 spec Section 13.1.3.3:
1108 // At the end of the UFS Interconnect Layer initialization on both host and device side,
1109 // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready.
1111 Status
= UfsExecNopCmds (Private
);
1112 if (EFI_ERROR (Status
)) {
1113 DEBUG ((DEBUG_ERROR
, "Ufs Sending NOP IN command Error, Status = %r\n", Status
));
1119 // The host enables the device initialization completion by setting fDeviceInit flag.
1121 Status
= UfsSetFlag (Private
, UfsFlagDevInit
);
1122 if (EFI_ERROR (Status
)) {
1123 DEBUG ((DEBUG_ERROR
, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status
));
1129 // Check if 8 common luns are active and set corresponding bit mask.
1131 for (Index
= 0; Index
< UFS_PEIM_MAX_LUNS
; Index
++) {
1132 Status
= UfsRwDeviceDesc (Private
, TRUE
, UfsUnitDesc
, (UINT8
)Index
, 0, &UnitDescriptor
, sizeof (UFS_UNIT_DESC
));
1133 if (EFI_ERROR (Status
)) {
1134 DEBUG ((DEBUG_ERROR
, "Fail to read UFS Unit Descriptor, Index = %X, Status = %r\n", Index
, Status
));
1138 if (UnitDescriptor
.LunEn
== 0x1) {
1139 DEBUG ((DEBUG_INFO
, "Ufs %d Lun %d is enabled\n", Controller
, Index
));
1140 Private
->Luns
.BitMask
|= (BIT0
<< Index
);
1144 PeiServicesInstallPpi (&Private
->BlkIoPpiList
);
1145 PeiServicesNotifyPpi (&Private
->EndOfPeiNotifyList
);