3 Copyright (c) 2014 - 2017, 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
,
119 UFS_LUN_0
, // Ufs Common Lun 0
120 UFS_LUN_1
, // Ufs Common Lun 1
121 UFS_LUN_2
, // Ufs Common Lun 2
122 UFS_LUN_3
, // Ufs Common Lun 3
123 UFS_LUN_4
, // Ufs Common Lun 4
124 UFS_LUN_5
, // Ufs Common Lun 5
125 UFS_LUN_6
, // Ufs Common Lun 6
126 UFS_LUN_7
, // Ufs Common Lun 7
128 0x0000, // By default exposing all Luns.
134 Execute Request Sense SCSI command on a specific UFS device.
136 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
137 @param[in] Lun The lun on which the SCSI cmd executed.
138 @param[out] DataBuffer A pointer to output sense data.
139 @param[out] DataBufferLength The length of output sense data.
141 @retval EFI_SUCCESS The command executed successfully.
142 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
143 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
147 UfsPeimRequestSense (
148 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
150 OUT VOID
*DataBuffer
,
151 OUT UINT32
*DataBufferLength
154 UFS_SCSI_REQUEST_PACKET Packet
;
155 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIX
];
158 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
159 ZeroMem (Cdb
, sizeof (Cdb
));
161 Cdb
[0] = EFI_SCSI_OP_REQUEST_SENSE
;
163 Packet
.Timeout
= UFS_TIMEOUT
;
165 Packet
.CdbLength
= sizeof (Cdb
);
166 Packet
.DataDirection
= UfsDataIn
;
167 Packet
.InDataBuffer
= DataBuffer
;
168 Packet
.InTransferLength
= *DataBufferLength
;
169 Packet
.SenseData
= NULL
;
170 Packet
.SenseDataLength
= 0;
172 Status
= UfsExecScsiCmds (Private
,(UINT8
)Lun
, &Packet
);
174 if (!EFI_ERROR (Status
)) {
175 *DataBufferLength
= Packet
.InTransferLength
;
182 Execute TEST UNITY READY SCSI command on a specific UFS device.
184 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
185 @param[in] Lun The lun on which the SCSI cmd executed.
186 @param[out] SenseData A pointer to output sense data.
187 @param[out] SenseDataLength The length of output sense data.
189 @retval EFI_SUCCESS The command executed successfully.
190 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
191 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
195 UfsPeimTestUnitReady (
196 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
198 OUT VOID
*SenseData
, OPTIONAL
199 OUT UINT8
*SenseDataLength
202 UFS_SCSI_REQUEST_PACKET Packet
;
203 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIX
];
206 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
207 ZeroMem (Cdb
, sizeof (Cdb
));
209 Cdb
[0] = EFI_SCSI_OP_TEST_UNIT_READY
;
211 Packet
.Timeout
= UFS_TIMEOUT
;
213 Packet
.CdbLength
= sizeof (Cdb
);
214 Packet
.DataDirection
= UfsNoData
;
215 Packet
.SenseData
= SenseData
;
216 Packet
.SenseDataLength
= *SenseDataLength
;
218 Status
= UfsExecScsiCmds (Private
,(UINT8
)Lun
, &Packet
);
220 if (*SenseDataLength
!= 0) {
221 *SenseDataLength
= Packet
.SenseDataLength
;
228 Execute INQUIRY SCSI command on a specific UFS device.
230 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
231 @param[in] Lun The lun on which the SCSI cmd executed.
232 @param[out] Inquiry A pointer to Inquiry data buffer.
233 @param[out] InquiryLengths The length of output Inquiry data.
234 @param[out] SenseData A pointer to output sense data.
235 @param[out] SenseDataLength The length of output sense data.
237 @retval EFI_SUCCESS The command executed successfully.
238 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
239 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
244 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
247 OUT UINT32
*InquiryLength
,
248 OUT VOID
*SenseData
, OPTIONAL
249 OUT UINT8
*SenseDataLength
252 UFS_SCSI_REQUEST_PACKET Packet
;
253 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIX
];
256 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
257 ZeroMem (Cdb
, sizeof (Cdb
));
259 Cdb
[0] = EFI_SCSI_OP_INQUIRY
;
260 Cdb
[4] = sizeof (EFI_SCSI_INQUIRY_DATA
);
262 Packet
.Timeout
= UFS_TIMEOUT
;
264 Packet
.CdbLength
= sizeof (Cdb
);
265 Packet
.InDataBuffer
= Inquiry
;
266 Packet
.InTransferLength
= *InquiryLength
;
267 Packet
.DataDirection
= UfsDataIn
;
268 Packet
.SenseData
= SenseData
;
269 Packet
.SenseDataLength
= *SenseDataLength
;
271 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
273 if (*SenseDataLength
!= 0) {
274 *SenseDataLength
= Packet
.SenseDataLength
;
277 if (!EFI_ERROR (Status
)) {
278 *InquiryLength
= Packet
.InTransferLength
;
285 Execute READ CAPACITY(10) SCSI command on a specific UFS device.
287 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
288 @param[in] Lun The lun on which the SCSI cmd executed.
289 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
290 @param[out] DataLength The length of output READ_CAPACITY data.
291 @param[out] SenseData A pointer to output sense data.
292 @param[out] SenseDataLength The length of output sense data.
294 @retval EFI_SUCCESS The command executed successfully.
295 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
296 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
300 UfsPeimReadCapacity (
301 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
303 OUT VOID
*DataBuffer
,
304 OUT UINT32
*DataLength
,
305 OUT VOID
*SenseData
, OPTIONAL
306 OUT UINT8
*SenseDataLength
309 UFS_SCSI_REQUEST_PACKET Packet
;
310 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_TEN
];
313 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
314 ZeroMem (Cdb
, sizeof (Cdb
));
316 Cdb
[0] = EFI_SCSI_OP_READ_CAPACITY
;
318 Packet
.Timeout
= UFS_TIMEOUT
;
320 Packet
.CdbLength
= sizeof (Cdb
);
321 Packet
.InDataBuffer
= DataBuffer
;
322 Packet
.InTransferLength
= *DataLength
;
323 Packet
.DataDirection
= UfsDataIn
;
324 Packet
.SenseData
= SenseData
;
325 Packet
.SenseDataLength
= *SenseDataLength
;
327 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
329 if (*SenseDataLength
!= 0) {
330 *SenseDataLength
= Packet
.SenseDataLength
;
333 if (!EFI_ERROR (Status
)) {
334 *DataLength
= Packet
.InTransferLength
;
341 Execute READ CAPACITY(16) SCSI command on a specific UFS device.
343 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
344 @param[in] Lun The lun on which the SCSI cmd executed.
345 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
346 @param[out] DataLength The length of output READ_CAPACITY data.
347 @param[out] SenseData A pointer to output sense data.
348 @param[out] SenseDataLength The length of output sense data.
350 @retval EFI_SUCCESS The command executed successfully.
351 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
352 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
356 UfsPeimReadCapacity16 (
357 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
359 OUT VOID
*DataBuffer
,
360 OUT UINT32
*DataLength
,
361 OUT VOID
*SenseData
, OPTIONAL
362 OUT UINT8
*SenseDataLength
365 UFS_SCSI_REQUEST_PACKET Packet
;
366 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIXTEEN
];
369 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
370 ZeroMem (Cdb
, sizeof (Cdb
));
372 Cdb
[0] = EFI_SCSI_OP_READ_CAPACITY16
;
373 Cdb
[1] = 0x10; // Service Action should be 0x10 for UFS device.
374 Cdb
[13] = 0x20; // The maximum number of bytes for returned data.
376 Packet
.Timeout
= UFS_TIMEOUT
;
378 Packet
.CdbLength
= sizeof (Cdb
);
379 Packet
.InDataBuffer
= DataBuffer
;
380 Packet
.InTransferLength
= *DataLength
;
381 Packet
.DataDirection
= UfsDataIn
;
382 Packet
.SenseData
= SenseData
;
383 Packet
.SenseDataLength
= *SenseDataLength
;
385 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
387 if (*SenseDataLength
!= 0) {
388 *SenseDataLength
= Packet
.SenseDataLength
;
391 if (!EFI_ERROR (Status
)) {
392 *DataLength
= Packet
.InTransferLength
;
399 Execute READ (10) SCSI command on a specific UFS device.
401 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
402 @param[in] Lun The lun on which the SCSI cmd executed.
403 @param[in] StartLba The start LBA.
404 @param[in] SectorNum The sector number to be read.
405 @param[out] DataBuffer A pointer to data buffer.
406 @param[out] DataLength The length of output data.
407 @param[out] SenseData A pointer to output sense data.
408 @param[out] SenseDataLength The length of output sense data.
410 @retval EFI_SUCCESS The command executed successfully.
411 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
412 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
417 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
421 OUT VOID
*DataBuffer
,
422 OUT UINT32
*DataLength
,
423 OUT VOID
*SenseData
, OPTIONAL
424 OUT UINT8
*SenseDataLength
427 UFS_SCSI_REQUEST_PACKET Packet
;
428 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_TEN
];
431 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
432 ZeroMem (Cdb
, sizeof (Cdb
));
434 Cdb
[0] = EFI_SCSI_OP_READ10
;
435 WriteUnaligned32 ((UINT32
*)&Cdb
[2], SwapBytes32 ((UINT32
) StartLba
));
436 WriteUnaligned16 ((UINT16
*)&Cdb
[7], SwapBytes16 ((UINT16
) SectorNum
));
438 Packet
.Timeout
= UFS_TIMEOUT
;
440 Packet
.CdbLength
= sizeof (Cdb
);
441 Packet
.InDataBuffer
= DataBuffer
;
442 Packet
.InTransferLength
= *DataLength
;
443 Packet
.DataDirection
= UfsDataIn
;
444 Packet
.SenseData
= SenseData
;
445 Packet
.SenseDataLength
= *SenseDataLength
;
447 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
449 if (*SenseDataLength
!= 0) {
450 *SenseDataLength
= Packet
.SenseDataLength
;
453 if (!EFI_ERROR (Status
)) {
454 *DataLength
= Packet
.InTransferLength
;
461 Execute READ (16) SCSI command on a specific UFS device.
463 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
464 @param[in] Lun The lun on which the SCSI cmd executed.
465 @param[in] StartLba The start LBA.
466 @param[in] SectorNum The sector number to be read.
467 @param[out] DataBuffer A pointer to data buffer.
468 @param[out] DataLength The length of output data.
469 @param[out] SenseData A pointer to output sense data.
470 @param[out] SenseDataLength The length of output sense data.
472 @retval EFI_SUCCESS The command executed successfully.
473 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
474 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
479 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
483 OUT VOID
*DataBuffer
,
484 OUT UINT32
*DataLength
,
485 OUT VOID
*SenseData
, OPTIONAL
486 OUT UINT8
*SenseDataLength
489 UFS_SCSI_REQUEST_PACKET Packet
;
490 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIXTEEN
];
493 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
494 ZeroMem (Cdb
, sizeof (Cdb
));
496 Cdb
[0] = EFI_SCSI_OP_READ16
;
497 WriteUnaligned64 ((UINT64
*)&Cdb
[2], SwapBytes64 (StartLba
));
498 WriteUnaligned32 ((UINT32
*)&Cdb
[10], SwapBytes32 (SectorNum
));
500 Packet
.Timeout
= UFS_TIMEOUT
;
502 Packet
.CdbLength
= sizeof (Cdb
);
503 Packet
.InDataBuffer
= DataBuffer
;
504 Packet
.InTransferLength
= *DataLength
;
505 Packet
.DataDirection
= UfsDataIn
;
506 Packet
.SenseData
= SenseData
;
507 Packet
.SenseDataLength
= *SenseDataLength
;
509 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
511 if (*SenseDataLength
!= 0) {
512 *SenseDataLength
= Packet
.SenseDataLength
;
515 if (!EFI_ERROR (Status
)) {
516 *DataLength
= Packet
.InTransferLength
;
523 Parsing Sense Keys from sense data.
525 @param Media The pointer of EFI_PEI_BLOCK_IO_MEDIA
526 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
527 @param NeedRetry The pointer of action which indicates what is need to retry
529 @retval EFI_DEVICE_ERROR Indicates that error occurs
530 @retval EFI_SUCCESS Successfully to complete the parsing
534 UfsPeimParsingSenseKeys (
535 IN EFI_PEI_BLOCK_IO2_MEDIA
*Media
,
536 IN EFI_SCSI_SENSE_DATA
*SenseData
,
537 OUT BOOLEAN
*NeedRetry
540 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
541 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
542 Media
->MediaPresent
= FALSE
;
544 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Is No Media\n"));
545 return EFI_DEVICE_ERROR
;
548 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
549 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
551 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Is Media Change\n"));
555 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
556 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
558 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Was Reset Before\n"));
562 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_MEDIUM_ERROR
) ||
563 ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
564 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
))) {
566 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Media Error\n"));
567 return EFI_DEVICE_ERROR
;
570 if (SenseData
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
572 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Hardware Error\n"));
573 return EFI_DEVICE_ERROR
;
576 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
577 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_NOT_READY
) &&
578 (SenseData
->Addnl_Sense_Code_Qualifier
== EFI_SCSI_ASCQ_IN_PROGRESS
)) {
580 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Was Reset Before\n"));
585 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
586 return EFI_DEVICE_ERROR
;
591 Gets the count of block I/O devices that one specific block driver detects.
593 This function is used for getting the count of block I/O devices that one
594 specific block driver detects. To the PEI ATAPI driver, it returns the number
595 of all the detected ATAPI devices it detects during the enumeration process.
596 To the PEI legacy floppy driver, it returns the number of all the legacy
597 devices it finds during its enumeration process. If no device is detected,
598 then the function will return zero.
600 @param[in] PeiServices General-purpose services that are available
602 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
604 @param[out] NumberBlockDevices The number of block I/O devices discovered.
606 @retval EFI_SUCCESS The operation performed successfully.
611 UfsBlockIoPeimGetDeviceNo (
612 IN EFI_PEI_SERVICES
**PeiServices
,
613 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
614 OUT UINTN
*NumberBlockDevices
618 // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
619 // At PEI phase, we will only expose normal Luns to user.
620 // For those disabled Lun, when user try to access it, the operation would fail.
622 *NumberBlockDevices
= UFS_PEIM_MAX_LUNS
;
627 Gets a block device's media information.
629 This function will provide the caller with the specified block device's media
630 information. If the media changes, calling this function will update the media
631 information accordingly.
633 @param[in] PeiServices General-purpose services that are available to every
635 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
636 @param[in] DeviceIndex Specifies the block device to which the function wants
637 to talk. Because the driver that implements Block I/O
638 PPIs will manage multiple block devices, the PPIs that
639 want to talk to a single device must specify the
640 device index that was assigned during the enumeration
641 process. This index is a number from one to
643 @param[out] MediaInfo The media information of the specified block media.
644 The caller is responsible for the ownership of this
648 The MediaInfo structure describes an enumeration of possible block device
649 types. This enumeration exists because no device paths are actually passed
650 across interfaces that describe the type or class of hardware that is publishing
651 the block I/O interface. This enumeration will allow for policy decisions
652 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
653 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
654 by a given device type, they should be reported in ascending order; this
655 order also applies to nested partitions, such as legacy MBR, where the
656 outermost partitions would have precedence in the reporting order. The
657 same logic applies to systems such as IDE that have precedence relationships
658 like "Master/Slave" or "Primary/Secondary". The master device should be
659 reported first, the slave second.
661 @retval EFI_SUCCESS Media information about the specified block device
662 was obtained successfully.
663 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
669 UfsBlockIoPeimGetMediaInfo (
670 IN EFI_PEI_SERVICES
**PeiServices
,
671 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
672 IN UINTN DeviceIndex
,
673 OUT EFI_PEI_BLOCK_IO_MEDIA
*MediaInfo
677 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
678 EFI_SCSI_SENSE_DATA SenseData
;
679 UINT8 SenseDataLength
;
680 EFI_SCSI_DISK_CAPACITY_DATA Capacity
;
681 EFI_SCSI_DISK_CAPACITY_DATA16 Capacity16
;
685 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
688 if (DeviceIndex
>= UFS_PEIM_MAX_LUNS
) {
689 return EFI_INVALID_PARAMETER
;
692 if ((Private
->Luns
.BitMask
& (BIT0
<< DeviceIndex
)) == 0) {
693 return EFI_ACCESS_DENIED
;
696 ZeroMem (&SenseData
, sizeof (SenseData
));
697 ZeroMem (&Capacity
, sizeof (Capacity
));
698 ZeroMem (&Capacity16
, sizeof (Capacity16
));
699 SenseDataLength
= sizeof (SenseData
);
701 // First test unit ready
704 Status
= UfsPeimTestUnitReady (
710 if (!EFI_ERROR (Status
)) {
714 if (SenseDataLength
== 0) {
718 Status
= UfsPeimParsingSenseKeys (&(Private
->Media
[DeviceIndex
]), &SenseData
, &NeedRetry
);
719 if (EFI_ERROR (Status
)) {
720 return EFI_DEVICE_ERROR
;
725 DataLength
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
727 Status
= UfsPeimReadCapacity (Private
, DeviceIndex
, &Capacity
, (UINT32
*)&DataLength
, NULL
, &SenseDataLength
);
728 if (EFI_ERROR (Status
)) {
729 return EFI_DEVICE_ERROR
;
732 if ((Capacity
.LastLba3
== 0xff) && (Capacity
.LastLba2
== 0xff) &&
733 (Capacity
.LastLba1
== 0xff) && (Capacity
.LastLba0
== 0xff)) {
734 DataLength
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
736 Status
= UfsPeimReadCapacity16 (Private
, DeviceIndex
, &Capacity16
, (UINT32
*)&DataLength
, NULL
, &SenseDataLength
);
737 if (EFI_ERROR (Status
)) {
738 return EFI_DEVICE_ERROR
;
740 Private
->Media
[DeviceIndex
].LastBlock
= ((UINT32
)Capacity16
.LastLba3
<< 24) | (Capacity16
.LastLba2
<< 16) | (Capacity16
.LastLba1
<< 8) | Capacity16
.LastLba0
;
741 Private
->Media
[DeviceIndex
].LastBlock
|= LShiftU64 ((UINT64
)Capacity16
.LastLba7
, 56) | LShiftU64((UINT64
)Capacity16
.LastLba6
, 48) | LShiftU64 ((UINT64
)Capacity16
.LastLba5
, 40) | LShiftU64 ((UINT64
)Capacity16
.LastLba4
, 32);
742 Private
->Media
[DeviceIndex
].BlockSize
= (Capacity16
.BlockSize3
<< 24) | (Capacity16
.BlockSize2
<< 16) | (Capacity16
.BlockSize1
<< 8) | Capacity16
.BlockSize0
;
744 Private
->Media
[DeviceIndex
].LastBlock
= ((UINT32
)Capacity
.LastLba3
<< 24) | (Capacity
.LastLba2
<< 16) | (Capacity
.LastLba1
<< 8) | Capacity
.LastLba0
;
745 Private
->Media
[DeviceIndex
].BlockSize
= (Capacity
.BlockSize3
<< 24) | (Capacity
.BlockSize2
<< 16) | (Capacity
.BlockSize1
<< 8) | Capacity
.BlockSize0
;
748 MediaInfo
->DeviceType
= UfsDevice
;
749 MediaInfo
->MediaPresent
= Private
->Media
[DeviceIndex
].MediaPresent
;
750 MediaInfo
->LastBlock
= (UINTN
)Private
->Media
[DeviceIndex
].LastBlock
;
751 MediaInfo
->BlockSize
= Private
->Media
[DeviceIndex
].BlockSize
;
757 Reads the requested number of blocks from the specified block device.
759 The function reads the requested number of blocks from the device. All the
760 blocks are read, or an error is returned. If there is no media in the device,
761 the function returns EFI_NO_MEDIA.
763 @param[in] PeiServices General-purpose services that are available to
765 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
766 @param[in] DeviceIndex Specifies the block device to which the function wants
767 to talk. Because the driver that implements Block I/O
768 PPIs will manage multiple block devices, PPIs that
769 want to talk to a single device must specify the device
770 index that was assigned during the enumeration process.
771 This index is a number from one to NumberBlockDevices.
772 @param[in] StartLBA The starting logical block address (LBA) to read from
774 @param[in] BufferSize The size of the Buffer in bytes. This number must be
775 a multiple of the intrinsic block size of the device.
776 @param[out] Buffer A pointer to the destination buffer for the data.
777 The caller is responsible for the ownership of the
780 @retval EFI_SUCCESS The data was read correctly from the device.
781 @retval EFI_DEVICE_ERROR The device reported an error while attempting
782 to perform the read operation.
783 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
784 valid, or the buffer is not properly aligned.
785 @retval EFI_NO_MEDIA There is no media in the device.
786 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
787 the intrinsic block size of the device.
792 UfsBlockIoPeimReadBlocks (
793 IN EFI_PEI_SERVICES
**PeiServices
,
794 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
795 IN UINTN DeviceIndex
,
796 IN EFI_PEI_LBA StartLBA
,
803 UINTN NumberOfBlocks
;
804 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
805 EFI_SCSI_SENSE_DATA SenseData
;
806 UINT8 SenseDataLength
;
809 Status
= EFI_SUCCESS
;
811 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
813 ZeroMem (&SenseData
, sizeof (SenseData
));
814 SenseDataLength
= sizeof (SenseData
);
819 if (Buffer
== NULL
) {
820 return EFI_INVALID_PARAMETER
;
823 if (BufferSize
== 0) {
827 if (DeviceIndex
>= UFS_PEIM_MAX_LUNS
) {
828 return EFI_INVALID_PARAMETER
;
831 if ((Private
->Luns
.BitMask
& (BIT0
<< DeviceIndex
)) == 0) {
832 return EFI_ACCESS_DENIED
;
835 BlockSize
= Private
->Media
[DeviceIndex
].BlockSize
;
837 if (BufferSize
% BlockSize
!= 0) {
838 Status
= EFI_BAD_BUFFER_SIZE
;
841 if (StartLBA
> Private
->Media
[DeviceIndex
].LastBlock
) {
842 Status
= EFI_INVALID_PARAMETER
;
845 NumberOfBlocks
= BufferSize
/ BlockSize
;
848 Status
= UfsPeimTestUnitReady (
854 if (!EFI_ERROR (Status
)) {
858 if (SenseDataLength
== 0) {
862 Status
= UfsPeimParsingSenseKeys (&(Private
->Media
[DeviceIndex
]), &SenseData
, &NeedRetry
);
863 if (EFI_ERROR (Status
)) {
864 return EFI_DEVICE_ERROR
;
870 if (Private
->Media
[DeviceIndex
].LastBlock
< 0xfffffffful
) {
871 Status
= UfsPeimRead10 (
875 (UINT32
)NumberOfBlocks
,
877 (UINT32
*)&BufferSize
,
882 Status
= UfsPeimRead16 (
886 (UINT32
)NumberOfBlocks
,
888 (UINT32
*)&BufferSize
,
897 Gets the count of block I/O devices that one specific block driver detects.
899 This function is used for getting the count of block I/O devices that one
900 specific block driver detects. To the PEI ATAPI driver, it returns the number
901 of all the detected ATAPI devices it detects during the enumeration process.
902 To the PEI legacy floppy driver, it returns the number of all the legacy
903 devices it finds during its enumeration process. If no device is detected,
904 then the function will return zero.
906 @param[in] PeiServices General-purpose services that are available
908 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
910 @param[out] NumberBlockDevices The number of block I/O devices discovered.
912 @retval EFI_SUCCESS The operation performed successfully.
917 UfsBlockIoPeimGetDeviceNo2 (
918 IN EFI_PEI_SERVICES
**PeiServices
,
919 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
920 OUT UINTN
*NumberBlockDevices
924 // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
925 // At PEI phase, we will only expose normal Luns to user.
926 // For those disabled Lun, when user try to access it, the operation would fail.
928 *NumberBlockDevices
= UFS_PEIM_MAX_LUNS
;
933 Gets a block device's media information.
935 This function will provide the caller with the specified block device's media
936 information. If the media changes, calling this function will update the media
937 information accordingly.
939 @param[in] PeiServices General-purpose services that are available to every
941 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
942 @param[in] DeviceIndex Specifies the block device to which the function wants
943 to talk. Because the driver that implements Block I/O
944 PPIs will manage multiple block devices, the PPIs that
945 want to talk to a single device must specify the
946 device index that was assigned during the enumeration
947 process. This index is a number from one to
949 @param[out] MediaInfo The media information of the specified block media.
950 The caller is responsible for the ownership of this
954 The MediaInfo structure describes an enumeration of possible block device
955 types. This enumeration exists because no device paths are actually passed
956 across interfaces that describe the type or class of hardware that is publishing
957 the block I/O interface. This enumeration will allow for policy decisions
958 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
959 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
960 by a given device type, they should be reported in ascending order; this
961 order also applies to nested partitions, such as legacy MBR, where the
962 outermost partitions would have precedence in the reporting order. The
963 same logic applies to systems such as IDE that have precedence relationships
964 like "Master/Slave" or "Primary/Secondary". The master device should be
965 reported first, the slave second.
967 @retval EFI_SUCCESS Media information about the specified block device
968 was obtained successfully.
969 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
975 UfsBlockIoPeimGetMediaInfo2 (
976 IN EFI_PEI_SERVICES
**PeiServices
,
977 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
978 IN UINTN DeviceIndex
,
979 OUT EFI_PEI_BLOCK_IO2_MEDIA
*MediaInfo
983 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
984 EFI_PEI_BLOCK_IO_MEDIA Media
;
986 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
988 Status
= UfsBlockIoPeimGetMediaInfo (
994 if (EFI_ERROR (Status
)) {
998 CopyMem (MediaInfo
, &(Private
->Media
[DeviceIndex
]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA
));
1003 Reads the requested number of blocks from the specified block device.
1005 The function reads the requested number of blocks from the device. All the
1006 blocks are read, or an error is returned. If there is no media in the device,
1007 the function returns EFI_NO_MEDIA.
1009 @param[in] PeiServices General-purpose services that are available to
1011 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
1012 @param[in] DeviceIndex Specifies the block device to which the function wants
1013 to talk. Because the driver that implements Block I/O
1014 PPIs will manage multiple block devices, PPIs that
1015 want to talk to a single device must specify the device
1016 index that was assigned during the enumeration process.
1017 This index is a number from one to NumberBlockDevices.
1018 @param[in] StartLBA The starting logical block address (LBA) to read from
1020 @param[in] BufferSize The size of the Buffer in bytes. This number must be
1021 a multiple of the intrinsic block size of the device.
1022 @param[out] Buffer A pointer to the destination buffer for the data.
1023 The caller is responsible for the ownership of the
1026 @retval EFI_SUCCESS The data was read correctly from the device.
1027 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1028 to perform the read operation.
1029 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
1030 valid, or the buffer is not properly aligned.
1031 @retval EFI_NO_MEDIA There is no media in the device.
1032 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
1033 the intrinsic block size of the device.
1038 UfsBlockIoPeimReadBlocks2 (
1039 IN EFI_PEI_SERVICES
**PeiServices
,
1040 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI
*This
,
1041 IN UINTN DeviceIndex
,
1042 IN EFI_PEI_LBA StartLBA
,
1043 IN UINTN BufferSize
,
1048 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
1050 Status
= EFI_SUCCESS
;
1051 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This
);
1053 Status
= UfsBlockIoPeimReadBlocks (
1065 The user code starts with this function.
1067 @param FileHandle Handle of the file being invoked.
1068 @param PeiServices Describes the list of possible PEI Services.
1070 @retval EFI_SUCCESS The driver is successfully initialized.
1071 @retval Others Can't initialize the driver.
1076 InitializeUfsBlockIoPeim (
1077 IN EFI_PEI_FILE_HANDLE FileHandle
,
1078 IN CONST EFI_PEI_SERVICES
**PeiServices
1082 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
1083 EDKII_UFS_HOST_CONTROLLER_PPI
*UfsHcPpi
;
1085 UFS_CONFIG_DESC Config
;
1090 // Shadow this PEIM to run from memory
1092 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
1097 // locate ufs host controller PPI
1099 Status
= PeiServicesLocatePpi (
1100 &gEdkiiPeiUfsHostControllerPpiGuid
,
1105 if (EFI_ERROR (Status
)) {
1106 return EFI_DEVICE_ERROR
;
1112 Status
= UfsHcPpi
->GetUfsHcMmioBar (UfsHcPpi
, Controller
, &MmioBase
);
1114 // When status is error, meant no controller is found
1116 if (EFI_ERROR (Status
)) {
1120 Private
= AllocateCopyPool (sizeof (UFS_PEIM_HC_PRIVATE_DATA
), &gUfsHcPeimTemplate
);
1121 if (Private
== NULL
) {
1122 Status
= EFI_OUT_OF_RESOURCES
;
1126 Private
->BlkIoPpiList
.Ppi
= &Private
->BlkIoPpi
;
1127 Private
->BlkIo2PpiList
.Ppi
= &Private
->BlkIo2Ppi
;
1128 Private
->UfsHcBase
= MmioBase
;
1131 // Initialize the memory pool which will be used in all transactions.
1133 Status
= UfsPeimInitMemPool (Private
);
1134 if (EFI_ERROR (Status
)) {
1135 Status
= EFI_OUT_OF_RESOURCES
;
1140 // Initialize UFS Host Controller H/W.
1142 Status
= UfsControllerInit (Private
);
1143 if (EFI_ERROR (Status
)) {
1144 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Host Controller Initialization Error, Status = %r\n", Status
));
1150 // UFS 2.0 spec Section 13.1.3.3:
1151 // At the end of the UFS Interconnect Layer initialization on both host and device side,
1152 // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready.
1154 Status
= UfsExecNopCmds (Private
);
1155 if (EFI_ERROR (Status
)) {
1156 DEBUG ((EFI_D_ERROR
, "Ufs Sending NOP IN command Error, Status = %r\n", Status
));
1162 // The host enables the device initialization completion by setting fDeviceInit flag.
1164 Status
= UfsSetFlag (Private
, UfsFlagDevInit
);
1165 if (EFI_ERROR (Status
)) {
1166 DEBUG ((EFI_D_ERROR
, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status
));
1172 // Get Ufs Device's Lun Info by reading Configuration Descriptor.
1174 Status
= UfsRwDeviceDesc (Private
, TRUE
, UfsConfigDesc
, 0, 0, &Config
, sizeof (UFS_CONFIG_DESC
));
1175 if (EFI_ERROR (Status
)) {
1176 DEBUG ((EFI_D_ERROR
, "Ufs Get Configuration Descriptor Error, Status = %r\n", Status
));
1181 for (Index
= 0; Index
< UFS_PEIM_MAX_LUNS
; Index
++) {
1182 if (Config
.UnitDescConfParams
[Index
].LunEn
!= 0) {
1183 Private
->Luns
.BitMask
|= (BIT0
<< Index
);
1184 DEBUG ((EFI_D_INFO
, "Ufs %d Lun %d is enabled\n", Controller
, Index
));
1188 Status
= PeiServicesInstallPpi (&Private
->BlkIoPpiList
);