3 Copyright (c) 2014, 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_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
30 &gEfiPeiVirtualBlockIoPpiGuid
,
92 UFS_LUN_0
, // Ufs Common Lun 0
93 UFS_LUN_1
, // Ufs Common Lun 1
94 UFS_LUN_2
, // Ufs Common Lun 2
95 UFS_LUN_3
, // Ufs Common Lun 3
96 UFS_LUN_4
, // Ufs Common Lun 4
97 UFS_LUN_5
, // Ufs Common Lun 5
98 UFS_LUN_6
, // Ufs Common Lun 6
99 UFS_LUN_7
, // Ufs Common Lun 7
101 0x0000, // By default exposing all Luns.
107 Execute Request Sense SCSI command on a specific UFS device.
109 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
110 @param[in] Lun The lun on which the SCSI cmd executed.
111 @param[out] DataBuffer A pointer to output sense data.
112 @param[out] DataBufferLength The length of output sense data.
114 @retval EFI_SUCCESS The command executed successfully.
115 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
116 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
120 UfsPeimRequestSense (
121 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
123 OUT VOID
*DataBuffer
,
124 OUT UINT32
*DataBufferLength
127 UFS_SCSI_REQUEST_PACKET Packet
;
128 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIX
];
131 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
132 ZeroMem (Cdb
, sizeof (Cdb
));
134 Cdb
[0] = EFI_SCSI_OP_REQUEST_SENSE
;
136 Packet
.Timeout
= UFS_TIMEOUT
;
138 Packet
.CdbLength
= sizeof (Cdb
);
139 Packet
.DataDirection
= UfsDataIn
;
140 Packet
.InDataBuffer
= DataBuffer
;
141 Packet
.InTransferLength
= *DataBufferLength
;
142 Packet
.SenseData
= NULL
;
143 Packet
.SenseDataLength
= 0;
145 Status
= UfsExecScsiCmds (Private
,(UINT8
)Lun
, &Packet
);
147 if (!EFI_ERROR (Status
)) {
148 *DataBufferLength
= Packet
.InTransferLength
;
155 Execute TEST UNITY READY SCSI command on a specific UFS device.
157 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
158 @param[in] Lun The lun on which the SCSI cmd executed.
159 @param[out] SenseData A pointer to output sense data.
160 @param[out] SenseDataLength The length of output sense data.
162 @retval EFI_SUCCESS The command executed successfully.
163 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
164 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
168 UfsPeimTestUnitReady (
169 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
171 OUT VOID
*SenseData
, OPTIONAL
172 OUT UINT8
*SenseDataLength
175 UFS_SCSI_REQUEST_PACKET Packet
;
176 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIX
];
179 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
180 ZeroMem (Cdb
, sizeof (Cdb
));
182 Cdb
[0] = EFI_SCSI_OP_TEST_UNIT_READY
;
184 Packet
.Timeout
= UFS_TIMEOUT
;
186 Packet
.CdbLength
= sizeof (Cdb
);
187 Packet
.DataDirection
= UfsNoData
;
188 Packet
.SenseData
= SenseData
;
189 Packet
.SenseDataLength
= *SenseDataLength
;
191 Status
= UfsExecScsiCmds (Private
,(UINT8
)Lun
, &Packet
);
193 if (*SenseDataLength
!= 0) {
194 *SenseDataLength
= Packet
.SenseDataLength
;
201 Execute INQUIRY SCSI command on a specific UFS device.
203 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
204 @param[in] Lun The lun on which the SCSI cmd executed.
205 @param[out] Inquiry A pointer to Inquiry data buffer.
206 @param[out] InquiryLengths The length of output Inquiry data.
207 @param[out] SenseData A pointer to output sense data.
208 @param[out] SenseDataLength The length of output sense data.
210 @retval EFI_SUCCESS The command executed successfully.
211 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
212 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
217 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
220 OUT UINT32
*InquiryLength
,
221 OUT VOID
*SenseData
, OPTIONAL
222 OUT UINT8
*SenseDataLength
225 UFS_SCSI_REQUEST_PACKET Packet
;
226 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIX
];
229 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
230 ZeroMem (Cdb
, sizeof (Cdb
));
232 Cdb
[0] = EFI_SCSI_OP_INQUIRY
;
233 Cdb
[4] = sizeof (EFI_SCSI_INQUIRY_DATA
);
235 Packet
.Timeout
= UFS_TIMEOUT
;
237 Packet
.CdbLength
= sizeof (Cdb
);
238 Packet
.InDataBuffer
= Inquiry
;
239 Packet
.InTransferLength
= *InquiryLength
;
240 Packet
.DataDirection
= UfsDataIn
;
241 Packet
.SenseData
= SenseData
;
242 Packet
.SenseDataLength
= *SenseDataLength
;
244 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
246 if (*SenseDataLength
!= 0) {
247 *SenseDataLength
= Packet
.SenseDataLength
;
250 if (!EFI_ERROR (Status
)) {
251 *InquiryLength
= Packet
.InTransferLength
;
258 Execute READ CAPACITY(10) SCSI command on a specific UFS device.
260 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
261 @param[in] Lun The lun on which the SCSI cmd executed.
262 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
263 @param[out] DataLength The length of output READ_CAPACITY data.
264 @param[out] SenseData A pointer to output sense data.
265 @param[out] SenseDataLength The length of output sense data.
267 @retval EFI_SUCCESS The command executed successfully.
268 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
269 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
273 UfsPeimReadCapacity (
274 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
276 OUT VOID
*DataBuffer
,
277 OUT UINT32
*DataLength
,
278 OUT VOID
*SenseData
, OPTIONAL
279 OUT UINT8
*SenseDataLength
282 UFS_SCSI_REQUEST_PACKET Packet
;
283 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_TEN
];
286 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
287 ZeroMem (Cdb
, sizeof (Cdb
));
289 Cdb
[0] = EFI_SCSI_OP_READ_CAPACITY
;
291 Packet
.Timeout
= UFS_TIMEOUT
;
293 Packet
.CdbLength
= sizeof (Cdb
);
294 Packet
.InDataBuffer
= DataBuffer
;
295 Packet
.InTransferLength
= *DataLength
;
296 Packet
.DataDirection
= UfsDataIn
;
297 Packet
.SenseData
= SenseData
;
298 Packet
.SenseDataLength
= *SenseDataLength
;
300 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
302 if (*SenseDataLength
!= 0) {
303 *SenseDataLength
= Packet
.SenseDataLength
;
306 if (!EFI_ERROR (Status
)) {
307 *DataLength
= Packet
.InTransferLength
;
314 Execute READ CAPACITY(16) SCSI command on a specific UFS device.
316 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
317 @param[in] Lun The lun on which the SCSI cmd executed.
318 @param[out] DataBuffer A pointer to READ_CAPACITY data buffer.
319 @param[out] DataLength The length of output READ_CAPACITY data.
320 @param[out] SenseData A pointer to output sense data.
321 @param[out] SenseDataLength The length of output sense data.
323 @retval EFI_SUCCESS The command executed successfully.
324 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
325 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
329 UfsPeimReadCapacity16 (
330 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
332 OUT VOID
*DataBuffer
,
333 OUT UINT32
*DataLength
,
334 OUT VOID
*SenseData
, OPTIONAL
335 OUT UINT8
*SenseDataLength
338 UFS_SCSI_REQUEST_PACKET Packet
;
339 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIXTEEN
];
342 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
343 ZeroMem (Cdb
, sizeof (Cdb
));
345 Cdb
[0] = EFI_SCSI_OP_READ_CAPACITY16
;
346 Cdb
[1] = 0x10; // Service Action should be 0x10 for UFS device.
347 Cdb
[13] = 0x20; // The maximum number of bytes for returned data.
349 Packet
.Timeout
= UFS_TIMEOUT
;
351 Packet
.CdbLength
= sizeof (Cdb
);
352 Packet
.InDataBuffer
= DataBuffer
;
353 Packet
.InTransferLength
= *DataLength
;
354 Packet
.DataDirection
= UfsDataIn
;
355 Packet
.SenseData
= SenseData
;
356 Packet
.SenseDataLength
= *SenseDataLength
;
358 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
360 if (*SenseDataLength
!= 0) {
361 *SenseDataLength
= Packet
.SenseDataLength
;
364 if (!EFI_ERROR (Status
)) {
365 *DataLength
= Packet
.InTransferLength
;
372 Execute READ (10) SCSI command on a specific UFS device.
374 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
375 @param[in] Lun The lun on which the SCSI cmd executed.
376 @param[in] StartLba The start LBA.
377 @param[in] SectorNum The sector number to be read.
378 @param[out] DataBuffer A pointer to data buffer.
379 @param[out] DataLength The length of output data.
380 @param[out] SenseData A pointer to output sense data.
381 @param[out] SenseDataLength The length of output sense data.
383 @retval EFI_SUCCESS The command executed successfully.
384 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
385 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
390 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
394 OUT VOID
*DataBuffer
,
395 OUT UINT32
*DataLength
,
396 OUT VOID
*SenseData
, OPTIONAL
397 OUT UINT8
*SenseDataLength
400 UFS_SCSI_REQUEST_PACKET Packet
;
401 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_TEN
];
404 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
405 ZeroMem (Cdb
, sizeof (Cdb
));
407 Cdb
[0] = EFI_SCSI_OP_READ10
;
408 WriteUnaligned32 ((UINT32
*)&Cdb
[2], SwapBytes32 ((UINT32
) StartLba
));
409 WriteUnaligned16 ((UINT16
*)&Cdb
[7], SwapBytes16 ((UINT16
) SectorNum
));
411 Packet
.Timeout
= UFS_TIMEOUT
;
413 Packet
.CdbLength
= sizeof (Cdb
);
414 Packet
.InDataBuffer
= DataBuffer
;
415 Packet
.InTransferLength
= *DataLength
;
416 Packet
.DataDirection
= UfsDataIn
;
417 Packet
.SenseData
= SenseData
;
418 Packet
.SenseDataLength
= *SenseDataLength
;
420 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
422 if (*SenseDataLength
!= 0) {
423 *SenseDataLength
= Packet
.SenseDataLength
;
426 if (!EFI_ERROR (Status
)) {
427 *DataLength
= Packet
.InTransferLength
;
434 Execute READ (16) SCSI command on a specific UFS device.
436 @param[in] Private A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
437 @param[in] Lun The lun on which the SCSI cmd executed.
438 @param[in] StartLba The start LBA.
439 @param[in] SectorNum The sector number to be read.
440 @param[out] DataBuffer A pointer to data buffer.
441 @param[out] DataLength The length of output data.
442 @param[out] SenseData A pointer to output sense data.
443 @param[out] SenseDataLength The length of output sense data.
445 @retval EFI_SUCCESS The command executed successfully.
446 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send SCSI Request Packet.
447 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.
452 IN UFS_PEIM_HC_PRIVATE_DATA
*Private
,
456 OUT VOID
*DataBuffer
,
457 OUT UINT32
*DataLength
,
458 OUT VOID
*SenseData
, OPTIONAL
459 OUT UINT8
*SenseDataLength
462 UFS_SCSI_REQUEST_PACKET Packet
;
463 UINT8 Cdb
[UFS_SCSI_OP_LENGTH_SIXTEEN
];
466 ZeroMem (&Packet
, sizeof (UFS_SCSI_REQUEST_PACKET
));
467 ZeroMem (Cdb
, sizeof (Cdb
));
469 Cdb
[0] = EFI_SCSI_OP_READ16
;
470 WriteUnaligned64 ((UINT64
*)&Cdb
[2], SwapBytes64 (StartLba
));
471 WriteUnaligned32 ((UINT32
*)&Cdb
[10], SwapBytes32 (SectorNum
));
473 Packet
.Timeout
= UFS_TIMEOUT
;
475 Packet
.CdbLength
= sizeof (Cdb
);
476 Packet
.InDataBuffer
= DataBuffer
;
477 Packet
.InTransferLength
= *DataLength
;
478 Packet
.DataDirection
= UfsDataIn
;
479 Packet
.SenseData
= SenseData
;
480 Packet
.SenseDataLength
= *SenseDataLength
;
482 Status
= UfsExecScsiCmds (Private
, (UINT8
)Lun
, &Packet
);
484 if (*SenseDataLength
!= 0) {
485 *SenseDataLength
= Packet
.SenseDataLength
;
488 if (!EFI_ERROR (Status
)) {
489 *DataLength
= Packet
.InTransferLength
;
496 Parsing Sense Keys from sense data.
498 @param Media The pointer of EFI_PEI_BLOCK_IO_MEDIA
499 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
500 @param NeedRetry The pointer of action which indicates what is need to retry
502 @retval EFI_DEVICE_ERROR Indicates that error occurs
503 @retval EFI_SUCCESS Successfully to complete the parsing
507 UfsPeimParsingSenseKeys (
508 IN EFI_PEI_BLOCK_IO_MEDIA
*Media
,
509 IN EFI_SCSI_SENSE_DATA
*SenseData
,
510 OUT BOOLEAN
*NeedRetry
513 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
514 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
515 Media
->MediaPresent
= FALSE
;
517 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Is No Media\n"));
518 return EFI_DEVICE_ERROR
;
521 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
522 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
524 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Is Media Change\n"));
528 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
529 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
531 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Was Reset Before\n"));
535 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_MEDIUM_ERROR
) ||
536 ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
537 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
))) {
539 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Media Error\n"));
540 return EFI_DEVICE_ERROR
;
543 if (SenseData
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
545 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Hardware Error\n"));
546 return EFI_DEVICE_ERROR
;
549 if ((SenseData
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
550 (SenseData
->Addnl_Sense_Code
== EFI_SCSI_ASC_NOT_READY
) &&
551 (SenseData
->Addnl_Sense_Code_Qualifier
== EFI_SCSI_ASCQ_IN_PROGRESS
)) {
553 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Was Reset Before\n"));
558 DEBUG ((EFI_D_VERBOSE
, "UfsBlockIoPei: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
559 return EFI_DEVICE_ERROR
;
564 Gets the count of block I/O devices that one specific block driver detects.
566 This function is used for getting the count of block I/O devices that one
567 specific block driver detects. To the PEI ATAPI driver, it returns the number
568 of all the detected ATAPI devices it detects during the enumeration process.
569 To the PEI legacy floppy driver, it returns the number of all the legacy
570 devices it finds during its enumeration process. If no device is detected,
571 then the function will return zero.
573 @param[in] PeiServices General-purpose services that are available
575 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
577 @param[out] NumberBlockDevices The number of block I/O devices discovered.
579 @retval EFI_SUCCESS The operation performed successfully.
584 UfsBlockIoPeimGetDeviceNo (
585 IN EFI_PEI_SERVICES
**PeiServices
,
586 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
587 OUT UINTN
*NumberBlockDevices
591 // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
592 // At PEI phase, we will only expose normal Luns to user.
593 // For those disabled Lun, when user try to access it, the operation would fail.
595 *NumberBlockDevices
= UFS_PEIM_MAX_LUNS
;
600 Gets a block device's media information.
602 This function will provide the caller with the specified block device's media
603 information. If the media changes, calling this function will update the media
604 information accordingly.
606 @param[in] PeiServices General-purpose services that are available to every
608 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
609 @param[in] DeviceIndex Specifies the block device to which the function wants
610 to talk. Because the driver that implements Block I/O
611 PPIs will manage multiple block devices, the PPIs that
612 want to talk to a single device must specify the
613 device index that was assigned during the enumeration
614 process. This index is a number from one to
616 @param[out] MediaInfo The media information of the specified block media.
617 The caller is responsible for the ownership of this
621 The MediaInfo structure describes an enumeration of possible block device
622 types. This enumeration exists because no device paths are actually passed
623 across interfaces that describe the type or class of hardware that is publishing
624 the block I/O interface. This enumeration will allow for policy decisions
625 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
626 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
627 by a given device type, they should be reported in ascending order; this
628 order also applies to nested partitions, such as legacy MBR, where the
629 outermost partitions would have precedence in the reporting order. The
630 same logic applies to systems such as IDE that have precedence relationships
631 like "Master/Slave" or "Primary/Secondary". The master device should be
632 reported first, the slave second.
634 @retval EFI_SUCCESS Media information about the specified block device
635 was obtained successfully.
636 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
642 UfsBlockIoPeimGetMediaInfo (
643 IN EFI_PEI_SERVICES
**PeiServices
,
644 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
645 IN UINTN DeviceIndex
,
646 OUT EFI_PEI_BLOCK_IO_MEDIA
*MediaInfo
650 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
651 EFI_SCSI_SENSE_DATA SenseData
;
652 UINT8 SenseDataLength
;
653 EFI_SCSI_DISK_CAPACITY_DATA Capacity
;
654 EFI_SCSI_DISK_CAPACITY_DATA16 Capacity16
;
658 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
661 if (DeviceIndex
>= UFS_PEIM_MAX_LUNS
) {
662 return EFI_INVALID_PARAMETER
;
665 if ((Private
->Luns
.BitMask
& (BIT0
<< DeviceIndex
)) == 0) {
666 return EFI_ACCESS_DENIED
;
669 ZeroMem (&SenseData
, sizeof (SenseData
));
670 ZeroMem (&Capacity
, sizeof (Capacity
));
671 ZeroMem (&Capacity16
, sizeof (Capacity16
));
672 SenseDataLength
= sizeof (SenseData
);
674 // First test unit ready
677 Status
= UfsPeimTestUnitReady (
683 if (!EFI_ERROR (Status
)) {
687 if (SenseDataLength
== 0) {
691 Status
= UfsPeimParsingSenseKeys (&(Private
->Media
[DeviceIndex
]), &SenseData
, &NeedRetry
);
692 if (EFI_ERROR (Status
)) {
693 return EFI_DEVICE_ERROR
;
698 DataLength
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
700 Status
= UfsPeimReadCapacity (Private
, DeviceIndex
, &Capacity
, (UINT32
*)&DataLength
, NULL
, &SenseDataLength
);
701 if (EFI_ERROR (Status
)) {
702 return EFI_DEVICE_ERROR
;
705 if ((Capacity
.LastLba3
== 0xff) && (Capacity
.LastLba2
== 0xff) &&
706 (Capacity
.LastLba1
== 0xff) && (Capacity
.LastLba0
== 0xff)) {
707 DataLength
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
709 Status
= UfsPeimReadCapacity16 (Private
, DeviceIndex
, &Capacity16
, (UINT32
*)&DataLength
, NULL
, &SenseDataLength
);
710 if (EFI_ERROR (Status
)) {
711 return EFI_DEVICE_ERROR
;
713 MediaInfo
->LastBlock
= (Capacity16
.LastLba3
<< 24) | (Capacity16
.LastLba2
<< 16) | (Capacity16
.LastLba1
<< 8) | Capacity16
.LastLba0
;
714 MediaInfo
->LastBlock
|= ((UINT64
)Capacity16
.LastLba7
<< 56) | ((UINT64
)Capacity16
.LastLba6
<< 48) | ((UINT64
)Capacity16
.LastLba5
<< 40) | ((UINT64
)Capacity16
.LastLba4
<< 32);
715 MediaInfo
->BlockSize
= (Capacity16
.BlockSize3
<< 24) | (Capacity16
.BlockSize2
<< 16) | (Capacity16
.BlockSize1
<< 8) | Capacity16
.BlockSize0
;
717 MediaInfo
->LastBlock
= (Capacity
.LastLba3
<< 24) | (Capacity
.LastLba2
<< 16) | (Capacity
.LastLba1
<< 8) | Capacity
.LastLba0
;
718 MediaInfo
->BlockSize
= (Capacity
.BlockSize3
<< 24) | (Capacity
.BlockSize2
<< 16) | (Capacity
.BlockSize1
<< 8) | Capacity
.BlockSize0
;
721 MediaInfo
->DeviceType
= UfsDevice
;
722 MediaInfo
->MediaPresent
= TRUE
;
728 Reads the requested number of blocks from the specified block device.
730 The function reads the requested number of blocks from the device. All the
731 blocks are read, or an error is returned. If there is no media in the device,
732 the function returns EFI_NO_MEDIA.
734 @param[in] PeiServices General-purpose services that are available to
736 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
737 @param[in] DeviceIndex Specifies the block device to which the function wants
738 to talk. Because the driver that implements Block I/O
739 PPIs will manage multiple block devices, PPIs that
740 want to talk to a single device must specify the device
741 index that was assigned during the enumeration process.
742 This index is a number from one to NumberBlockDevices.
743 @param[in] StartLBA The starting logical block address (LBA) to read from
745 @param[in] BufferSize The size of the Buffer in bytes. This number must be
746 a multiple of the intrinsic block size of the device.
747 @param[out] Buffer A pointer to the destination buffer for the data.
748 The caller is responsible for the ownership of the
751 @retval EFI_SUCCESS The data was read correctly from the device.
752 @retval EFI_DEVICE_ERROR The device reported an error while attempting
753 to perform the read operation.
754 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
755 valid, or the buffer is not properly aligned.
756 @retval EFI_NO_MEDIA There is no media in the device.
757 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
758 the intrinsic block size of the device.
763 UfsBlockIoPeimReadBlocks (
764 IN EFI_PEI_SERVICES
**PeiServices
,
765 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI
*This
,
766 IN UINTN DeviceIndex
,
767 IN EFI_PEI_LBA StartLBA
,
774 UINTN NumberOfBlocks
;
775 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
776 EFI_SCSI_SENSE_DATA SenseData
;
777 UINT8 SenseDataLength
;
780 Status
= EFI_SUCCESS
;
782 Private
= GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This
);
784 ZeroMem (&SenseData
, sizeof (SenseData
));
785 SenseDataLength
= sizeof (SenseData
);
790 if (Buffer
== NULL
) {
791 return EFI_INVALID_PARAMETER
;
794 if (BufferSize
== 0) {
798 if (DeviceIndex
>= UFS_PEIM_MAX_LUNS
) {
799 return EFI_INVALID_PARAMETER
;
802 if ((Private
->Luns
.BitMask
& (BIT0
<< DeviceIndex
)) == 0) {
803 return EFI_ACCESS_DENIED
;
806 BlockSize
= Private
->Media
[DeviceIndex
].BlockSize
;
808 if (BufferSize
% BlockSize
!= 0) {
809 Status
= EFI_BAD_BUFFER_SIZE
;
812 if (StartLBA
> Private
->Media
[DeviceIndex
].LastBlock
) {
813 Status
= EFI_INVALID_PARAMETER
;
816 NumberOfBlocks
= BufferSize
/ BlockSize
;
819 Status
= UfsPeimTestUnitReady (
825 if (!EFI_ERROR (Status
)) {
829 if (SenseDataLength
== 0) {
833 Status
= UfsPeimParsingSenseKeys (&(Private
->Media
[DeviceIndex
]), &SenseData
, &NeedRetry
);
834 if (EFI_ERROR (Status
)) {
835 return EFI_DEVICE_ERROR
;
841 if (Private
->Media
[DeviceIndex
].LastBlock
!= ~((UINTN
)0)) {
842 Status
= UfsPeimRead10 (
846 (UINT32
)NumberOfBlocks
,
848 (UINT32
*)&BufferSize
,
853 Status
= UfsPeimRead16 (
857 (UINT32
)NumberOfBlocks
,
859 (UINT32
*)&BufferSize
,
868 The user code starts with this function.
870 @param FileHandle Handle of the file being invoked.
871 @param PeiServices Describes the list of possible PEI Services.
873 @retval EFI_SUCCESS The driver is successfully initialized.
874 @retval Others Can't initialize the driver.
879 InitializeUfsBlockIoPeim (
880 IN EFI_PEI_FILE_HANDLE FileHandle
,
881 IN CONST EFI_PEI_SERVICES
**PeiServices
885 UFS_PEIM_HC_PRIVATE_DATA
*Private
;
886 EDKII_UFS_HOST_CONTROLLER_PPI
*UfsHcPpi
;
888 UFS_CONFIG_DESC Config
;
893 // Shadow this PEIM to run from memory
895 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle
))) {
900 // locate ufs host controller PPI
902 Status
= PeiServicesLocatePpi (
903 &gEdkiiPeiUfsHostControllerPpiGuid
,
908 if (EFI_ERROR (Status
)) {
909 return EFI_DEVICE_ERROR
;
915 Status
= UfsHcPpi
->GetUfsHcMmioBar (UfsHcPpi
, Controller
, &MmioBase
);
917 // When status is error, meant no controller is found
919 if (EFI_ERROR (Status
)) {
923 Private
= AllocateCopyPool (sizeof (UFS_PEIM_HC_PRIVATE_DATA
), &gUfsHcPeimTemplate
);
924 if (Private
== NULL
) {
925 Status
= EFI_OUT_OF_RESOURCES
;
929 Private
->BlkIoPpiList
.Ppi
= &Private
->BlkIoPpi
;
930 Private
->UfsHcBase
= MmioBase
;
933 // Initialize the memory pool which will be used in all transactions.
935 Status
= UfsPeimInitMemPool (Private
);
936 if (EFI_ERROR (Status
)) {
937 Status
= EFI_OUT_OF_RESOURCES
;
942 // Initialize UFS Host Controller H/W.
944 Status
= UfsControllerInit (Private
);
945 if (EFI_ERROR (Status
)) {
946 DEBUG ((EFI_D_ERROR
, "UfsDevicePei: Host Controller Initialization Error, Status = %r\n", Status
));
952 // UFS 2.0 spec Section 13.1.3.3:
953 // At the end of the UFS Interconnect Layer initialization on both host and device side,
954 // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready.
956 Status
= UfsExecNopCmds (Private
);
957 if (EFI_ERROR (Status
)) {
958 DEBUG ((EFI_D_ERROR
, "Ufs Sending NOP IN command Error, Status = %r\n", Status
));
964 // The host enables the device initialization completion by setting fDeviceInit flag.
966 Status
= UfsSetFlag (Private
, UfsFlagDevInit
);
967 if (EFI_ERROR (Status
)) {
968 DEBUG ((EFI_D_ERROR
, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status
));
974 // Get Ufs Device's Lun Info by reading Configuration Descriptor.
976 Status
= UfsRwDeviceDesc (Private
, TRUE
, UfsConfigDesc
, 0, 0, &Config
, sizeof (UFS_CONFIG_DESC
));
977 if (EFI_ERROR (Status
)) {
978 DEBUG ((EFI_D_ERROR
, "Ufs Get Configuration Descriptor Error, Status = %r\n", Status
));
983 for (Index
= 0; Index
< UFS_PEIM_MAX_LUNS
; Index
++) {
984 if (Config
.UnitDescConfParams
[Index
].LunEn
!= 0) {
985 Private
->Luns
.BitMask
|= (BIT0
<< Index
);
986 DEBUG ((EFI_D_INFO
, "Ufs %d Lun %d is enabled\n", Controller
, Index
));
990 Status
= PeiServicesInstallPpi (&Private
->BlkIoPpiList
);