3 Copyright (c) 2014 - 2019, 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.
137 Execute TEST UNITY READY SCSI command on a specific UFS device.
139 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
140 @param[in] Lun The lun on which the SCSI cmd executed.
141 @param[out] SenseData A pointer to output sense data.
142 @param[out] SenseDataLength The length of output sense data.
144 @retval EFI_SUCCESS The command executed successfully.
145 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
146 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
150 UfsPeimTestUnitReady (
151 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
153 OUT VOID
*SenseData
, OPTIONAL
154 OUT UINT8
*SenseDataLength
157 UFS_SCSI_REQUEST_PACKET Packet
;
158 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIX
];
161 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
162 ZeroMem (Cdb
, sizeof (Cdb
));
164 Cdb
[0] = EFI_SCSI_OP_TEST_UNIT_READY
;
166 Packet
.Timeout
= UFS_TIMEOUT
;
168 Packet
.CdbLength
= sizeof (Cdb
);
169 Packet
.DataDirection
= UfsNoData
;
170 Packet
.SenseData
= SenseData
;
171 Packet
.SenseDataLength
= *SenseDataLength
;
173 Status
= UfsExecScsiCmds (Private
,(UINT8
)Lun
, &Packet
);
175 if (*SenseDataLength
!= 0) {
176 *SenseDataLength
= Packet
.SenseDataLength
;
185 Execute READ CAPACITY(10) SCSI command on a specific UFS device.
187 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
188 @param[in] Lun The lun on which the SCSI cmd executed.
189 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
190 @param[out] DataLength The length of output READ_CAPACITY data.
191 @param[out] SenseData A pointer to output sense data.
192 @param[out] SenseDataLength The length of output sense data.
194 @retval EFI_SUCCESS The command executed successfully.
195 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
196 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
200 UfsPeimReadCapacity (
201 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
203 OUT VOID
*DataBuffer
,
204 OUT UINT32
*DataLength
,
205 OUT VOID
*SenseData
, OPTIONAL
206 OUT UINT8
*SenseDataLength
209 UFS_SCSI_REQUEST_PACKET Packet
;
210 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_TEN
];
213 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
214 ZeroMem (Cdb
, sizeof (Cdb
));
216 Cdb
[0] = EFI_SCSI_OP_READ_CAPACITY
;
218 Packet
.Timeout
= UFS_TIMEOUT
;
220 Packet
.CdbLength
= sizeof (Cdb
);
221 Packet
.InDataBuffer
= DataBuffer
;
222 Packet
.InTransferLength
= *DataLength
;
223 Packet
.DataDirection
= UfsDataIn
;
224 Packet
.SenseData
= SenseData
;
225 Packet
.SenseDataLength
= *SenseDataLength
;
227 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
229 if (*SenseDataLength
!= 0) {
230 *SenseDataLength
= Packet
.SenseDataLength
;
233 if (!EFI_ERROR (Status
)) {
234 *DataLength
= Packet
.InTransferLength
;
241 Execute READ CAPACITY(16) SCSI command on a specific UFS device.
243 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
244 @param[in] Lun The lun on which the SCSI cmd executed.
245 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
246 @param[out] DataLength The length of output READ_CAPACITY data.
247 @param[out] SenseData A pointer to output sense data.
248 @param[out] SenseDataLength The length of output sense data.
250 @retval EFI_SUCCESS The command executed successfully.
251 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
252 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
256 UfsPeimReadCapacity16 (
257 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
259 OUT VOID
*DataBuffer
,
260 OUT UINT32
*DataLength
,
261 OUT VOID
*SenseData
, OPTIONAL
262 OUT UINT8
*SenseDataLength
265 UFS_SCSI_REQUEST_PACKET Packet
;
266 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIXTEEN
];
269 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
270 ZeroMem (Cdb
, sizeof (Cdb
));
272 Cdb
[0] = EFI_SCSI_OP_READ_CAPACITY16
;
273 Cdb
[1] = 0x10; // Service Action should be 0x10 for UFS device.
274 Cdb
[13] = 0x20; // The maximum number of bytes for returned data.
276 Packet
.Timeout
= UFS_TIMEOUT
;
278 Packet
.CdbLength
= sizeof (Cdb
);
279 Packet
.InDataBuffer
= DataBuffer
;
280 Packet
.InTransferLength
= *DataLength
;
281 Packet
.DataDirection
= UfsDataIn
;
282 Packet
.SenseData
= SenseData
;
283 Packet
.SenseDataLength
= *SenseDataLength
;
285 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
287 if (*SenseDataLength
!= 0) {
288 *SenseDataLength
= Packet
.SenseDataLength
;
291 if (!EFI_ERROR (Status
)) {
292 *DataLength
= Packet
.InTransferLength
;
299 Execute READ (10) SCSI command on a specific UFS device.
301 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
302 @param[in] Lun The lun on which the SCSI cmd executed.
303 @param[in] StartLba The start LBA.
304 @param[in] SectorNum The sector number to be read.
305 @param[out] DataBuffer A pointer to data buffer.
306 @param[out] DataLength The length of output data.
307 @param[out] SenseData A pointer to output sense data.
308 @param[out] SenseDataLength The length of output sense data.
310 @retval EFI_SUCCESS The command executed successfully.
311 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
312 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
317 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
321 OUT VOID
*DataBuffer
,
322 OUT UINT32
*DataLength
,
323 OUT VOID
*SenseData
, OPTIONAL
324 OUT UINT8
*SenseDataLength
327 UFS_SCSI_REQUEST_PACKET Packet
;
328 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_TEN
];
331 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
332 ZeroMem (Cdb
, sizeof (Cdb
));
334 Cdb
[0] = EFI_SCSI_OP_READ10
;
335 WriteUnaligned32 ((UINT32
*)&Cdb
[2], SwapBytes32 ((UINT32
) StartLba
));
336 WriteUnaligned16 ((UINT16
*)&Cdb
[7], SwapBytes16 ((UINT16
) SectorNum
));
338 Packet
.Timeout
= UFS_TIMEOUT
;
340 Packet
.CdbLength
= sizeof (Cdb
);
341 Packet
.InDataBuffer
= DataBuffer
;
342 Packet
.InTransferLength
= *DataLength
;
343 Packet
.DataDirection
= UfsDataIn
;
344 Packet
.SenseData
= SenseData
;
345 Packet
.SenseDataLength
= *SenseDataLength
;
347 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
349 if (*SenseDataLength
!= 0) {
350 *SenseDataLength
= Packet
.SenseDataLength
;
353 if (!EFI_ERROR (Status
)) {
354 *DataLength
= Packet
.InTransferLength
;
361 Execute READ (16) SCSI command on a specific UFS device.
363 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
364 @param[in] Lun The lun on which the SCSI cmd executed.
365 @param[in] StartLba The start LBA.
366 @param[in] SectorNum The sector number to be read.
367 @param[out] DataBuffer A pointer to data buffer.
368 @param[out] DataLength The length of output data.
369 @param[out] SenseData A pointer to output sense data.
370 @param[out] SenseDataLength The length of output sense data.
372 @retval EFI_SUCCESS The command executed successfully.
373 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
374 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
379 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
383 OUT VOID
*DataBuffer
,
384 OUT UINT32
*DataLength
,
385 OUT VOID
*SenseData
, OPTIONAL
386 OUT UINT8
*SenseDataLength
389 UFS_SCSI_REQUEST_PACKET Packet
;
390 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIXTEEN
];
393 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
394 ZeroMem (Cdb
, sizeof (Cdb
));
396 Cdb
[0] = EFI_SCSI_OP_READ16
;
397 WriteUnaligned64 ((UINT64
*)&Cdb
[2], SwapBytes64 (StartLba
));
398 WriteUnaligned32 ((UINT32
*)&Cdb
[10], SwapBytes32 (SectorNum
));
400 Packet
.Timeout
= UFS_TIMEOUT
;
402 Packet
.CdbLength
= sizeof (Cdb
);
403 Packet
.InDataBuffer
= DataBuffer
;
404 Packet
.InTransferLength
= *DataLength
;
405 Packet
.DataDirection
= UfsDataIn
;
406 Packet
.SenseData
= SenseData
;
407 Packet
.SenseDataLength
= *SenseDataLength
;
409 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
411 if (*SenseDataLength
!= 0) {
412 *SenseDataLength
= Packet
.SenseDataLength
;
415 if (!EFI_ERROR (Status
)) {
416 *DataLength
= Packet
.InTransferLength
;
423 Parsing Sense Keys from sense data.
425 @param Media The pointer of EFI_PEI_BLOCK_IO_MEDIA
426 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
427 @param NeedRetry The pointer of action which indicates what is need to retry
429 @retval EFI_DEVICE_ERROR Indicates that error occurs
430 @retval EFI_SUCCESS Successfully to complete the parsing
434 UfsPeimParsingSenseKeys (
435 IN EFI_PEI_BLOCK_IO2_MEDIA
*Media
,
436 IN EFI_SCSI_SENSE_DATA
*SenseData
,
437 OUT BOOLEAN
*NeedRetry
440 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
441 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
442 Media
->MediaPresent
= FALSE
;
444 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Is No Media\n"));
445 return EFI_DEVICE_ERROR
;
448 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
449 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
451 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Is Media Change\n"));
455 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
456 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
458 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Was Reset Before\n"));
462 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_MEDIUM_ERROR
) ||
463 ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
464 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
))) {
466 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Media Error\n"));
467 return EFI_DEVICE_ERROR
;
470 if (SenseData
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
472 DEBUG ((EFI_D_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
)) {
480 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Was Reset Before\n"));
485 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
486 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
;
627 DataLength
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
629 Status
= UfsPeimReadCapacity (Private
, Lun
, &Capacity
, (UINT32
*)&DataLength
, NULL
, &SenseDataLength
);
630 if (EFI_ERROR (Status
)) {
631 return EFI_DEVICE_ERROR
;
634 if ((Capacity
.LastLba3
== 0xff) && (Capacity
.LastLba2
== 0xff) &&
635 (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
;
642 Private
->Media
[Lun
].LastBlock
= ((UINT32
)Capacity16
.LastLba3
<< 24) | (Capacity16
.LastLba2
<< 16) | (Capacity16
.LastLba1
<< 8) | Capacity16
.LastLba0
;
643 Private
->Media
[Lun
].LastBlock
|= LShiftU64 ((UINT64
)Capacity16
.LastLba7
, 56) | LShiftU64((UINT64
)Capacity16
.LastLba6
, 48) | LShiftU64 ((UINT64
)Capacity16
.LastLba5
, 40) | LShiftU64 ((UINT64
)Capacity16
.LastLba4
, 32);
644 Private
->Media
[Lun
].BlockSize
= (Capacity16
.BlockSize3
<< 24) | (Capacity16
.BlockSize2
<< 16) | (Capacity16
.BlockSize1
<< 8) | Capacity16
.BlockSize0
;
646 Private
->Media
[Lun
].LastBlock
= ((UINT32
)Capacity
.LastLba3
<< 24) | (Capacity
.LastLba2
<< 16) | (Capacity
.LastLba1
<< 8) | Capacity
.LastLba0
;
647 Private
->Media
[Lun
].BlockSize
= (Capacity
.BlockSize3
<< 24) | (Capacity
.BlockSize2
<< 16) | (Capacity
.BlockSize1
<< 8) | Capacity
.BlockSize0
;
650 MediaInfo
->DeviceType
= UfsDevice
;
651 MediaInfo
->MediaPresent
= Private
->Media
[Lun
].MediaPresent
;
652 MediaInfo
->LastBlock
= (UINTN
)Private
->Media
[Lun
].LastBlock
;
653 MediaInfo
->BlockSize
= Private
->Media
[Lun
].BlockSize
;
659 Reads the requested number of blocks from the specified block device.
661 The function reads the requested number of blocks from the device. All the
662 blocks are read, or an error is returned. If there is no media in the device,
663 the function returns EFI_NO_MEDIA.
665 @param[in] PeiServices General-purpose services that are available to
667 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
668 @param[in] DeviceIndex Specifies the block device to which the function wants
669 to talk. Because the driver that implements Block I/O
670 PPIs will manage multiple block devices, PPIs that
671 want to talk to a single device must specify the device
672 index that was assigned during the enumeration process.
673 This index is a number from one to NumberBlockDevices.
674 @param[in] StartLBA The starting logical block address (LBA) to read from
676 @param[in] BufferSize The size of the Buffer in bytes. This number must be
677 a multiple of the intrinsic block size of the device.
678 @param[out] Buffer A pointer to the destination buffer for the data.
679 The caller is responsible for the ownership of the
682 @retval EFI_SUCCESS The data was read correctly from the device.
683 @retval EFI_DEVICE_ERROR The device reported an error while attempting
684 to perform the read operation.
685 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
686 valid, or the buffer is not properly aligned.
687 @retval EFI_NO_MEDIA There is no media in the device.
688 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
689 the intrinsic block size of the device.
694 UfsBlockIoPeimReadBlocks (
695 IN EFI_PEI_SERVICES
**PeiServices
,
696 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
697 IN UINTN DeviceIndex
,
698 IN EFI_PEI_LBA StartLBA
,
705 UINTN NumberOfBlocks
;
706 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
707 EFI_SCSI_SENSE_DATA SenseData
;
708 UINT8 SenseDataLength
;
712 Status
= EFI_SUCCESS
;
714 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
716 ZeroMem (&SenseData
, sizeof (SenseData
));
717 SenseDataLength
= sizeof (SenseData
);
722 if (Buffer
== NULL
) {
723 return EFI_INVALID_PARAMETER
;
726 if (BufferSize
== 0) {
730 if ((DeviceIndex
== 0) || (DeviceIndex
> UFS_PEIM_MAX_LUNS
)) {
731 return EFI_INVALID_PARAMETER
;
734 Lun
= DeviceIndex
- 1;
735 if ((Private
->Luns
.BitMask
& (BIT0
<< Lun
)) == 0) {
736 return EFI_ACCESS_DENIED
;
739 BlockSize
= Private
->Media
[Lun
].BlockSize
;
741 if (BufferSize
% BlockSize
!= 0) {
742 Status
= EFI_BAD_BUFFER_SIZE
;
745 if (StartLBA
> Private
->Media
[Lun
].LastBlock
) {
746 Status
= EFI_INVALID_PARAMETER
;
749 NumberOfBlocks
= BufferSize
/ BlockSize
;
752 Status
= UfsPeimTestUnitReady (
758 if (!EFI_ERROR (Status
)) {
762 if (SenseDataLength
== 0) {
766 Status
= UfsPeimParsingSenseKeys (&(Private
->Media
[Lun
]), &SenseData
, &NeedRetry
);
767 if (EFI_ERROR (Status
)) {
768 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
,
801 Gets the count of block I/O devices that one specific block driver detects.
803 This function is used for getting the count of block I/O devices that one
804 specific block driver detects. To the PEI ATAPI driver, it returns the number
805 of all the detected ATAPI devices it detects during the enumeration process.
806 To the PEI legacy floppy driver, it returns the number of all the legacy
807 devices it finds during its enumeration process. If no device is detected,
808 then the function will return zero.
810 @param[in] PeiServices General-purpose services that are available
812 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
814 @param[out] NumberBlockDevices The number of block I/O devices discovered.
816 @retval EFI_SUCCESS The operation performed successfully.
821 UfsBlockIoPeimGetDeviceNo2 (
822 IN EFI_PEI_SERVICES
**PeiServices
,
823 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
824 OUT UINTN
*NumberBlockDevices
828 // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
829 // At PEI phase, we will only expose normal Luns to user.
830 // For those disabled Lun, when user try to access it, the operation would fail.
832 *NumberBlockDevices
= UFS_PEIM_MAX_LUNS
;
837 Gets a block device's media information.
839 This function will provide the caller with the specified block device's media
840 information. If the media changes, calling this function will update the media
841 information accordingly.
843 @param[in] PeiServices General-purpose services that are available to every
845 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
846 @param[in] DeviceIndex Specifies the block device to which the function wants
847 to talk. Because the driver that implements Block I/O
848 PPIs will manage multiple block devices, the PPIs that
849 want to talk to a single device must specify the
850 device index that was assigned during the enumeration
851 process. This index is a number from one to
853 @param[out] MediaInfo The media information of the specified block media.
854 The caller is responsible for the ownership of this
858 The MediaInfo structure describes an enumeration of possible block device
859 types. This enumeration exists because no device paths are actually passed
860 across interfaces that describe the type or class of hardware that is publishing
861 the block I/O interface. This enumeration will allow for policy decisions
862 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
863 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
864 by a given device type, they should be reported in ascending order; this
865 order also applies to nested partitions, such as legacy MBR, where the
866 outermost partitions would have precedence in the reporting order. The
867 same logic applies to systems such as IDE that have precedence relationships
868 like "Master/Slave" or "Primary/Secondary". The master device should be
869 reported first, the slave second.
871 @retval EFI_SUCCESS Media information about the specified block device
872 was obtained successfully.
873 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
879 UfsBlockIoPeimGetMediaInfo2 (
880 IN EFI_PEI_SERVICES
**PeiServices
,
881 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
882 IN UINTN DeviceIndex
,
883 OUT EFI_PEI_BLOCK_IO2_MEDIA
*MediaInfo
887 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
888 EFI_PEI_BLOCK_IO_MEDIA Media
;
891 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
893 Status
= UfsBlockIoPeimGetMediaInfo (
899 if (EFI_ERROR (Status
)) {
903 Lun
= DeviceIndex
- 1;
904 CopyMem (MediaInfo
, &(Private
->Media
[Lun
]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA
));
909 Reads the requested number of blocks from the specified block device.
911 The function reads the requested number of blocks from the device. All the
912 blocks are read, or an error is returned. If there is no media in the device,
913 the function returns EFI_NO_MEDIA.
915 @param[in] PeiServices General-purpose services that are available to
917 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
918 @param[in] DeviceIndex Specifies the block device to which the function wants
919 to talk. Because the driver that implements Block I/O
920 PPIs will manage multiple block devices, PPIs that
921 want to talk to a single device must specify the device
922 index that was assigned during the enumeration process.
923 This index is a number from one to NumberBlockDevices.
924 @param[in] StartLBA The starting logical block address (LBA) to read from
926 @param[in] BufferSize The size of the Buffer in bytes. This number must be
927 a multiple of the intrinsic block size of the device.
928 @param[out] Buffer A pointer to the destination buffer for the data.
929 The caller is responsible for the ownership of the
932 @retval EFI_SUCCESS The data was read correctly from the device.
933 @retval EFI_DEVICE_ERROR The device reported an error while attempting
934 to perform the read operation.
935 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
936 valid, or the buffer is not properly aligned.
937 @retval EFI_NO_MEDIA There is no media in the device.
938 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
939 the intrinsic block size of the device.
944 UfsBlockIoPeimReadBlocks2 (
945 IN EFI_PEI_SERVICES
**PeiServices
,
946 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
947 IN UINTN DeviceIndex
,
948 IN EFI_PEI_LBA StartLBA
,
954 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
956 Status
= EFI_SUCCESS
;
957 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
959 Status
= UfsBlockIoPeimReadBlocks (
971 One notified function to cleanup the allocated DMA buffers at the end of PEI.
973 @param[in] PeiServices Pointer to PEI Services Table.
974 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
975 event that caused this function to execute.
976 @param[in] Ppi Pointer to the PPI data associated with this function.
978 @retval EFI_SUCCESS The function completes successfully
984 IN EFI_PEI_SERVICES
**PeiServices
,
985 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
989 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
991 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor
);
993 if ((Private
->Pool
!= NULL
) && (Private
->Pool
->Head
!= NULL
)) {
994 UfsPeimFreeMemPool (Private
->Pool
);
997 if (Private
->UtpTmrlBase
!= NULL
) {
999 EFI_SIZE_TO_PAGES (Private
->Nutmrs
* sizeof (UTP_TMRD
)),
1000 Private
->UtpTmrlBase
,
1001 Private
->TmrlMapping
1005 if (Private
->UtpTrlBase
!= NULL
) {
1007 EFI_SIZE_TO_PAGES (Private
->Nutrs
* sizeof (UTP_TRD
)),
1008 Private
->UtpTrlBase
,
1013 UfsControllerStop (Private
);
1019 The user code starts with this function.
1021 @param FileHandle Handle of the file being invoked.
1022 @param PeiServices Describes the list of possible PEI Services.
1024 @retval EFI_SUCCESS The driver is successfully initialized.
1025 @retval Others Can't initialize the driver.
1030 InitializeUfsBlockIoPeim (
1031 IN EFI_PEI_FILE_HANDLE FileHandle
,
1032 IN CONST EFI_PEI_SERVICES
**PeiServices
1036 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
1037 EDKII_UFS_HOST_CONTROLLER_PPI
*UfsHcPpi
;
1039 UFS_CONFIG_DESC Config
;
1044 // Shadow this PEIM to run from memory
1046 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
1051 // locate ufs host controller PPI
1053 Status
= PeiServicesLocatePpi (
1054 &gEdkiiPeiUfsHostControllerPpiGuid
,
1059 if (EFI_ERROR (Status
)) {
1060 return EFI_DEVICE_ERROR
;
1068 Status
= UfsHcPpi
->GetUfsHcMmioBar (UfsHcPpi
, Controller
, &MmioBase
);
1070 // When status is error, meant no controller is found
1072 if (EFI_ERROR (Status
)) {
1076 Private
= AllocateCopyPool (sizeof (UFS_PEIM_HC_PRIVATE_DATA
), &gUfsHcPeimTemplate
);
1077 if (Private
== NULL
) {
1078 Status
= EFI_OUT_OF_RESOURCES
;
1082 Private
->BlkIoPpiList
.Ppi
= &Private
->BlkIoPpi
;
1083 Private
->BlkIo2PpiList
.Ppi
= &Private
->BlkIo2Ppi
;
1084 Private
->UfsHcBase
= MmioBase
;
1087 // Initialize the memory pool which will be used in all transactions.
1089 Status
= UfsPeimInitMemPool (Private
);
1090 if (EFI_ERROR (Status
)) {
1091 Status
= EFI_OUT_OF_RESOURCES
;
1096 // Initialize UFS Host Controller H/W.
1098 Status
= UfsControllerInit (Private
);
1099 if (EFI_ERROR (Status
)) {
1100 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Host Controller Initialization Error, Status = %r\n", Status
));
1106 // UFS 2.0 spec Section 13.1.3.3:
1107 // At the end of the UFS Interconnect Layer initialization on both host and device side,
1108 // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready.
1110 Status
= UfsExecNopCmds (Private
);
1111 if (EFI_ERROR (Status
)) {
1112 DEBUG ((EFI_D_ERROR
, "Ufs Sending NOP IN command Error, Status = %r\n", Status
));
1118 // The host enables the device initialization completion by setting fDeviceInit flag.
1120 Status
= UfsSetFlag (Private
, UfsFlagDevInit
);
1121 if (EFI_ERROR (Status
)) {
1122 DEBUG ((EFI_D_ERROR
, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status
));
1128 // Get Ufs Device's Lun Info by reading Configuration Descriptor.
1130 Status
= UfsRwDeviceDesc (Private
, TRUE
, UfsConfigDesc
, 0, 0, &Config
, sizeof (UFS_CONFIG_DESC
));
1131 if (EFI_ERROR (Status
)) {
1132 DEBUG ((EFI_D_ERROR
, "Ufs Get Configuration Descriptor Error, Status = %r\n", Status
));
1137 for (Index
= 0; Index
< UFS_PEIM_MAX_LUNS
; Index
++) {
1138 if (Config
.UnitDescConfParams
[Index
].LunEn
!= 0) {
1139 Private
->Luns
.BitMask
|= (BIT0
<< Index
);
1140 DEBUG ((EFI_D_INFO
, "Ufs %d Lun %d is enabled\n", Controller
, Index
));
1144 PeiServicesInstallPpi (&Private
->BlkIoPpiList
);
1145 PeiServicesNotifyPpi (&Private
->EndOfPeiNotifyList
);