3 Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 #include "UfsBlockIoPei.h"
17 // Template for UFS HC Peim Private Data.
19 UFS_PEIM_HC_PRIVATE_DATA gUfsHcPeimTemplate
= {
20 UFS_PEIM_HC_SIG
, // Signature
24 UfsBlockIoPeimGetDeviceNo
,
25 UfsBlockIoPeimGetMediaInfo
,
26 UfsBlockIoPeimReadBlocks
29 EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION
,
30 UfsBlockIoPeimGetDeviceNo2
,
31 UfsBlockIoPeimGetMediaInfo2
,
32 UfsBlockIoPeimReadBlocks2
35 EFI_PEI_PPI_DESCRIPTOR_PPI
,
36 &gEfiPeiVirtualBlockIoPpiGuid
,
40 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
41 &gEfiPeiVirtualBlockIo2PpiGuid
,
110 { // EndOfPeiNotifyList
111 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
112 &gEfiEndOfPeiSignalPpiGuid
,
126 UFS_LUN_0
, // Ufs Common Lun 0
127 UFS_LUN_1
, // Ufs Common Lun 1
128 UFS_LUN_2
, // Ufs Common Lun 2
129 UFS_LUN_3
, // Ufs Common Lun 3
130 UFS_LUN_4
, // Ufs Common Lun 4
131 UFS_LUN_5
, // Ufs Common Lun 5
132 UFS_LUN_6
, // Ufs Common Lun 6
133 UFS_LUN_7
, // Ufs Common Lun 7
135 0x0000, // By default exposing all Luns.
141 Execute Request Sense SCSI command on a specific UFS device.
143 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
144 @param[in] Lun The lun on which the SCSI cmd executed.
145 @param[out] DataBuffer A pointer to output sense data.
146 @param[out] DataBufferLength The length of output sense data.
148 @retval EFI_SUCCESS The command executed successfully.
149 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
150 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
154 UfsPeimRequestSense (
155 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
157 OUT VOID
*DataBuffer
,
158 OUT UINT32
*DataBufferLength
161 UFS_SCSI_REQUEST_PACKET Packet
;
162 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIX
];
165 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
166 ZeroMem (Cdb
, sizeof (Cdb
));
168 Cdb
[0] = EFI_SCSI_OP_REQUEST_SENSE
;
170 Packet
.Timeout
= UFS_TIMEOUT
;
172 Packet
.CdbLength
= sizeof (Cdb
);
173 Packet
.DataDirection
= UfsDataIn
;
174 Packet
.InDataBuffer
= DataBuffer
;
175 Packet
.InTransferLength
= *DataBufferLength
;
176 Packet
.SenseData
= NULL
;
177 Packet
.SenseDataLength
= 0;
179 Status
= UfsExecScsiCmds (Private
,(UINT8
)Lun
, &Packet
);
181 if (!EFI_ERROR (Status
)) {
182 *DataBufferLength
= Packet
.InTransferLength
;
189 Execute TEST UNITY READY SCSI command on a specific UFS device.
191 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
192 @param[in] Lun The lun on which the SCSI cmd executed.
193 @param[out] SenseData A pointer to output sense data.
194 @param[out] SenseDataLength The length of output sense data.
196 @retval EFI_SUCCESS The command executed successfully.
197 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
198 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
202 UfsPeimTestUnitReady (
203 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
205 OUT VOID
*SenseData
, OPTIONAL
206 OUT UINT8
*SenseDataLength
209 UFS_SCSI_REQUEST_PACKET Packet
;
210 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIX
];
213 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
214 ZeroMem (Cdb
, sizeof (Cdb
));
216 Cdb
[0] = EFI_SCSI_OP_TEST_UNIT_READY
;
218 Packet
.Timeout
= UFS_TIMEOUT
;
220 Packet
.CdbLength
= sizeof (Cdb
);
221 Packet
.DataDirection
= UfsNoData
;
222 Packet
.SenseData
= SenseData
;
223 Packet
.SenseDataLength
= *SenseDataLength
;
225 Status
= UfsExecScsiCmds (Private
,(UINT8
)Lun
, &Packet
);
227 if (*SenseDataLength
!= 0) {
228 *SenseDataLength
= Packet
.SenseDataLength
;
235 Execute INQUIRY SCSI command on a specific UFS device.
237 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
238 @param[in] Lun The lun on which the SCSI cmd executed.
239 @param[out] Inquiry A pointer to Inquiry data buffer.
240 @param[out] InquiryLengths The length of output Inquiry data.
241 @param[out] SenseData A pointer to output sense data.
242 @param[out] SenseDataLength The length of output sense data.
244 @retval EFI_SUCCESS The command executed successfully.
245 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
246 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
251 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
254 OUT UINT32
*InquiryLength
,
255 OUT VOID
*SenseData
, OPTIONAL
256 OUT UINT8
*SenseDataLength
259 UFS_SCSI_REQUEST_PACKET Packet
;
260 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIX
];
263 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
264 ZeroMem (Cdb
, sizeof (Cdb
));
266 Cdb
[0] = EFI_SCSI_OP_INQUIRY
;
267 Cdb
[4] = sizeof (EFI_SCSI_INQUIRY_DATA
);
269 Packet
.Timeout
= UFS_TIMEOUT
;
271 Packet
.CdbLength
= sizeof (Cdb
);
272 Packet
.InDataBuffer
= Inquiry
;
273 Packet
.InTransferLength
= *InquiryLength
;
274 Packet
.DataDirection
= UfsDataIn
;
275 Packet
.SenseData
= SenseData
;
276 Packet
.SenseDataLength
= *SenseDataLength
;
278 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
280 if (*SenseDataLength
!= 0) {
281 *SenseDataLength
= Packet
.SenseDataLength
;
284 if (!EFI_ERROR (Status
)) {
285 *InquiryLength
= Packet
.InTransferLength
;
292 Execute READ CAPACITY(10) SCSI command on a specific UFS device.
294 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
295 @param[in] Lun The lun on which the SCSI cmd executed.
296 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
297 @param[out] DataLength The length of output READ_CAPACITY data.
298 @param[out] SenseData A pointer to output sense data.
299 @param[out] SenseDataLength The length of output sense data.
301 @retval EFI_SUCCESS The command executed successfully.
302 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
303 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
307 UfsPeimReadCapacity (
308 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
310 OUT VOID
*DataBuffer
,
311 OUT UINT32
*DataLength
,
312 OUT VOID
*SenseData
, OPTIONAL
313 OUT UINT8
*SenseDataLength
316 UFS_SCSI_REQUEST_PACKET Packet
;
317 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_TEN
];
320 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
321 ZeroMem (Cdb
, sizeof (Cdb
));
323 Cdb
[0] = EFI_SCSI_OP_READ_CAPACITY
;
325 Packet
.Timeout
= UFS_TIMEOUT
;
327 Packet
.CdbLength
= sizeof (Cdb
);
328 Packet
.InDataBuffer
= DataBuffer
;
329 Packet
.InTransferLength
= *DataLength
;
330 Packet
.DataDirection
= UfsDataIn
;
331 Packet
.SenseData
= SenseData
;
332 Packet
.SenseDataLength
= *SenseDataLength
;
334 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
336 if (*SenseDataLength
!= 0) {
337 *SenseDataLength
= Packet
.SenseDataLength
;
340 if (!EFI_ERROR (Status
)) {
341 *DataLength
= Packet
.InTransferLength
;
348 Execute READ CAPACITY(16) SCSI command on a specific UFS device.
350 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
351 @param[in] Lun The lun on which the SCSI cmd executed.
352 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
353 @param[out] DataLength The length of output READ_CAPACITY data.
354 @param[out] SenseData A pointer to output sense data.
355 @param[out] SenseDataLength The length of output sense data.
357 @retval EFI_SUCCESS The command executed successfully.
358 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
359 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
363 UfsPeimReadCapacity16 (
364 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
366 OUT VOID
*DataBuffer
,
367 OUT UINT32
*DataLength
,
368 OUT VOID
*SenseData
, OPTIONAL
369 OUT UINT8
*SenseDataLength
372 UFS_SCSI_REQUEST_PACKET Packet
;
373 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIXTEEN
];
376 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
377 ZeroMem (Cdb
, sizeof (Cdb
));
379 Cdb
[0] = EFI_SCSI_OP_READ_CAPACITY16
;
380 Cdb
[1] = 0x10; // Service Action should be 0x10 for UFS device.
381 Cdb
[13] = 0x20; // The maximum number of bytes for returned data.
383 Packet
.Timeout
= UFS_TIMEOUT
;
385 Packet
.CdbLength
= sizeof (Cdb
);
386 Packet
.InDataBuffer
= DataBuffer
;
387 Packet
.InTransferLength
= *DataLength
;
388 Packet
.DataDirection
= UfsDataIn
;
389 Packet
.SenseData
= SenseData
;
390 Packet
.SenseDataLength
= *SenseDataLength
;
392 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
394 if (*SenseDataLength
!= 0) {
395 *SenseDataLength
= Packet
.SenseDataLength
;
398 if (!EFI_ERROR (Status
)) {
399 *DataLength
= Packet
.InTransferLength
;
406 Execute READ (10) SCSI command on a specific UFS device.
408 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
409 @param[in] Lun The lun on which the SCSI cmd executed.
410 @param[in] StartLba The start LBA.
411 @param[in] SectorNum The sector number to be read.
412 @param[out] DataBuffer A pointer to data buffer.
413 @param[out] DataLength The length of output data.
414 @param[out] SenseData A pointer to output sense data.
415 @param[out] SenseDataLength The length of output sense data.
417 @retval EFI_SUCCESS The command executed successfully.
418 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
419 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
424 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
428 OUT VOID
*DataBuffer
,
429 OUT UINT32
*DataLength
,
430 OUT VOID
*SenseData
, OPTIONAL
431 OUT UINT8
*SenseDataLength
434 UFS_SCSI_REQUEST_PACKET Packet
;
435 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_TEN
];
438 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
439 ZeroMem (Cdb
, sizeof (Cdb
));
441 Cdb
[0] = EFI_SCSI_OP_READ10
;
442 WriteUnaligned32 ((UINT32
*)&Cdb
[2], SwapBytes32 ((UINT32
) StartLba
));
443 WriteUnaligned16 ((UINT16
*)&Cdb
[7], SwapBytes16 ((UINT16
) SectorNum
));
445 Packet
.Timeout
= UFS_TIMEOUT
;
447 Packet
.CdbLength
= sizeof (Cdb
);
448 Packet
.InDataBuffer
= DataBuffer
;
449 Packet
.InTransferLength
= *DataLength
;
450 Packet
.DataDirection
= UfsDataIn
;
451 Packet
.SenseData
= SenseData
;
452 Packet
.SenseDataLength
= *SenseDataLength
;
454 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
456 if (*SenseDataLength
!= 0) {
457 *SenseDataLength
= Packet
.SenseDataLength
;
460 if (!EFI_ERROR (Status
)) {
461 *DataLength
= Packet
.InTransferLength
;
468 Execute READ (16) SCSI command on a specific UFS device.
470 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
471 @param[in] Lun The lun on which the SCSI cmd executed.
472 @param[in] StartLba The start LBA.
473 @param[in] SectorNum The sector number to be read.
474 @param[out] DataBuffer A pointer to data buffer.
475 @param[out] DataLength The length of output data.
476 @param[out] SenseData A pointer to output sense data.
477 @param[out] SenseDataLength The length of output sense data.
479 @retval EFI_SUCCESS The command executed successfully.
480 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
481 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
486 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
490 OUT VOID
*DataBuffer
,
491 OUT UINT32
*DataLength
,
492 OUT VOID
*SenseData
, OPTIONAL
493 OUT UINT8
*SenseDataLength
496 UFS_SCSI_REQUEST_PACKET Packet
;
497 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIXTEEN
];
500 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
501 ZeroMem (Cdb
, sizeof (Cdb
));
503 Cdb
[0] = EFI_SCSI_OP_READ16
;
504 WriteUnaligned64 ((UINT64
*)&Cdb
[2], SwapBytes64 (StartLba
));
505 WriteUnaligned32 ((UINT32
*)&Cdb
[10], SwapBytes32 (SectorNum
));
507 Packet
.Timeout
= UFS_TIMEOUT
;
509 Packet
.CdbLength
= sizeof (Cdb
);
510 Packet
.InDataBuffer
= DataBuffer
;
511 Packet
.InTransferLength
= *DataLength
;
512 Packet
.DataDirection
= UfsDataIn
;
513 Packet
.SenseData
= SenseData
;
514 Packet
.SenseDataLength
= *SenseDataLength
;
516 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
518 if (*SenseDataLength
!= 0) {
519 *SenseDataLength
= Packet
.SenseDataLength
;
522 if (!EFI_ERROR (Status
)) {
523 *DataLength
= Packet
.InTransferLength
;
530 Parsing Sense Keys from sense data.
532 @param Media The pointer of EFI_PEI_BLOCK_IO_MEDIA
533 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
534 @param NeedRetry The pointer of action which indicates what is need to retry
536 @retval EFI_DEVICE_ERROR Indicates that error occurs
537 @retval EFI_SUCCESS Successfully to complete the parsing
541 UfsPeimParsingSenseKeys (
542 IN EFI_PEI_BLOCK_IO2_MEDIA
*Media
,
543 IN EFI_SCSI_SENSE_DATA
*SenseData
,
544 OUT BOOLEAN
*NeedRetry
547 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
548 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
549 Media
->MediaPresent
= FALSE
;
551 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Is No Media\n"));
552 return EFI_DEVICE_ERROR
;
555 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
556 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
558 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Is Media Change\n"));
562 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
563 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
565 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Was Reset Before\n"));
569 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_MEDIUM_ERROR
) ||
570 ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
571 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
))) {
573 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Media Error\n"));
574 return EFI_DEVICE_ERROR
;
577 if (SenseData
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
579 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Hardware Error\n"));
580 return EFI_DEVICE_ERROR
;
583 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
584 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_NOT_READY
) &&
585 (SenseData
->Addnl_Sense_Code_Qualifier
== EFI_SCSI_ASCQ_IN_PROGRESS
)) {
587 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Was Reset Before\n"));
592 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
593 return EFI_DEVICE_ERROR
;
598 Gets the count of block I/O devices that one specific block driver detects.
600 This function is used for getting the count of block I/O devices that one
601 specific block driver detects. To the PEI ATAPI driver, it returns the number
602 of all the detected ATAPI devices it detects during the enumeration process.
603 To the PEI legacy floppy driver, it returns the number of all the legacy
604 devices it finds during its enumeration process. If no device is detected,
605 then the function will return zero.
607 @param[in] PeiServices General-purpose services that are available
609 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
611 @param[out] NumberBlockDevices The number of block I/O devices discovered.
613 @retval EFI_SUCCESS The operation performed successfully.
618 UfsBlockIoPeimGetDeviceNo (
619 IN EFI_PEI_SERVICES
**PeiServices
,
620 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
621 OUT UINTN
*NumberBlockDevices
625 // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
626 // At PEI phase, we will only expose normal Luns to user.
627 // For those disabled Lun, when user try to access it, the operation would fail.
629 *NumberBlockDevices
= UFS_PEIM_MAX_LUNS
;
634 Gets a block device's media information.
636 This function will provide the caller with the specified block device's media
637 information. If the media changes, calling this function will update the media
638 information accordingly.
640 @param[in] PeiServices General-purpose services that are available to every
642 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
643 @param[in] DeviceIndex Specifies the block device to which the function wants
644 to talk. Because the driver that implements Block I/O
645 PPIs will manage multiple block devices, the PPIs that
646 want to talk to a single device must specify the
647 device index that was assigned during the enumeration
648 process. This index is a number from one to
650 @param[out] MediaInfo The media information of the specified block media.
651 The caller is responsible for the ownership of this
655 The MediaInfo structure describes an enumeration of possible block device
656 types. This enumeration exists because no device paths are actually passed
657 across interfaces that describe the type or class of hardware that is publishing
658 the block I/O interface. This enumeration will allow for policy decisions
659 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
660 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
661 by a given device type, they should be reported in ascending order; this
662 order also applies to nested partitions, such as legacy MBR, where the
663 outermost partitions would have precedence in the reporting order. The
664 same logic applies to systems such as IDE that have precedence relationships
665 like "Master/Slave" or "Primary/Secondary". The master device should be
666 reported first, the slave second.
668 @retval EFI_SUCCESS Media information about the specified block device
669 was obtained successfully.
670 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
676 UfsBlockIoPeimGetMediaInfo (
677 IN EFI_PEI_SERVICES
**PeiServices
,
678 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
679 IN UINTN DeviceIndex
,
680 OUT EFI_PEI_BLOCK_IO_MEDIA
*MediaInfo
684 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
685 EFI_SCSI_SENSE_DATA SenseData
;
686 UINT8 SenseDataLength
;
687 EFI_SCSI_DISK_CAPACITY_DATA Capacity
;
688 EFI_SCSI_DISK_CAPACITY_DATA16 Capacity16
;
692 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
695 if (DeviceIndex
>= UFS_PEIM_MAX_LUNS
) {
696 return EFI_INVALID_PARAMETER
;
699 if ((Private
->Luns
.BitMask
& (BIT0
<< DeviceIndex
)) == 0) {
700 return EFI_ACCESS_DENIED
;
703 ZeroMem (&SenseData
, sizeof (SenseData
));
704 ZeroMem (&Capacity
, sizeof (Capacity
));
705 ZeroMem (&Capacity16
, sizeof (Capacity16
));
706 SenseDataLength
= sizeof (SenseData
);
708 // First test unit ready
711 Status
= UfsPeimTestUnitReady (
717 if (!EFI_ERROR (Status
)) {
721 if (SenseDataLength
== 0) {
725 Status
= UfsPeimParsingSenseKeys (&(Private
->Media
[DeviceIndex
]), &SenseData
, &NeedRetry
);
726 if (EFI_ERROR (Status
)) {
727 return EFI_DEVICE_ERROR
;
732 DataLength
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
734 Status
= UfsPeimReadCapacity (Private
, DeviceIndex
, &Capacity
, (UINT32
*)&DataLength
, NULL
, &SenseDataLength
);
735 if (EFI_ERROR (Status
)) {
736 return EFI_DEVICE_ERROR
;
739 if ((Capacity
.LastLba3
== 0xff) && (Capacity
.LastLba2
== 0xff) &&
740 (Capacity
.LastLba1
== 0xff) && (Capacity
.LastLba0
== 0xff)) {
741 DataLength
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
743 Status
= UfsPeimReadCapacity16 (Private
, DeviceIndex
, &Capacity16
, (UINT32
*)&DataLength
, NULL
, &SenseDataLength
);
744 if (EFI_ERROR (Status
)) {
745 return EFI_DEVICE_ERROR
;
747 Private
->Media
[DeviceIndex
].LastBlock
= ((UINT32
)Capacity16
.LastLba3
<< 24) | (Capacity16
.LastLba2
<< 16) | (Capacity16
.LastLba1
<< 8) | Capacity16
.LastLba0
;
748 Private
->Media
[DeviceIndex
].LastBlock
|= LShiftU64 ((UINT64
)Capacity16
.LastLba7
, 56) | LShiftU64((UINT64
)Capacity16
.LastLba6
, 48) | LShiftU64 ((UINT64
)Capacity16
.LastLba5
, 40) | LShiftU64 ((UINT64
)Capacity16
.LastLba4
, 32);
749 Private
->Media
[DeviceIndex
].BlockSize
= (Capacity16
.BlockSize3
<< 24) | (Capacity16
.BlockSize2
<< 16) | (Capacity16
.BlockSize1
<< 8) | Capacity16
.BlockSize0
;
751 Private
->Media
[DeviceIndex
].LastBlock
= ((UINT32
)Capacity
.LastLba3
<< 24) | (Capacity
.LastLba2
<< 16) | (Capacity
.LastLba1
<< 8) | Capacity
.LastLba0
;
752 Private
->Media
[DeviceIndex
].BlockSize
= (Capacity
.BlockSize3
<< 24) | (Capacity
.BlockSize2
<< 16) | (Capacity
.BlockSize1
<< 8) | Capacity
.BlockSize0
;
755 MediaInfo
->DeviceType
= UfsDevice
;
756 MediaInfo
->MediaPresent
= Private
->Media
[DeviceIndex
].MediaPresent
;
757 MediaInfo
->LastBlock
= (UINTN
)Private
->Media
[DeviceIndex
].LastBlock
;
758 MediaInfo
->BlockSize
= Private
->Media
[DeviceIndex
].BlockSize
;
764 Reads the requested number of blocks from the specified block device.
766 The function reads the requested number of blocks from the device. All the
767 blocks are read, or an error is returned. If there is no media in the device,
768 the function returns EFI_NO_MEDIA.
770 @param[in] PeiServices General-purpose services that are available to
772 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
773 @param[in] DeviceIndex Specifies the block device to which the function wants
774 to talk. Because the driver that implements Block I/O
775 PPIs will manage multiple block devices, PPIs that
776 want to talk to a single device must specify the device
777 index that was assigned during the enumeration process.
778 This index is a number from one to NumberBlockDevices.
779 @param[in] StartLBA The starting logical block address (LBA) to read from
781 @param[in] BufferSize The size of the Buffer in bytes. This number must be
782 a multiple of the intrinsic block size of the device.
783 @param[out] Buffer A pointer to the destination buffer for the data.
784 The caller is responsible for the ownership of the
787 @retval EFI_SUCCESS The data was read correctly from the device.
788 @retval EFI_DEVICE_ERROR The device reported an error while attempting
789 to perform the read operation.
790 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
791 valid, or the buffer is not properly aligned.
792 @retval EFI_NO_MEDIA There is no media in the device.
793 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
794 the intrinsic block size of the device.
799 UfsBlockIoPeimReadBlocks (
800 IN EFI_PEI_SERVICES
**PeiServices
,
801 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
802 IN UINTN DeviceIndex
,
803 IN EFI_PEI_LBA StartLBA
,
810 UINTN NumberOfBlocks
;
811 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
812 EFI_SCSI_SENSE_DATA SenseData
;
813 UINT8 SenseDataLength
;
816 Status
= EFI_SUCCESS
;
818 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
820 ZeroMem (&SenseData
, sizeof (SenseData
));
821 SenseDataLength
= sizeof (SenseData
);
826 if (Buffer
== NULL
) {
827 return EFI_INVALID_PARAMETER
;
830 if (BufferSize
== 0) {
834 if (DeviceIndex
>= UFS_PEIM_MAX_LUNS
) {
835 return EFI_INVALID_PARAMETER
;
838 if ((Private
->Luns
.BitMask
& (BIT0
<< DeviceIndex
)) == 0) {
839 return EFI_ACCESS_DENIED
;
842 BlockSize
= Private
->Media
[DeviceIndex
].BlockSize
;
844 if (BufferSize
% BlockSize
!= 0) {
845 Status
= EFI_BAD_BUFFER_SIZE
;
848 if (StartLBA
> Private
->Media
[DeviceIndex
].LastBlock
) {
849 Status
= EFI_INVALID_PARAMETER
;
852 NumberOfBlocks
= BufferSize
/ BlockSize
;
855 Status
= UfsPeimTestUnitReady (
861 if (!EFI_ERROR (Status
)) {
865 if (SenseDataLength
== 0) {
869 Status
= UfsPeimParsingSenseKeys (&(Private
->Media
[DeviceIndex
]), &SenseData
, &NeedRetry
);
870 if (EFI_ERROR (Status
)) {
871 return EFI_DEVICE_ERROR
;
877 if (Private
->Media
[DeviceIndex
].LastBlock
< 0xfffffffful
) {
878 Status
= UfsPeimRead10 (
882 (UINT32
)NumberOfBlocks
,
884 (UINT32
*)&BufferSize
,
889 Status
= UfsPeimRead16 (
893 (UINT32
)NumberOfBlocks
,
895 (UINT32
*)&BufferSize
,
904 Gets the count of block I/O devices that one specific block driver detects.
906 This function is used for getting the count of block I/O devices that one
907 specific block driver detects. To the PEI ATAPI driver, it returns the number
908 of all the detected ATAPI devices it detects during the enumeration process.
909 To the PEI legacy floppy driver, it returns the number of all the legacy
910 devices it finds during its enumeration process. If no device is detected,
911 then the function will return zero.
913 @param[in] PeiServices General-purpose services that are available
915 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
917 @param[out] NumberBlockDevices The number of block I/O devices discovered.
919 @retval EFI_SUCCESS The operation performed successfully.
924 UfsBlockIoPeimGetDeviceNo2 (
925 IN EFI_PEI_SERVICES
**PeiServices
,
926 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
927 OUT UINTN
*NumberBlockDevices
931 // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
932 // At PEI phase, we will only expose normal Luns to user.
933 // For those disabled Lun, when user try to access it, the operation would fail.
935 *NumberBlockDevices
= UFS_PEIM_MAX_LUNS
;
940 Gets a block device's media information.
942 This function will provide the caller with the specified block device's media
943 information. If the media changes, calling this function will update the media
944 information accordingly.
946 @param[in] PeiServices General-purpose services that are available to every
948 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
949 @param[in] DeviceIndex Specifies the block device to which the function wants
950 to talk. Because the driver that implements Block I/O
951 PPIs will manage multiple block devices, the PPIs that
952 want to talk to a single device must specify the
953 device index that was assigned during the enumeration
954 process. This index is a number from one to
956 @param[out] MediaInfo The media information of the specified block media.
957 The caller is responsible for the ownership of this
961 The MediaInfo structure describes an enumeration of possible block device
962 types. This enumeration exists because no device paths are actually passed
963 across interfaces that describe the type or class of hardware that is publishing
964 the block I/O interface. This enumeration will allow for policy decisions
965 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
966 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
967 by a given device type, they should be reported in ascending order; this
968 order also applies to nested partitions, such as legacy MBR, where the
969 outermost partitions would have precedence in the reporting order. The
970 same logic applies to systems such as IDE that have precedence relationships
971 like "Master/Slave" or "Primary/Secondary". The master device should be
972 reported first, the slave second.
974 @retval EFI_SUCCESS Media information about the specified block device
975 was obtained successfully.
976 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
982 UfsBlockIoPeimGetMediaInfo2 (
983 IN EFI_PEI_SERVICES
**PeiServices
,
984 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
985 IN UINTN DeviceIndex
,
986 OUT EFI_PEI_BLOCK_IO2_MEDIA
*MediaInfo
990 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
991 EFI_PEI_BLOCK_IO_MEDIA Media
;
993 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
995 Status
= UfsBlockIoPeimGetMediaInfo (
1001 if (EFI_ERROR (Status
)) {
1005 CopyMem (MediaInfo
, &(Private
->Media
[DeviceIndex
]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA
));
1010 Reads the requested number of blocks from the specified block device.
1012 The function reads the requested number of blocks from the device. All the
1013 blocks are read, or an error is returned. If there is no media in the device,
1014 the function returns EFI_NO_MEDIA.
1016 @param[in] PeiServices General-purpose services that are available to
1018 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
1019 @param[in] DeviceIndex Specifies the block device to which the function wants
1020 to talk. Because the driver that implements Block I/O
1021 PPIs will manage multiple block devices, PPIs that
1022 want to talk to a single device must specify the device
1023 index that was assigned during the enumeration process.
1024 This index is a number from one to NumberBlockDevices.
1025 @param[in] StartLBA The starting logical block address (LBA) to read from
1027 @param[in] BufferSize The size of the Buffer in bytes. This number must be
1028 a multiple of the intrinsic block size of the device.
1029 @param[out] Buffer A pointer to the destination buffer for the data.
1030 The caller is responsible for the ownership of the
1033 @retval EFI_SUCCESS The data was read correctly from the device.
1034 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1035 to perform the read operation.
1036 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
1037 valid, or the buffer is not properly aligned.
1038 @retval EFI_NO_MEDIA There is no media in the device.
1039 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
1040 the intrinsic block size of the device.
1045 UfsBlockIoPeimReadBlocks2 (
1046 IN EFI_PEI_SERVICES
**PeiServices
,
1047 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
1048 IN UINTN DeviceIndex
,
1049 IN EFI_PEI_LBA StartLBA
,
1050 IN UINTN BufferSize
,
1055 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
1057 Status
= EFI_SUCCESS
;
1058 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
1060 Status
= UfsBlockIoPeimReadBlocks (
1072 One notified function to cleanup the allocated DMA buffers at the end of PEI.
1074 @param[in] PeiServices Pointer to PEI Services Table.
1075 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
1076 event that caused this function to execute.
1077 @param[in] Ppi Pointer to the PPI data associated with this function.
1079 @retval EFI_SUCCESS The function completes successfully
1085 IN EFI_PEI_SERVICES
**PeiServices
,
1086 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
1090 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
1092 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor
);
1094 if ((Private
->Pool
!= NULL
) && (Private
->Pool
->Head
!= NULL
)) {
1095 UfsPeimFreeMemPool (Private
->Pool
);
1098 if (Private
->UtpTmrlBase
!= NULL
) {
1100 EFI_SIZE_TO_PAGES (Private
->Nutmrs
* sizeof (UTP_TMRD
)),
1101 Private
->UtpTmrlBase
,
1102 Private
->TmrlMapping
1106 if (Private
->UtpTrlBase
!= NULL
) {
1108 EFI_SIZE_TO_PAGES (Private
->Nutrs
* sizeof (UTP_TRD
)),
1109 Private
->UtpTrlBase
,
1114 UfsControllerStop (Private
);
1120 The user code starts with this function.
1122 @param FileHandle Handle of the file being invoked.
1123 @param PeiServices Describes the list of possible PEI Services.
1125 @retval EFI_SUCCESS The driver is successfully initialized.
1126 @retval Others Can't initialize the driver.
1131 InitializeUfsBlockIoPeim (
1132 IN EFI_PEI_FILE_HANDLE FileHandle
,
1133 IN CONST EFI_PEI_SERVICES
**PeiServices
1137 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
1138 EDKII_UFS_HOST_CONTROLLER_PPI
*UfsHcPpi
;
1140 UFS_CONFIG_DESC Config
;
1145 // Shadow this PEIM to run from memory
1147 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
1152 // locate ufs host controller PPI
1154 Status
= PeiServicesLocatePpi (
1155 &gEdkiiPeiUfsHostControllerPpiGuid
,
1160 if (EFI_ERROR (Status
)) {
1161 return EFI_DEVICE_ERROR
;
1169 Status
= UfsHcPpi
->GetUfsHcMmioBar (UfsHcPpi
, Controller
, &MmioBase
);
1171 // When status is error, meant no controller is found
1173 if (EFI_ERROR (Status
)) {
1177 Private
= AllocateCopyPool (sizeof (UFS_PEIM_HC_PRIVATE_DATA
), &gUfsHcPeimTemplate
);
1178 if (Private
== NULL
) {
1179 Status
= EFI_OUT_OF_RESOURCES
;
1183 Private
->BlkIoPpiList
.Ppi
= &Private
->BlkIoPpi
;
1184 Private
->BlkIo2PpiList
.Ppi
= &Private
->BlkIo2Ppi
;
1185 Private
->UfsHcBase
= MmioBase
;
1188 // Initialize the memory pool which will be used in all transactions.
1190 Status
= UfsPeimInitMemPool (Private
);
1191 if (EFI_ERROR (Status
)) {
1192 Status
= EFI_OUT_OF_RESOURCES
;
1197 // Initialize UFS Host Controller H/W.
1199 Status
= UfsControllerInit (Private
);
1200 if (EFI_ERROR (Status
)) {
1201 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Host Controller Initialization Error, Status = %r\n", Status
));
1207 // UFS 2.0 spec Section 13.1.3.3:
1208 // At the end of the UFS Interconnect Layer initialization on both host and device side,
1209 // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready.
1211 Status
= UfsExecNopCmds (Private
);
1212 if (EFI_ERROR (Status
)) {
1213 DEBUG ((EFI_D_ERROR
, "Ufs Sending NOP IN command Error, Status = %r\n", Status
));
1219 // The host enables the device initialization completion by setting fDeviceInit flag.
1221 Status
= UfsSetFlag (Private
, UfsFlagDevInit
);
1222 if (EFI_ERROR (Status
)) {
1223 DEBUG ((EFI_D_ERROR
, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status
));
1229 // Get Ufs Device's Lun Info by reading Configuration Descriptor.
1231 Status
= UfsRwDeviceDesc (Private
, TRUE
, UfsConfigDesc
, 0, 0, &Config
, sizeof (UFS_CONFIG_DESC
));
1232 if (EFI_ERROR (Status
)) {
1233 DEBUG ((EFI_D_ERROR
, "Ufs Get Configuration Descriptor Error, Status = %r\n", Status
));
1238 for (Index
= 0; Index
< UFS_PEIM_MAX_LUNS
; Index
++) {
1239 if (Config
.UnitDescConfParams
[Index
].LunEn
!= 0) {
1240 Private
->Luns
.BitMask
|= (BIT0
<< Index
);
1241 DEBUG ((EFI_D_INFO
, "Ufs %d Lun %d is enabled\n", Controller
, Index
));
1245 PeiServicesInstallPpi (&Private
->BlkIoPpiList
);
1246 PeiServicesNotifyPpi (&Private
->EndOfPeiNotifyList
);