1 /** @file
2 
3   Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
4   SPDX-License-Identifier: BSD-2-Clause-Patent
5 
6 **/
7 
8 #include "UfsBlockIoPei.h"
9 
10 //
11 // Template for UFS HC Peim Private Data.
12 //
13 UFS_PEIM_HC_PRIVATE_DATA   gUfsHcPeimTemplate = {
14   UFS_PEIM_HC_SIG,                // Signature
15   NULL,                           // Controller
16   NULL,                           // Pool
17   {                               // BlkIoPpi
18     UfsBlockIoPeimGetDeviceNo,
19     UfsBlockIoPeimGetMediaInfo,
20     UfsBlockIoPeimReadBlocks
21   },
22   {                               // BlkIo2Ppi
23     EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
24     UfsBlockIoPeimGetDeviceNo2,
25     UfsBlockIoPeimGetMediaInfo2,
26     UfsBlockIoPeimReadBlocks2
27   },
28   {                               // BlkIoPpiList
29     EFI_PEI_PPI_DESCRIPTOR_PPI,
30     &gEfiPeiVirtualBlockIoPpiGuid,
31     NULL
32   },
33   {                               // BlkIo2PpiList
34     EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
35     &gEfiPeiVirtualBlockIo2PpiGuid,
36     NULL
37   },
38   {                               // Media
39     {
40       MSG_UFS_DP,
41       FALSE,
42       TRUE,
43       FALSE,
44       0x1000,
45       0
46     },
47     {
48       MSG_UFS_DP,
49       FALSE,
50       TRUE,
51       FALSE,
52       0x1000,
53       0
54     },
55     {
56       MSG_UFS_DP,
57       FALSE,
58       TRUE,
59       FALSE,
60       0x1000,
61       0
62     },
63     {
64       MSG_UFS_DP,
65       FALSE,
66       TRUE,
67       FALSE,
68       0x1000,
69       0
70     },
71     {
72       MSG_UFS_DP,
73       FALSE,
74       TRUE,
75       FALSE,
76       0x1000,
77       0
78     },
79     {
80       MSG_UFS_DP,
81       FALSE,
82       TRUE,
83       FALSE,
84       0x1000,
85       0
86     },
87     {
88       MSG_UFS_DP,
89       FALSE,
90       TRUE,
91       FALSE,
92       0x1000,
93       0
94     },
95     {
96       MSG_UFS_DP,
97       FALSE,
98       TRUE,
99       FALSE,
100       0x1000,
101       0
102     }
103   },
104   {                               // EndOfPeiNotifyList
105     (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
106     &gEfiEndOfPeiSignalPpiGuid,
107     UfsEndOfPei
108   },
109   0,                              // UfsHcBase
110   0,                              // Capabilities
111   0,                              // TaskTag
112   0,                              // UtpTrlBase
113   0,                              // Nutrs
114   NULL,                           // TrlMapping
115   0,                              // UtpTmrlBase
116   0,                              // Nutmrs
117   NULL,                           // TmrlMapping
118   {                               // Luns
119     {
120       UFS_LUN_0,                      // Ufs Common Lun 0
121       UFS_LUN_1,                      // Ufs Common Lun 1
122       UFS_LUN_2,                      // Ufs Common Lun 2
123       UFS_LUN_3,                      // Ufs Common Lun 3
124       UFS_LUN_4,                      // Ufs Common Lun 4
125       UFS_LUN_5,                      // Ufs Common Lun 5
126       UFS_LUN_6,                      // Ufs Common Lun 6
127       UFS_LUN_7,                      // Ufs Common Lun 7
128     },
129     0x0000,                           // By default exposing all Luns.
130     0x0
131   }
132 };
133 
134 
135 
136 /**
137   Execute TEST UNITY READY SCSI command on a specific UFS device.
138 
139   @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
140   @param[in]  Lun                  The lun on which the SCSI cmd executed.
141   @param[out] SenseData            A pointer to output sense data.
142   @param[out] SenseDataLength      The length of output sense data.
143 
144   @retval EFI_SUCCESS              The command executed successfully.
145   @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.
146   @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.
147 
148 **/
149 EFI_STATUS
UfsPeimTestUnitReady(IN UFS_PEIM_HC_PRIVATE_DATA * Private,IN UINTN Lun,OUT VOID * SenseData,OPTIONAL OUT UINT8 * SenseDataLength)150 UfsPeimTestUnitReady (
151   IN     UFS_PEIM_HC_PRIVATE_DATA        *Private,
152   IN     UINTN                           Lun,
153      OUT VOID                            *SenseData,  OPTIONAL
154      OUT UINT8                           *SenseDataLength
155   )
156 {
157   UFS_SCSI_REQUEST_PACKET                Packet;
158   UINT8                                  Cdb[UFS_SCSI_OP_LENGTH_SIX];
159   EFI_STATUS                             Status;
160 
161   ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
162   ZeroMem (Cdb, sizeof (Cdb));
163 
164   Cdb[0]  = EFI_SCSI_OP_TEST_UNIT_READY;
165 
166   Packet.Timeout         = UFS_TIMEOUT;
167   Packet.Cdb             = Cdb;
168   Packet.CdbLength       = sizeof (Cdb);
169   Packet.DataDirection   = UfsNoData;
170   Packet.SenseData       = SenseData;
171   Packet.SenseDataLength = *SenseDataLength;
172 
173   Status = UfsExecScsiCmds (Private,(UINT8)Lun, &Packet);
174 
175   if (*SenseDataLength != 0) {
176     *SenseDataLength = Packet.SenseDataLength;
177   }
178 
179   return Status;
180 }
181 
182 
183 
184 /**
185   Execute READ CAPACITY(10) SCSI command on a specific UFS device.
186 
187   @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
188   @param[in]  Lun                  The lun on which the SCSI cmd executed.
189   @param[out] DataBuffer           A pointer to READ_CAPACITY data buffer.
190   @param[out] DataLength           The length of output READ_CAPACITY data.
191   @param[out] SenseData            A pointer to output sense data.
192   @param[out] SenseDataLength      The length of output sense data.
193 
194   @retval EFI_SUCCESS              The command executed successfully.
195   @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.
196   @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.
197 
198 **/
199 EFI_STATUS
UfsPeimReadCapacity(IN UFS_PEIM_HC_PRIVATE_DATA * Private,IN UINTN Lun,OUT VOID * DataBuffer,OUT UINT32 * DataLength,OUT VOID * SenseData,OPTIONAL OUT UINT8 * SenseDataLength)200 UfsPeimReadCapacity (
201   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
202   IN     UINTN                        Lun,
203      OUT VOID                         *DataBuffer,
204      OUT UINT32                       *DataLength,
205      OUT VOID                         *SenseData,  OPTIONAL
206      OUT UINT8                        *SenseDataLength
207   )
208 {
209   UFS_SCSI_REQUEST_PACKET             Packet;
210   UINT8                               Cdb[UFS_SCSI_OP_LENGTH_TEN];
211   EFI_STATUS                          Status;
212 
213   ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
214   ZeroMem (Cdb, sizeof (Cdb));
215 
216   Cdb[0] = EFI_SCSI_OP_READ_CAPACITY;
217 
218   Packet.Timeout          = UFS_TIMEOUT;
219   Packet.Cdb              = Cdb;
220   Packet.CdbLength        = sizeof (Cdb);
221   Packet.InDataBuffer     = DataBuffer;
222   Packet.InTransferLength = *DataLength;
223   Packet.DataDirection    = UfsDataIn;
224   Packet.SenseData        = SenseData;
225   Packet.SenseDataLength  = *SenseDataLength;
226 
227   Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
228 
229   if (*SenseDataLength != 0) {
230     *SenseDataLength = Packet.SenseDataLength;
231   }
232 
233   if (!EFI_ERROR (Status)) {
234     *DataLength = Packet.InTransferLength;
235   }
236 
237   return Status;
238 }
239 
240 /**
241   Execute READ CAPACITY(16) SCSI command on a specific UFS device.
242 
243   @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
244   @param[in]  Lun                  The lun on which the SCSI cmd executed.
245   @param[out] DataBuffer           A pointer to READ_CAPACITY data buffer.
246   @param[out] DataLength           The length of output READ_CAPACITY data.
247   @param[out] SenseData            A pointer to output sense data.
248   @param[out] SenseDataLength      The length of output sense data.
249 
250   @retval EFI_SUCCESS              The command executed successfully.
251   @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.
252   @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.
253 
254 **/
255 EFI_STATUS
UfsPeimReadCapacity16(IN UFS_PEIM_HC_PRIVATE_DATA * Private,IN UINTN Lun,OUT VOID * DataBuffer,OUT UINT32 * DataLength,OUT VOID * SenseData,OPTIONAL OUT UINT8 * SenseDataLength)256 UfsPeimReadCapacity16 (
257   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
258   IN     UINTN                        Lun,
259      OUT VOID                         *DataBuffer,
260      OUT UINT32                       *DataLength,
261      OUT VOID                         *SenseData,  OPTIONAL
262      OUT UINT8                        *SenseDataLength
263   )
264 {
265   UFS_SCSI_REQUEST_PACKET             Packet;
266   UINT8                               Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN];
267   EFI_STATUS                          Status;
268 
269   ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
270   ZeroMem (Cdb, sizeof (Cdb));
271 
272   Cdb[0]  = EFI_SCSI_OP_READ_CAPACITY16;
273   Cdb[1]  = 0x10;          // Service Action should be 0x10 for UFS device.
274   Cdb[13] = 0x20;          // The maximum number of bytes for returned data.
275 
276   Packet.Timeout          = UFS_TIMEOUT;
277   Packet.Cdb              = Cdb;
278   Packet.CdbLength        = sizeof (Cdb);
279   Packet.InDataBuffer     = DataBuffer;
280   Packet.InTransferLength = *DataLength;
281   Packet.DataDirection    = UfsDataIn;
282   Packet.SenseData        = SenseData;
283   Packet.SenseDataLength  = *SenseDataLength;
284 
285   Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
286 
287   if (*SenseDataLength != 0) {
288     *SenseDataLength = Packet.SenseDataLength;
289   }
290 
291   if (!EFI_ERROR (Status)) {
292     *DataLength = Packet.InTransferLength;
293   }
294 
295   return Status;
296 }
297 
298 /**
299   Execute READ (10) SCSI command on a specific UFS device.
300 
301   @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
302   @param[in]  Lun                  The lun on which the SCSI cmd executed.
303   @param[in]  StartLba             The start LBA.
304   @param[in]  SectorNum            The sector number to be read.
305   @param[out] DataBuffer           A pointer to data buffer.
306   @param[out] DataLength           The length of output data.
307   @param[out] SenseData            A pointer to output sense data.
308   @param[out] SenseDataLength      The length of output sense data.
309 
310   @retval EFI_SUCCESS              The command executed successfully.
311   @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.
312   @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.
313 
314 **/
315 EFI_STATUS
UfsPeimRead10(IN UFS_PEIM_HC_PRIVATE_DATA * Private,IN UINTN Lun,IN UINTN StartLba,IN UINT32 SectorNum,OUT VOID * DataBuffer,OUT UINT32 * DataLength,OUT VOID * SenseData,OPTIONAL OUT UINT8 * SenseDataLength)316 UfsPeimRead10 (
317   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
318   IN     UINTN                        Lun,
319   IN     UINTN                        StartLba,
320   IN     UINT32                       SectorNum,
321      OUT VOID                         *DataBuffer,
322      OUT UINT32                       *DataLength,
323      OUT VOID                         *SenseData,  OPTIONAL
324      OUT UINT8                        *SenseDataLength
325   )
326 {
327   UFS_SCSI_REQUEST_PACKET             Packet;
328   UINT8                               Cdb[UFS_SCSI_OP_LENGTH_TEN];
329   EFI_STATUS                          Status;
330 
331   ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
332   ZeroMem (Cdb, sizeof (Cdb));
333 
334   Cdb[0] = EFI_SCSI_OP_READ10;
335   WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 ((UINT32) StartLba));
336   WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorNum));
337 
338   Packet.Timeout          = UFS_TIMEOUT;
339   Packet.Cdb              = Cdb;
340   Packet.CdbLength        = sizeof (Cdb);
341   Packet.InDataBuffer     = DataBuffer;
342   Packet.InTransferLength = *DataLength;
343   Packet.DataDirection    = UfsDataIn;
344   Packet.SenseData        = SenseData;
345   Packet.SenseDataLength  = *SenseDataLength;
346 
347   Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
348 
349   if (*SenseDataLength != 0) {
350     *SenseDataLength = Packet.SenseDataLength;
351   }
352 
353   if (!EFI_ERROR (Status)) {
354     *DataLength = Packet.InTransferLength;
355   }
356 
357   return Status;
358 }
359 
360 /**
361   Execute READ (16) SCSI command on a specific UFS device.
362 
363   @param[in]  Private              A pointer to UFS_PEIM_HC_PRIVATE_DATA data structure.
364   @param[in]  Lun                  The lun on which the SCSI cmd executed.
365   @param[in]  StartLba             The start LBA.
366   @param[in]  SectorNum            The sector number to be read.
367   @param[out] DataBuffer           A pointer to data buffer.
368   @param[out] DataLength           The length of output data.
369   @param[out] SenseData            A pointer to output sense data.
370   @param[out] SenseDataLength      The length of output sense data.
371 
372   @retval EFI_SUCCESS              The command executed successfully.
373   @retval EFI_DEVICE_ERROR         A device error occurred while attempting to send SCSI Request Packet.
374   @retval EFI_TIMEOUT              A timeout occurred while waiting for the SCSI Request Packet to execute.
375 
376 **/
377 EFI_STATUS
UfsPeimRead16(IN UFS_PEIM_HC_PRIVATE_DATA * Private,IN UINTN Lun,IN UINTN StartLba,IN UINT32 SectorNum,OUT VOID * DataBuffer,OUT UINT32 * DataLength,OUT VOID * SenseData,OPTIONAL OUT UINT8 * SenseDataLength)378 UfsPeimRead16 (
379   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
380   IN     UINTN                        Lun,
381   IN     UINTN                        StartLba,
382   IN     UINT32                       SectorNum,
383      OUT VOID                         *DataBuffer,
384      OUT UINT32                       *DataLength,
385      OUT VOID                         *SenseData,  OPTIONAL
386      OUT UINT8                        *SenseDataLength
387   )
388 {
389   UFS_SCSI_REQUEST_PACKET             Packet;
390   UINT8                               Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN];
391   EFI_STATUS                          Status;
392 
393   ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
394   ZeroMem (Cdb, sizeof (Cdb));
395 
396   Cdb[0] = EFI_SCSI_OP_READ16;
397   WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));
398   WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorNum));
399 
400   Packet.Timeout          = UFS_TIMEOUT;
401   Packet.Cdb              = Cdb;
402   Packet.CdbLength        = sizeof (Cdb);
403   Packet.InDataBuffer     = DataBuffer;
404   Packet.InTransferLength = *DataLength;
405   Packet.DataDirection    = UfsDataIn;
406   Packet.SenseData        = SenseData;
407   Packet.SenseDataLength  = *SenseDataLength;
408 
409   Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
410 
411   if (*SenseDataLength != 0) {
412     *SenseDataLength = Packet.SenseDataLength;
413   }
414 
415   if (!EFI_ERROR (Status)) {
416     *DataLength = Packet.InTransferLength;
417   }
418 
419   return Status;
420 }
421 
422 /**
423   Parsing Sense Keys from sense data.
424 
425   @param  Media              The pointer of EFI_PEI_BLOCK_IO_MEDIA
426   @param  SenseData          The pointer of EFI_SCSI_SENSE_DATA
427   @param  NeedRetry          The pointer of action which indicates what is need to retry
428 
429   @retval EFI_DEVICE_ERROR   Indicates that error occurs
430   @retval EFI_SUCCESS        Successfully to complete the parsing
431 
432 **/
433 EFI_STATUS
UfsPeimParsingSenseKeys(IN EFI_PEI_BLOCK_IO2_MEDIA * Media,IN EFI_SCSI_SENSE_DATA * SenseData,OUT BOOLEAN * NeedRetry)434 UfsPeimParsingSenseKeys (
435   IN     EFI_PEI_BLOCK_IO2_MEDIA   *Media,
436   IN     EFI_SCSI_SENSE_DATA       *SenseData,
437      OUT BOOLEAN                   *NeedRetry
438   )
439 {
440   if ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
441       (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
442     Media->MediaPresent = FALSE;
443     *NeedRetry = FALSE;
444     DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is No Media\n"));
445     return EFI_DEVICE_ERROR;
446   }
447 
448   if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
449       (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
450     *NeedRetry = TRUE;
451     DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is Media Change\n"));
452     return EFI_SUCCESS;
453   }
454 
455   if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
456       (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
457     *NeedRetry = TRUE;
458     DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n"));
459     return EFI_SUCCESS;
460   }
461 
462   if ((SenseData->Sense_Key == EFI_SCSI_SK_MEDIUM_ERROR) ||
463       ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
464       (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN))) {
465     *NeedRetry = FALSE;
466     DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Media Error\n"));
467     return EFI_DEVICE_ERROR;
468   }
469 
470   if (SenseData->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
471     *NeedRetry = FALSE;
472     DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Hardware Error\n"));
473     return EFI_DEVICE_ERROR;
474   }
475 
476   if ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
477       (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_NOT_READY) &&
478       (SenseData->Addnl_Sense_Code_Qualifier == EFI_SCSI_ASCQ_IN_PROGRESS)) {
479     *NeedRetry = TRUE;
480     DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n"));
481     return EFI_SUCCESS;
482   }
483 
484   *NeedRetry = FALSE;
485   DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
486   return EFI_DEVICE_ERROR;
487 }
488 
489 
490 /**
491   Gets the count of block I/O devices that one specific block driver detects.
492 
493   This function is used for getting the count of block I/O devices that one
494   specific block driver detects.  To the PEI ATAPI driver, it returns the number
495   of all the detected ATAPI devices it detects during the enumeration process.
496   To the PEI legacy floppy driver, it returns the number of all the legacy
497   devices it finds during its enumeration process. If no device is detected,
498   then the function will return zero.
499 
500   @param[in]  PeiServices          General-purpose services that are available
501                                    to every PEIM.
502   @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
503                                    instance.
504   @param[out] NumberBlockDevices   The number of block I/O devices discovered.
505 
506   @retval     EFI_SUCCESS          The operation performed successfully.
507 
508 **/
509 EFI_STATUS
510 EFIAPI
UfsBlockIoPeimGetDeviceNo(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * This,OUT UINTN * NumberBlockDevices)511 UfsBlockIoPeimGetDeviceNo (
512   IN  EFI_PEI_SERVICES               **PeiServices,
513   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
514   OUT UINTN                          *NumberBlockDevices
515   )
516 {
517   //
518   // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
519   // At PEI phase, we will only expose normal Luns to user.
520   // For those disabled Lun, when user try to access it, the operation would fail.
521   //
522   *NumberBlockDevices = UFS_PEIM_MAX_LUNS;
523   return EFI_SUCCESS;
524 }
525 
526 /**
527   Gets a block device's media information.
528 
529   This function will provide the caller with the specified block device's media
530   information. If the media changes, calling this function will update the media
531   information accordingly.
532 
533   @param[in]  PeiServices   General-purpose services that are available to every
534                             PEIM
535   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
536   @param[in]  DeviceIndex   Specifies the block device to which the function wants
537                             to talk. Because the driver that implements Block I/O
538                             PPIs will manage multiple block devices, the PPIs that
539                             want to talk to a single device must specify the
540                             device index that was assigned during the enumeration
541                             process. This index is a number from one to
542                             NumberBlockDevices.
543   @param[out] MediaInfo     The media information of the specified block media.
544                             The caller is responsible for the ownership of this
545                             data structure.
546 
547   @par Note:
548       The MediaInfo structure describes an enumeration of possible block device
549       types.  This enumeration exists because no device paths are actually passed
550       across interfaces that describe the type or class of hardware that is publishing
551       the block I/O interface. This enumeration will allow for policy decisions
552       in the Recovery PEIM, such as "Try to recover from legacy floppy first,
553       LS-120 second, CD-ROM third." If there are multiple partitions abstracted
554       by a given device type, they should be reported in ascending order; this
555       order also applies to nested partitions, such as legacy MBR, where the
556       outermost partitions would have precedence in the reporting order. The
557       same logic applies to systems such as IDE that have precedence relationships
558       like "Master/Slave" or "Primary/Secondary". The master device should be
559       reported first, the slave second.
560 
561   @retval EFI_SUCCESS        Media information about the specified block device
562                              was obtained successfully.
563   @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware
564                              error.
565 
566 **/
567 EFI_STATUS
568 EFIAPI
UfsBlockIoPeimGetMediaInfo(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * This,IN UINTN DeviceIndex,OUT EFI_PEI_BLOCK_IO_MEDIA * MediaInfo)569 UfsBlockIoPeimGetMediaInfo (
570   IN  EFI_PEI_SERVICES               **PeiServices,
571   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
572   IN  UINTN                          DeviceIndex,
573   OUT EFI_PEI_BLOCK_IO_MEDIA         *MediaInfo
574   )
575 {
576   EFI_STATUS                         Status;
577   UFS_PEIM_HC_PRIVATE_DATA           *Private;
578   EFI_SCSI_SENSE_DATA                SenseData;
579   UINT8                              SenseDataLength;
580   EFI_SCSI_DISK_CAPACITY_DATA        Capacity;
581   EFI_SCSI_DISK_CAPACITY_DATA16      Capacity16;
582   UINTN                              DataLength;
583   BOOLEAN                            NeedRetry;
584   UINTN                              Lun;
585 
586   Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
587   NeedRetry = TRUE;
588 
589   if ((DeviceIndex == 0) || (DeviceIndex > UFS_PEIM_MAX_LUNS)) {
590     return EFI_INVALID_PARAMETER;
591   }
592 
593   Lun = DeviceIndex - 1;
594   if ((Private->Luns.BitMask & (BIT0 << Lun)) == 0) {
595     return EFI_ACCESS_DENIED;
596   }
597 
598   ZeroMem (&SenseData, sizeof (SenseData));
599   ZeroMem (&Capacity, sizeof (Capacity));
600   ZeroMem (&Capacity16, sizeof (Capacity16));
601   SenseDataLength = sizeof (SenseData);
602   //
603   // First test unit ready
604   //
605   do {
606     Status = UfsPeimTestUnitReady (
607                Private,
608                Lun,
609                &SenseData,
610                &SenseDataLength
611                );
612     if (!EFI_ERROR (Status)) {
613       break;
614     }
615 
616     if (SenseDataLength == 0) {
617       continue;
618     }
619 
620     Status = UfsPeimParsingSenseKeys (&(Private->Media[Lun]), &SenseData, &NeedRetry);
621     if (EFI_ERROR (Status)) {
622       return EFI_DEVICE_ERROR;
623     }
624 
625   } while (NeedRetry);
626 
627   DataLength      = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
628   SenseDataLength = 0;
629   Status = UfsPeimReadCapacity (Private, Lun, &Capacity, (UINT32 *)&DataLength, NULL, &SenseDataLength);
630   if (EFI_ERROR (Status)) {
631     return EFI_DEVICE_ERROR;
632   }
633 
634   if ((Capacity.LastLba3 == 0xff) && (Capacity.LastLba2 == 0xff) &&
635       (Capacity.LastLba1 == 0xff) && (Capacity.LastLba0 == 0xff)) {
636     DataLength      = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
637     SenseDataLength = 0;
638     Status = UfsPeimReadCapacity16 (Private, Lun, &Capacity16, (UINT32 *)&DataLength, NULL, &SenseDataLength);
639     if (EFI_ERROR (Status)) {
640       return EFI_DEVICE_ERROR;
641     }
642     Private->Media[Lun].LastBlock  = ((UINT32)Capacity16.LastLba3 << 24) | (Capacity16.LastLba2 << 16) | (Capacity16.LastLba1 << 8) | Capacity16.LastLba0;
643     Private->Media[Lun].LastBlock |= LShiftU64 ((UINT64)Capacity16.LastLba7, 56) | LShiftU64((UINT64)Capacity16.LastLba6, 48) | LShiftU64 ((UINT64)Capacity16.LastLba5, 40) | LShiftU64 ((UINT64)Capacity16.LastLba4, 32);
644     Private->Media[Lun].BlockSize  = (Capacity16.BlockSize3 << 24) | (Capacity16.BlockSize2 << 16) | (Capacity16.BlockSize1 << 8) | Capacity16.BlockSize0;
645   } else {
646     Private->Media[Lun].LastBlock  = ((UINT32)Capacity.LastLba3 << 24) | (Capacity.LastLba2 << 16) | (Capacity.LastLba1 << 8) | Capacity.LastLba0;
647     Private->Media[Lun].BlockSize  = (Capacity.BlockSize3 << 24) | (Capacity.BlockSize2 << 16) | (Capacity.BlockSize1 << 8) | Capacity.BlockSize0;
648   }
649 
650   MediaInfo->DeviceType   = UfsDevice;
651   MediaInfo->MediaPresent = Private->Media[Lun].MediaPresent;
652   MediaInfo->LastBlock    = (UINTN)Private->Media[Lun].LastBlock;
653   MediaInfo->BlockSize    = Private->Media[Lun].BlockSize;
654 
655   return EFI_SUCCESS;
656 }
657 
658 /**
659   Reads the requested number of blocks from the specified block device.
660 
661   The function reads the requested number of blocks from the device. All the
662   blocks are read, or an error is returned. If there is no media in the device,
663   the function returns EFI_NO_MEDIA.
664 
665   @param[in]  PeiServices   General-purpose services that are available to
666                             every PEIM.
667   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
668   @param[in]  DeviceIndex   Specifies the block device to which the function wants
669                             to talk. Because the driver that implements Block I/O
670                             PPIs will manage multiple block devices, PPIs that
671                             want to talk to a single device must specify the device
672                             index that was assigned during the enumeration process.
673                             This index is a number from one to NumberBlockDevices.
674   @param[in]  StartLBA      The starting logical block address (LBA) to read from
675                             on the device
676   @param[in]  BufferSize    The size of the Buffer in bytes. This number must be
677                             a multiple of the intrinsic block size of the device.
678   @param[out] Buffer        A pointer to the destination buffer for the data.
679                             The caller is responsible for the ownership of the
680                             buffer.
681 
682   @retval EFI_SUCCESS             The data was read correctly from the device.
683   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
684                                   to perform the read operation.
685   @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not
686                                   valid, or the buffer is not properly aligned.
687   @retval EFI_NO_MEDIA            There is no media in the device.
688   @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
689                                   the intrinsic block size of the device.
690 
691 **/
692 EFI_STATUS
693 EFIAPI
UfsBlockIoPeimReadBlocks(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO_PPI * This,IN UINTN DeviceIndex,IN EFI_PEI_LBA StartLBA,IN UINTN BufferSize,OUT VOID * Buffer)694 UfsBlockIoPeimReadBlocks (
695   IN  EFI_PEI_SERVICES               **PeiServices,
696   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
697   IN  UINTN                          DeviceIndex,
698   IN  EFI_PEI_LBA                    StartLBA,
699   IN  UINTN                          BufferSize,
700   OUT VOID                           *Buffer
701   )
702 {
703   EFI_STATUS                         Status;
704   UINTN                              BlockSize;
705   UINTN                              NumberOfBlocks;
706   UFS_PEIM_HC_PRIVATE_DATA           *Private;
707   EFI_SCSI_SENSE_DATA                SenseData;
708   UINT8                              SenseDataLength;
709   BOOLEAN                            NeedRetry;
710   UINTN                              Lun;
711 
712   Status    = EFI_SUCCESS;
713   NeedRetry = TRUE;
714   Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
715 
716   ZeroMem (&SenseData, sizeof (SenseData));
717   SenseDataLength = sizeof (SenseData);
718 
719   //
720   // Check parameters
721   //
722   if (Buffer == NULL) {
723     return EFI_INVALID_PARAMETER;
724   }
725 
726   if (BufferSize == 0) {
727     return EFI_SUCCESS;
728   }
729 
730   if ((DeviceIndex == 0) || (DeviceIndex > UFS_PEIM_MAX_LUNS)) {
731     return EFI_INVALID_PARAMETER;
732   }
733 
734   Lun = DeviceIndex - 1;
735   if ((Private->Luns.BitMask & (BIT0 << Lun)) == 0) {
736     return EFI_ACCESS_DENIED;
737   }
738 
739   BlockSize = Private->Media[Lun].BlockSize;
740 
741   if (BufferSize % BlockSize != 0) {
742     Status = EFI_BAD_BUFFER_SIZE;
743   }
744 
745   if (StartLBA > Private->Media[Lun].LastBlock) {
746     Status = EFI_INVALID_PARAMETER;
747   }
748 
749   NumberOfBlocks = BufferSize / BlockSize;
750 
751   do {
752     Status = UfsPeimTestUnitReady (
753                Private,
754                Lun,
755                &SenseData,
756                &SenseDataLength
757                );
758     if (!EFI_ERROR (Status)) {
759       break;
760     }
761 
762     if (SenseDataLength == 0) {
763       continue;
764     }
765 
766     Status = UfsPeimParsingSenseKeys (&(Private->Media[Lun]), &SenseData, &NeedRetry);
767     if (EFI_ERROR (Status)) {
768       return EFI_DEVICE_ERROR;
769     }
770 
771   } while (NeedRetry);
772 
773   SenseDataLength = 0;
774   if (Private->Media[Lun].LastBlock < 0xfffffffful) {
775     Status = UfsPeimRead10 (
776                Private,
777                Lun,
778                (UINT32)StartLBA,
779                (UINT32)NumberOfBlocks,
780                Buffer,
781                (UINT32 *)&BufferSize,
782                NULL,
783                &SenseDataLength
784                );
785   } else {
786     Status = UfsPeimRead16 (
787                Private,
788                Lun,
789                (UINT32)StartLBA,
790                (UINT32)NumberOfBlocks,
791                Buffer,
792                (UINT32 *)&BufferSize,
793                NULL,
794                &SenseDataLength
795                );
796   }
797   return Status;
798 }
799 
800 /**
801   Gets the count of block I/O devices that one specific block driver detects.
802 
803   This function is used for getting the count of block I/O devices that one
804   specific block driver detects.  To the PEI ATAPI driver, it returns the number
805   of all the detected ATAPI devices it detects during the enumeration process.
806   To the PEI legacy floppy driver, it returns the number of all the legacy
807   devices it finds during its enumeration process. If no device is detected,
808   then the function will return zero.
809 
810   @param[in]  PeiServices          General-purpose services that are available
811                                    to every PEIM.
812   @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
813                                    instance.
814   @param[out] NumberBlockDevices   The number of block I/O devices discovered.
815 
816   @retval     EFI_SUCCESS          The operation performed successfully.
817 
818 **/
819 EFI_STATUS
820 EFIAPI
UfsBlockIoPeimGetDeviceNo2(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * This,OUT UINTN * NumberBlockDevices)821 UfsBlockIoPeimGetDeviceNo2 (
822   IN  EFI_PEI_SERVICES               **PeiServices,
823   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
824   OUT UINTN                          *NumberBlockDevices
825   )
826 {
827   //
828   // For Ufs device, it has up to 8 normal Luns plus some well-known Luns.
829   // At PEI phase, we will only expose normal Luns to user.
830   // For those disabled Lun, when user try to access it, the operation would fail.
831   //
832   *NumberBlockDevices = UFS_PEIM_MAX_LUNS;
833   return EFI_SUCCESS;
834 }
835 
836 /**
837   Gets a block device's media information.
838 
839   This function will provide the caller with the specified block device's media
840   information. If the media changes, calling this function will update the media
841   information accordingly.
842 
843   @param[in]  PeiServices   General-purpose services that are available to every
844                             PEIM
845   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
846   @param[in]  DeviceIndex   Specifies the block device to which the function wants
847                             to talk. Because the driver that implements Block I/O
848                             PPIs will manage multiple block devices, the PPIs that
849                             want to talk to a single device must specify the
850                             device index that was assigned during the enumeration
851                             process. This index is a number from one to
852                             NumberBlockDevices.
853   @param[out] MediaInfo     The media information of the specified block media.
854                             The caller is responsible for the ownership of this
855                             data structure.
856 
857   @par Note:
858       The MediaInfo structure describes an enumeration of possible block device
859       types.  This enumeration exists because no device paths are actually passed
860       across interfaces that describe the type or class of hardware that is publishing
861       the block I/O interface. This enumeration will allow for policy decisions
862       in the Recovery PEIM, such as "Try to recover from legacy floppy first,
863       LS-120 second, CD-ROM third." If there are multiple partitions abstracted
864       by a given device type, they should be reported in ascending order; this
865       order also applies to nested partitions, such as legacy MBR, where the
866       outermost partitions would have precedence in the reporting order. The
867       same logic applies to systems such as IDE that have precedence relationships
868       like "Master/Slave" or "Primary/Secondary". The master device should be
869       reported first, the slave second.
870 
871   @retval EFI_SUCCESS        Media information about the specified block device
872                              was obtained successfully.
873   @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware
874                              error.
875 
876 **/
877 EFI_STATUS
878 EFIAPI
UfsBlockIoPeimGetMediaInfo2(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * This,IN UINTN DeviceIndex,OUT EFI_PEI_BLOCK_IO2_MEDIA * MediaInfo)879 UfsBlockIoPeimGetMediaInfo2 (
880   IN  EFI_PEI_SERVICES               **PeiServices,
881   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
882   IN  UINTN                          DeviceIndex,
883   OUT EFI_PEI_BLOCK_IO2_MEDIA        *MediaInfo
884   )
885 {
886   EFI_STATUS                         Status;
887   UFS_PEIM_HC_PRIVATE_DATA           *Private;
888   EFI_PEI_BLOCK_IO_MEDIA             Media;
889   UINTN                              Lun;
890 
891   Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
892 
893   Status    = UfsBlockIoPeimGetMediaInfo (
894                 PeiServices,
895                 &Private->BlkIoPpi,
896                 DeviceIndex,
897                 &Media
898                 );
899   if (EFI_ERROR (Status)) {
900     return Status;
901   }
902 
903   Lun = DeviceIndex - 1;
904   CopyMem (MediaInfo, &(Private->Media[Lun]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));
905   return EFI_SUCCESS;
906 }
907 
908 /**
909   Reads the requested number of blocks from the specified block device.
910 
911   The function reads the requested number of blocks from the device. All the
912   blocks are read, or an error is returned. If there is no media in the device,
913   the function returns EFI_NO_MEDIA.
914 
915   @param[in]  PeiServices   General-purpose services that are available to
916                             every PEIM.
917   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
918   @param[in]  DeviceIndex   Specifies the block device to which the function wants
919                             to talk. Because the driver that implements Block I/O
920                             PPIs will manage multiple block devices, PPIs that
921                             want to talk to a single device must specify the device
922                             index that was assigned during the enumeration process.
923                             This index is a number from one to NumberBlockDevices.
924   @param[in]  StartLBA      The starting logical block address (LBA) to read from
925                             on the device
926   @param[in]  BufferSize    The size of the Buffer in bytes. This number must be
927                             a multiple of the intrinsic block size of the device.
928   @param[out] Buffer        A pointer to the destination buffer for the data.
929                             The caller is responsible for the ownership of the
930                             buffer.
931 
932   @retval EFI_SUCCESS             The data was read correctly from the device.
933   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
934                                   to perform the read operation.
935   @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not
936                                   valid, or the buffer is not properly aligned.
937   @retval EFI_NO_MEDIA            There is no media in the device.
938   @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
939                                   the intrinsic block size of the device.
940 
941 **/
942 EFI_STATUS
943 EFIAPI
UfsBlockIoPeimReadBlocks2(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI * This,IN UINTN DeviceIndex,IN EFI_PEI_LBA StartLBA,IN UINTN BufferSize,OUT VOID * Buffer)944 UfsBlockIoPeimReadBlocks2 (
945   IN  EFI_PEI_SERVICES               **PeiServices,
946   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
947   IN  UINTN                          DeviceIndex,
948   IN  EFI_PEI_LBA                    StartLBA,
949   IN  UINTN                          BufferSize,
950   OUT VOID                           *Buffer
951   )
952 {
953   EFI_STATUS                         Status;
954   UFS_PEIM_HC_PRIVATE_DATA           *Private;
955 
956   Status    = EFI_SUCCESS;
957   Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
958 
959   Status  = UfsBlockIoPeimReadBlocks (
960               PeiServices,
961               &Private->BlkIoPpi,
962               DeviceIndex,
963               StartLBA,
964               BufferSize,
965               Buffer
966               );
967   return Status;
968 }
969 
970 /**
971   One notified function to cleanup the allocated DMA buffers at the end of PEI.
972 
973   @param[in]  PeiServices        Pointer to PEI Services Table.
974   @param[in]  NotifyDescriptor   Pointer to the descriptor for the Notification
975                                  event that caused this function to execute.
976   @param[in]  Ppi                Pointer to the PPI data associated with this function.
977 
978   @retval     EFI_SUCCESS  The function completes successfully
979 
980 **/
981 EFI_STATUS
982 EFIAPI
UfsEndOfPei(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)983 UfsEndOfPei (
984   IN EFI_PEI_SERVICES           **PeiServices,
985   IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
986   IN VOID                       *Ppi
987   )
988 {
989   UFS_PEIM_HC_PRIVATE_DATA    *Private;
990 
991   Private = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
992 
993   if ((Private->Pool != NULL) && (Private->Pool->Head != NULL)) {
994     UfsPeimFreeMemPool (Private->Pool);
995   }
996 
997   if (Private->UtpTmrlBase != NULL) {
998     IoMmuFreeBuffer (
999       EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)),
1000       Private->UtpTmrlBase,
1001       Private->TmrlMapping
1002       );
1003   }
1004 
1005   if (Private->UtpTrlBase != NULL) {
1006     IoMmuFreeBuffer (
1007       EFI_SIZE_TO_PAGES (Private->Nutrs * sizeof (UTP_TRD)),
1008       Private->UtpTrlBase,
1009       Private->TrlMapping
1010       );
1011   }
1012 
1013   UfsControllerStop (Private);
1014 
1015   return EFI_SUCCESS;
1016 }
1017 
1018 /**
1019   The user code starts with this function.
1020 
1021   @param  FileHandle             Handle of the file being invoked.
1022   @param  PeiServices            Describes the list of possible PEI Services.
1023 
1024   @retval EFI_SUCCESS            The driver is successfully initialized.
1025   @retval Others                 Can't initialize the driver.
1026 
1027 **/
1028 EFI_STATUS
1029 EFIAPI
InitializeUfsBlockIoPeim(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)1030 InitializeUfsBlockIoPeim (
1031   IN EFI_PEI_FILE_HANDLE        FileHandle,
1032   IN CONST EFI_PEI_SERVICES     **PeiServices
1033   )
1034 {
1035   EFI_STATUS                    Status;
1036   UFS_PEIM_HC_PRIVATE_DATA      *Private;
1037   EDKII_UFS_HOST_CONTROLLER_PPI *UfsHcPpi;
1038   UINT32                        Index;
1039   UFS_CONFIG_DESC               Config;
1040   UINTN                         MmioBase;
1041   UINT8                         Controller;
1042 
1043   //
1044   // Shadow this PEIM to run from memory
1045   //
1046   if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
1047     return EFI_SUCCESS;
1048   }
1049 
1050   //
1051   // locate ufs host controller PPI
1052   //
1053   Status = PeiServicesLocatePpi (
1054              &gEdkiiPeiUfsHostControllerPpiGuid,
1055              0,
1056              NULL,
1057              (VOID **) &UfsHcPpi
1058              );
1059   if (EFI_ERROR (Status)) {
1060     return EFI_DEVICE_ERROR;
1061   }
1062 
1063   IoMmuInit ();
1064 
1065   Controller = 0;
1066   MmioBase   = 0;
1067   while (TRUE) {
1068     Status = UfsHcPpi->GetUfsHcMmioBar (UfsHcPpi, Controller, &MmioBase);
1069     //
1070     // When status is error, meant no controller is found
1071     //
1072     if (EFI_ERROR (Status)) {
1073       break;
1074     }
1075 
1076     Private = AllocateCopyPool (sizeof (UFS_PEIM_HC_PRIVATE_DATA), &gUfsHcPeimTemplate);
1077     if (Private == NULL) {
1078       Status = EFI_OUT_OF_RESOURCES;
1079       break;
1080     }
1081 
1082     Private->BlkIoPpiList.Ppi  = &Private->BlkIoPpi;
1083     Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;
1084     Private->UfsHcBase         = MmioBase;
1085 
1086     //
1087     // Initialize the memory pool which will be used in all transactions.
1088     //
1089     Status = UfsPeimInitMemPool (Private);
1090     if (EFI_ERROR (Status)) {
1091       Status = EFI_OUT_OF_RESOURCES;
1092       break;
1093     }
1094 
1095     //
1096     // Initialize UFS Host Controller H/W.
1097     //
1098     Status = UfsControllerInit (Private);
1099     if (EFI_ERROR (Status)) {
1100       DEBUG ((EFI_D_ERROR, "UfsDevicePei: Host Controller Initialization Error, Status = %r\n", Status));
1101       Controller++;
1102       continue;
1103     }
1104 
1105     //
1106     // UFS 2.0 spec Section 13.1.3.3:
1107     // At the end of the UFS Interconnect Layer initialization on both host and device side,
1108     // the host shall send a NOP OUT UPIU to verify that the device UTP Layer is ready.
1109     //
1110     Status = UfsExecNopCmds (Private);
1111     if (EFI_ERROR (Status)) {
1112       DEBUG ((EFI_D_ERROR, "Ufs Sending NOP IN command Error, Status = %r\n", Status));
1113       Controller++;
1114       continue;
1115     }
1116 
1117     //
1118     // The host enables the device initialization completion by setting fDeviceInit flag.
1119     //
1120     Status = UfsSetFlag (Private, UfsFlagDevInit);
1121     if (EFI_ERROR (Status)) {
1122       DEBUG ((EFI_D_ERROR, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status));
1123       Controller++;
1124       continue;
1125     }
1126 
1127     //
1128     // Get Ufs Device's Lun Info by reading Configuration Descriptor.
1129     //
1130     Status = UfsRwDeviceDesc (Private, TRUE, UfsConfigDesc, 0, 0, &Config, sizeof (UFS_CONFIG_DESC));
1131     if (EFI_ERROR (Status)) {
1132       DEBUG ((EFI_D_ERROR, "Ufs Get Configuration Descriptor Error, Status = %r\n", Status));
1133       Controller++;
1134       continue;
1135     }
1136 
1137     for (Index = 0; Index < UFS_PEIM_MAX_LUNS; Index++) {
1138       if (Config.UnitDescConfParams[Index].LunEn != 0) {
1139         Private->Luns.BitMask |= (BIT0 << Index);
1140         DEBUG ((EFI_D_INFO, "Ufs %d Lun %d is enabled\n", Controller, Index));
1141       }
1142     }
1143 
1144     PeiServicesInstallPpi (&Private->BlkIoPpiList);
1145     PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
1146     Controller++;
1147   }
1148 
1149   return EFI_SUCCESS;
1150 }
1151