Home | History | Annotate | Download | only in UfsBlockIoPei
      1 /** @file
      2 
      3   Copyright (c) 2014 - 2016, 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
      8 
      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.
     11 
     12 **/
     13 
     14 #include "UfsBlockIoPei.h"
     15 
     16 //
     17 // Template for UFS HC Peim Private Data.
     18 //
     19 UFS_PEIM_HC_PRIVATE_DATA   gUfsHcPeimTemplate = {
     20   UFS_PEIM_HC_SIG,                // Signature
     21   NULL,                           // Controller
     22   NULL,                           // Pool
     23   {                               // BlkIoPpi
     24     UfsBlockIoPeimGetDeviceNo,
     25     UfsBlockIoPeimGetMediaInfo,
     26     UfsBlockIoPeimReadBlocks
     27   },
     28   {                               // BlkIo2Ppi
     29     EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
     30     UfsBlockIoPeimGetDeviceNo2,
     31     UfsBlockIoPeimGetMediaInfo2,
     32     UfsBlockIoPeimReadBlocks2
     33   },
     34   {                               // BlkIoPpiList
     35     EFI_PEI_PPI_DESCRIPTOR_PPI,
     36     &gEfiPeiVirtualBlockIoPpiGuid,
     37     NULL
     38   },
     39   {                               // BlkIo2PpiList
     40     EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
     41     &gEfiPeiVirtualBlockIo2PpiGuid,
     42     NULL
     43   },
     44   {                               // Media
     45     {
     46       MSG_UFS_DP,
     47       FALSE,
     48       TRUE,
     49       FALSE,
     50       0x1000,
     51       0
     52     },
     53     {
     54       MSG_UFS_DP,
     55       FALSE,
     56       TRUE,
     57       FALSE,
     58       0x1000,
     59       0
     60     },
     61     {
     62       MSG_UFS_DP,
     63       FALSE,
     64       TRUE,
     65       FALSE,
     66       0x1000,
     67       0
     68     },
     69     {
     70       MSG_UFS_DP,
     71       FALSE,
     72       TRUE,
     73       FALSE,
     74       0x1000,
     75       0
     76     },
     77     {
     78       MSG_UFS_DP,
     79       FALSE,
     80       TRUE,
     81       FALSE,
     82       0x1000,
     83       0
     84     },
     85     {
     86       MSG_UFS_DP,
     87       FALSE,
     88       TRUE,
     89       FALSE,
     90       0x1000,
     91       0
     92     },
     93     {
     94       MSG_UFS_DP,
     95       FALSE,
     96       TRUE,
     97       FALSE,
     98       0x1000,
     99       0
    100     },
    101     {
    102       MSG_UFS_DP,
    103       FALSE,
    104       TRUE,
    105       FALSE,
    106       0x1000,
    107       0
    108     }
    109   },
    110   0,                              // UfsHcBase
    111   0,                              // Capabilities
    112   0,                              // TaskTag
    113   0,                              // UtpTrlBase
    114   0,                              // Nutrs
    115   0,                              // UtpTmrlBase
    116   0,                              // Nutmrs
    117   {                               // Luns
    118     {
    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
    127     },
    128     0x0000,                           // By default exposing all Luns.
    129     0x0
    130   }
    131 };
    132 
    133 /**
    134   Execute Request Sense SCSI command on a specific UFS device.
    135 
    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.
    140 
    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.
    144 
    145 **/
    146 EFI_STATUS
    147 UfsPeimRequestSense (
    148   IN     UFS_PEIM_HC_PRIVATE_DATA        *Private,
    149   IN     UINTN                           Lun,
    150      OUT VOID                            *DataBuffer,
    151      OUT UINT32                          *DataBufferLength
    152   )
    153 {
    154   UFS_SCSI_REQUEST_PACKET                Packet;
    155   UINT8                                  Cdb[UFS_SCSI_OP_LENGTH_SIX];
    156   EFI_STATUS                             Status;
    157 
    158   ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
    159   ZeroMem (Cdb, sizeof (Cdb));
    160 
    161   Cdb[0]  = EFI_SCSI_OP_REQUEST_SENSE;
    162 
    163   Packet.Timeout          = UFS_TIMEOUT;
    164   Packet.Cdb              = Cdb;
    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;
    171 
    172   Status = UfsExecScsiCmds (Private,(UINT8)Lun, &Packet);
    173 
    174   if (!EFI_ERROR (Status)) {
    175     *DataBufferLength = Packet.InTransferLength;
    176   }
    177 
    178   return Status;
    179 }
    180 
    181 /**
    182   Execute TEST UNITY READY SCSI command on a specific UFS device.
    183 
    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.
    188 
    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.
    192 
    193 **/
    194 EFI_STATUS
    195 UfsPeimTestUnitReady (
    196   IN     UFS_PEIM_HC_PRIVATE_DATA        *Private,
    197   IN     UINTN                           Lun,
    198      OUT VOID                            *SenseData,  OPTIONAL
    199      OUT UINT8                           *SenseDataLength
    200   )
    201 {
    202   UFS_SCSI_REQUEST_PACKET                Packet;
    203   UINT8                                  Cdb[UFS_SCSI_OP_LENGTH_SIX];
    204   EFI_STATUS                             Status;
    205 
    206   ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
    207   ZeroMem (Cdb, sizeof (Cdb));
    208 
    209   Cdb[0]  = EFI_SCSI_OP_TEST_UNIT_READY;
    210 
    211   Packet.Timeout         = UFS_TIMEOUT;
    212   Packet.Cdb             = Cdb;
    213   Packet.CdbLength       = sizeof (Cdb);
    214   Packet.DataDirection   = UfsNoData;
    215   Packet.SenseData       = SenseData;
    216   Packet.SenseDataLength = *SenseDataLength;
    217 
    218   Status = UfsExecScsiCmds (Private,(UINT8)Lun, &Packet);
    219 
    220   if (*SenseDataLength != 0) {
    221     *SenseDataLength = Packet.SenseDataLength;
    222   }
    223 
    224   return Status;
    225 }
    226 
    227 /**
    228   Execute INQUIRY SCSI command on a specific UFS device.
    229 
    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.
    236 
    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.
    240 
    241 **/
    242 EFI_STATUS
    243 UfsPeimInquiry (
    244   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
    245   IN     UINTN                        Lun,
    246      OUT VOID                         *Inquiry,
    247      OUT UINT32                       *InquiryLength,
    248      OUT VOID                         *SenseData,  OPTIONAL
    249      OUT UINT8                        *SenseDataLength
    250   )
    251 {
    252   UFS_SCSI_REQUEST_PACKET             Packet;
    253   UINT8                               Cdb[UFS_SCSI_OP_LENGTH_SIX];
    254   EFI_STATUS                          Status;
    255 
    256   ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
    257   ZeroMem (Cdb, sizeof (Cdb));
    258 
    259   Cdb[0]  = EFI_SCSI_OP_INQUIRY;
    260   Cdb[4]  = sizeof (EFI_SCSI_INQUIRY_DATA);
    261 
    262   Packet.Timeout          = UFS_TIMEOUT;
    263   Packet.Cdb              = Cdb;
    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;
    270 
    271   Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
    272 
    273   if (*SenseDataLength != 0) {
    274     *SenseDataLength = Packet.SenseDataLength;
    275   }
    276 
    277   if (!EFI_ERROR (Status)) {
    278     *InquiryLength = Packet.InTransferLength;
    279   }
    280 
    281   return Status;
    282 }
    283 
    284 /**
    285   Execute READ CAPACITY(10) SCSI command on a specific UFS device.
    286 
    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.
    293 
    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.
    297 
    298 **/
    299 EFI_STATUS
    300 UfsPeimReadCapacity (
    301   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
    302   IN     UINTN                        Lun,
    303      OUT VOID                         *DataBuffer,
    304      OUT UINT32                       *DataLength,
    305      OUT VOID                         *SenseData,  OPTIONAL
    306      OUT UINT8                        *SenseDataLength
    307   )
    308 {
    309   UFS_SCSI_REQUEST_PACKET             Packet;
    310   UINT8                               Cdb[UFS_SCSI_OP_LENGTH_TEN];
    311   EFI_STATUS                          Status;
    312 
    313   ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
    314   ZeroMem (Cdb, sizeof (Cdb));
    315 
    316   Cdb[0] = EFI_SCSI_OP_READ_CAPACITY;
    317 
    318   Packet.Timeout          = UFS_TIMEOUT;
    319   Packet.Cdb              = Cdb;
    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;
    326 
    327   Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
    328 
    329   if (*SenseDataLength != 0) {
    330     *SenseDataLength = Packet.SenseDataLength;
    331   }
    332 
    333   if (!EFI_ERROR (Status)) {
    334     *DataLength = Packet.InTransferLength;
    335   }
    336 
    337   return Status;
    338 }
    339 
    340 /**
    341   Execute READ CAPACITY(16) SCSI command on a specific UFS device.
    342 
    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.
    349 
    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.
    353 
    354 **/
    355 EFI_STATUS
    356 UfsPeimReadCapacity16 (
    357   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
    358   IN     UINTN                        Lun,
    359      OUT VOID                         *DataBuffer,
    360      OUT UINT32                       *DataLength,
    361      OUT VOID                         *SenseData,  OPTIONAL
    362      OUT UINT8                        *SenseDataLength
    363   )
    364 {
    365   UFS_SCSI_REQUEST_PACKET             Packet;
    366   UINT8                               Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN];
    367   EFI_STATUS                          Status;
    368 
    369   ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
    370   ZeroMem (Cdb, sizeof (Cdb));
    371 
    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.
    375 
    376   Packet.Timeout          = UFS_TIMEOUT;
    377   Packet.Cdb              = Cdb;
    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;
    384 
    385   Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
    386 
    387   if (*SenseDataLength != 0) {
    388     *SenseDataLength = Packet.SenseDataLength;
    389   }
    390 
    391   if (!EFI_ERROR (Status)) {
    392     *DataLength = Packet.InTransferLength;
    393   }
    394 
    395   return Status;
    396 }
    397 
    398 /**
    399   Execute READ (10) SCSI command on a specific UFS device.
    400 
    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.
    409 
    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.
    413 
    414 **/
    415 EFI_STATUS
    416 UfsPeimRead10 (
    417   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
    418   IN     UINTN                        Lun,
    419   IN     UINTN                        StartLba,
    420   IN     UINT32                       SectorNum,
    421      OUT VOID                         *DataBuffer,
    422      OUT UINT32                       *DataLength,
    423      OUT VOID                         *SenseData,  OPTIONAL
    424      OUT UINT8                        *SenseDataLength
    425   )
    426 {
    427   UFS_SCSI_REQUEST_PACKET             Packet;
    428   UINT8                               Cdb[UFS_SCSI_OP_LENGTH_TEN];
    429   EFI_STATUS                          Status;
    430 
    431   ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
    432   ZeroMem (Cdb, sizeof (Cdb));
    433 
    434   Cdb[0] = EFI_SCSI_OP_READ10;
    435   WriteUnaligned32 ((UINT32 *)&Cdb[2], SwapBytes32 ((UINT32) StartLba));
    436   WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 ((UINT16) SectorNum));
    437 
    438   Packet.Timeout          = UFS_TIMEOUT;
    439   Packet.Cdb              = Cdb;
    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;
    446 
    447   Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
    448 
    449   if (*SenseDataLength != 0) {
    450     *SenseDataLength = Packet.SenseDataLength;
    451   }
    452 
    453   if (!EFI_ERROR (Status)) {
    454     *DataLength = Packet.InTransferLength;
    455   }
    456 
    457   return Status;
    458 }
    459 
    460 /**
    461   Execute READ (16) SCSI command on a specific UFS device.
    462 
    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.
    471 
    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.
    475 
    476 **/
    477 EFI_STATUS
    478 UfsPeimRead16 (
    479   IN     UFS_PEIM_HC_PRIVATE_DATA     *Private,
    480   IN     UINTN                        Lun,
    481   IN     UINTN                        StartLba,
    482   IN     UINT32                       SectorNum,
    483      OUT VOID                         *DataBuffer,
    484      OUT UINT32                       *DataLength,
    485      OUT VOID                         *SenseData,  OPTIONAL
    486      OUT UINT8                        *SenseDataLength
    487   )
    488 {
    489   UFS_SCSI_REQUEST_PACKET             Packet;
    490   UINT8                               Cdb[UFS_SCSI_OP_LENGTH_SIXTEEN];
    491   EFI_STATUS                          Status;
    492 
    493   ZeroMem (&Packet, sizeof (UFS_SCSI_REQUEST_PACKET));
    494   ZeroMem (Cdb, sizeof (Cdb));
    495 
    496   Cdb[0] = EFI_SCSI_OP_READ16;
    497   WriteUnaligned64 ((UINT64 *)&Cdb[2], SwapBytes64 (StartLba));
    498   WriteUnaligned32 ((UINT32 *)&Cdb[10], SwapBytes32 (SectorNum));
    499 
    500   Packet.Timeout          = UFS_TIMEOUT;
    501   Packet.Cdb              = Cdb;
    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;
    508 
    509   Status = UfsExecScsiCmds (Private, (UINT8)Lun, &Packet);
    510 
    511   if (*SenseDataLength != 0) {
    512     *SenseDataLength = Packet.SenseDataLength;
    513   }
    514 
    515   if (!EFI_ERROR (Status)) {
    516     *DataLength = Packet.InTransferLength;
    517   }
    518 
    519   return Status;
    520 }
    521 
    522 /**
    523   Parsing Sense Keys from sense data.
    524 
    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
    528 
    529   @retval EFI_DEVICE_ERROR   Indicates that error occurs
    530   @retval EFI_SUCCESS        Successfully to complete the parsing
    531 
    532 **/
    533 EFI_STATUS
    534 UfsPeimParsingSenseKeys (
    535   IN     EFI_PEI_BLOCK_IO2_MEDIA   *Media,
    536   IN     EFI_SCSI_SENSE_DATA       *SenseData,
    537      OUT BOOLEAN                   *NeedRetry
    538   )
    539 {
    540   if ((SenseData->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
    541       (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
    542     Media->MediaPresent = FALSE;
    543     *NeedRetry = FALSE;
    544     DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is No Media\n"));
    545     return EFI_DEVICE_ERROR;
    546   }
    547 
    548   if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
    549       (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
    550     *NeedRetry = TRUE;
    551     DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Is Media Change\n"));
    552     return EFI_SUCCESS;
    553   }
    554 
    555   if ((SenseData->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
    556       (SenseData->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
    557     *NeedRetry = TRUE;
    558     DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n"));
    559     return EFI_SUCCESS;
    560   }
    561 
    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))) {
    565     *NeedRetry = FALSE;
    566     DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Media Error\n"));
    567     return EFI_DEVICE_ERROR;
    568   }
    569 
    570   if (SenseData->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
    571     *NeedRetry = FALSE;
    572     DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Hardware Error\n"));
    573     return EFI_DEVICE_ERROR;
    574   }
    575 
    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)) {
    579     *NeedRetry = TRUE;
    580     DEBUG ((EFI_D_VERBOSE, "UfsBlockIoPei: Was Reset Before\n"));
    581     return EFI_SUCCESS;
    582   }
    583 
    584   *NeedRetry = FALSE;
    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;
    587 }
    588 
    589 
    590 /**
    591   Gets the count of block I/O devices that one specific block driver detects.
    592 
    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.
    599 
    600   @param[in]  PeiServices          General-purpose services that are available
    601                                    to every PEIM.
    602   @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
    603                                    instance.
    604   @param[out] NumberBlockDevices   The number of block I/O devices discovered.
    605 
    606   @retval     EFI_SUCCESS          The operation performed successfully.
    607 
    608 **/
    609 EFI_STATUS
    610 EFIAPI
    611 UfsBlockIoPeimGetDeviceNo (
    612   IN  EFI_PEI_SERVICES               **PeiServices,
    613   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,
    614   OUT UINTN                          *NumberBlockDevices
    615   )
    616 {
    617   //
    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.
    621   //
    622   *NumberBlockDevices = UFS_PEIM_MAX_LUNS;
    623   return EFI_SUCCESS;
    624 }
    625 
    626 /**
    627   Gets a block device's media information.
    628 
    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.
    632 
    633   @param[in]  PeiServices   General-purpose services that are available to every
    634                             PEIM
    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
    642                             NumberBlockDevices.
    643   @param[out] MediaInfo     The media information of the specified block media.
    644                             The caller is responsible for the ownership of this
    645                             data structure.
    646 
    647   @par Note:
    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.
    660 
    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
    664                              error.
    665 
    666 **/
    667 EFI_STATUS
    668 EFIAPI
    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
    674   )
    675 {
    676   EFI_STATUS                         Status;
    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;
    682   UINTN                              DataLength;
    683   BOOLEAN                            NeedRetry;
    684 
    685   Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
    686   NeedRetry = TRUE;
    687 
    688   if (DeviceIndex >= UFS_PEIM_MAX_LUNS) {
    689     return EFI_INVALID_PARAMETER;
    690   }
    691 
    692   if ((Private->Luns.BitMask & (BIT0 << DeviceIndex)) == 0) {
    693     return EFI_ACCESS_DENIED;
    694   }
    695 
    696   ZeroMem (&SenseData, sizeof (SenseData));
    697   ZeroMem (&Capacity, sizeof (Capacity));
    698   ZeroMem (&Capacity16, sizeof (Capacity16));
    699   SenseDataLength = sizeof (SenseData);
    700   //
    701   // First test unit ready
    702   //
    703   do {
    704     Status = UfsPeimTestUnitReady (
    705                Private,
    706                DeviceIndex,
    707                &SenseData,
    708                &SenseDataLength
    709                );
    710     if (!EFI_ERROR (Status)) {
    711       break;
    712     }
    713 
    714     if (SenseDataLength == 0) {
    715       continue;
    716     }
    717 
    718     Status = UfsPeimParsingSenseKeys (&(Private->Media[DeviceIndex]), &SenseData, &NeedRetry);
    719     if (EFI_ERROR (Status)) {
    720       return EFI_DEVICE_ERROR;
    721     }
    722 
    723   } while (NeedRetry);
    724 
    725   DataLength      = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
    726   SenseDataLength = 0;
    727   Status = UfsPeimReadCapacity (Private, DeviceIndex, &Capacity, (UINT32 *)&DataLength, NULL, &SenseDataLength);
    728   if (EFI_ERROR (Status)) {
    729     return EFI_DEVICE_ERROR;
    730   }
    731 
    732   if ((Capacity.LastLba3 == 0xff) && (Capacity.LastLba2 == 0xff) &&
    733       (Capacity.LastLba1 == 0xff) && (Capacity.LastLba0 == 0xff)) {
    734     DataLength      = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
    735     SenseDataLength = 0;
    736     Status = UfsPeimReadCapacity16 (Private, DeviceIndex, &Capacity16, (UINT32 *)&DataLength, NULL, &SenseDataLength);
    737     if (EFI_ERROR (Status)) {
    738       return EFI_DEVICE_ERROR;
    739     }
    740     Private->Media[DeviceIndex].LastBlock  = (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;
    743   } else {
    744     Private->Media[DeviceIndex].LastBlock  = (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;
    746   }
    747 
    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;
    752 
    753   return EFI_SUCCESS;
    754 }
    755 
    756 /**
    757   Reads the requested number of blocks from the specified block device.
    758 
    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.
    762 
    763   @param[in]  PeiServices   General-purpose services that are available to
    764                             every PEIM.
    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
    773                             on the device
    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
    778                             buffer.
    779 
    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.
    788 
    789 **/
    790 EFI_STATUS
    791 EFIAPI
    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,
    797   IN  UINTN                          BufferSize,
    798   OUT VOID                           *Buffer
    799   )
    800 {
    801   EFI_STATUS                         Status;
    802   UINTN                              BlockSize;
    803   UINTN                              NumberOfBlocks;
    804   UFS_PEIM_HC_PRIVATE_DATA           *Private;
    805   EFI_SCSI_SENSE_DATA                SenseData;
    806   UINT8                              SenseDataLength;
    807   BOOLEAN                            NeedRetry;
    808 
    809   Status    = EFI_SUCCESS;
    810   NeedRetry = TRUE;
    811   Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);
    812 
    813   ZeroMem (&SenseData, sizeof (SenseData));
    814   SenseDataLength = sizeof (SenseData);
    815 
    816   //
    817   // Check parameters
    818   //
    819   if (Buffer == NULL) {
    820     return EFI_INVALID_PARAMETER;
    821   }
    822 
    823   if (BufferSize == 0) {
    824     return EFI_SUCCESS;
    825   }
    826 
    827   if (DeviceIndex >= UFS_PEIM_MAX_LUNS) {
    828     return EFI_INVALID_PARAMETER;
    829   }
    830 
    831   if ((Private->Luns.BitMask & (BIT0 << DeviceIndex)) == 0) {
    832     return EFI_ACCESS_DENIED;
    833   }
    834 
    835   BlockSize = Private->Media[DeviceIndex].BlockSize;
    836 
    837   if (BufferSize % BlockSize != 0) {
    838     Status = EFI_BAD_BUFFER_SIZE;
    839   }
    840 
    841   if (StartLBA > Private->Media[DeviceIndex].LastBlock) {
    842     Status = EFI_INVALID_PARAMETER;
    843   }
    844 
    845   NumberOfBlocks = BufferSize / BlockSize;
    846 
    847   do {
    848     Status = UfsPeimTestUnitReady (
    849                Private,
    850                DeviceIndex,
    851                &SenseData,
    852                &SenseDataLength
    853                );
    854     if (!EFI_ERROR (Status)) {
    855       break;
    856     }
    857 
    858     if (SenseDataLength == 0) {
    859       continue;
    860     }
    861 
    862     Status = UfsPeimParsingSenseKeys (&(Private->Media[DeviceIndex]), &SenseData, &NeedRetry);
    863     if (EFI_ERROR (Status)) {
    864       return EFI_DEVICE_ERROR;
    865     }
    866 
    867   } while (NeedRetry);
    868 
    869   SenseDataLength = 0;
    870   if (Private->Media[DeviceIndex].LastBlock < 0xfffffffful) {
    871     Status = UfsPeimRead10 (
    872                Private,
    873                DeviceIndex,
    874                (UINT32)StartLBA,
    875                (UINT32)NumberOfBlocks,
    876                Buffer,
    877                (UINT32 *)&BufferSize,
    878                NULL,
    879                &SenseDataLength
    880                );
    881   } else {
    882     Status = UfsPeimRead16 (
    883                Private,
    884                DeviceIndex,
    885                (UINT32)StartLBA,
    886                (UINT32)NumberOfBlocks,
    887                Buffer,
    888                (UINT32 *)&BufferSize,
    889                NULL,
    890                &SenseDataLength
    891                );
    892   }
    893   return Status;
    894 }
    895 
    896 /**
    897   Gets the count of block I/O devices that one specific block driver detects.
    898 
    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.
    905 
    906   @param[in]  PeiServices          General-purpose services that are available
    907                                    to every PEIM.
    908   @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
    909                                    instance.
    910   @param[out] NumberBlockDevices   The number of block I/O devices discovered.
    911 
    912   @retval     EFI_SUCCESS          The operation performed successfully.
    913 
    914 **/
    915 EFI_STATUS
    916 EFIAPI
    917 UfsBlockIoPeimGetDeviceNo2 (
    918   IN  EFI_PEI_SERVICES               **PeiServices,
    919   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
    920   OUT UINTN                          *NumberBlockDevices
    921   )
    922 {
    923   //
    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.
    927   //
    928   *NumberBlockDevices = UFS_PEIM_MAX_LUNS;
    929   return EFI_SUCCESS;
    930 }
    931 
    932 /**
    933   Gets a block device's media information.
    934 
    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.
    938 
    939   @param[in]  PeiServices   General-purpose services that are available to every
    940                             PEIM
    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
    948                             NumberBlockDevices.
    949   @param[out] MediaInfo     The media information of the specified block media.
    950                             The caller is responsible for the ownership of this
    951                             data structure.
    952 
    953   @par Note:
    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.
    966 
    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
    970                              error.
    971 
    972 **/
    973 EFI_STATUS
    974 EFIAPI
    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
    980   )
    981 {
    982   EFI_STATUS                         Status;
    983   UFS_PEIM_HC_PRIVATE_DATA           *Private;
    984   EFI_PEI_BLOCK_IO_MEDIA             Media;
    985 
    986   Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
    987 
    988   Status    = UfsBlockIoPeimGetMediaInfo (
    989                 PeiServices,
    990                 &Private->BlkIoPpi,
    991                 DeviceIndex,
    992                 &Media
    993                 );
    994   if (EFI_ERROR (Status)) {
    995     return Status;
    996   }
    997 
    998   CopyMem (MediaInfo, &(Private->Media[DeviceIndex]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));
    999   return EFI_SUCCESS;
   1000 }
   1001 
   1002 /**
   1003   Reads the requested number of blocks from the specified block device.
   1004 
   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.
   1008 
   1009   @param[in]  PeiServices   General-purpose services that are available to
   1010                             every PEIM.
   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
   1019                             on the device
   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
   1024                             buffer.
   1025 
   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.
   1034 
   1035 **/
   1036 EFI_STATUS
   1037 EFIAPI
   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,
   1044   OUT VOID                           *Buffer
   1045   )
   1046 {
   1047   EFI_STATUS                         Status;
   1048   UFS_PEIM_HC_PRIVATE_DATA           *Private;
   1049 
   1050   Status    = EFI_SUCCESS;
   1051   Private   = GET_UFS_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);
   1052 
   1053   Status  = UfsBlockIoPeimReadBlocks (
   1054               PeiServices,
   1055               &Private->BlkIoPpi,
   1056               DeviceIndex,
   1057               StartLBA,
   1058               BufferSize,
   1059               Buffer
   1060               );
   1061   return Status;
   1062 }
   1063 
   1064 /**
   1065   The user code starts with this function.
   1066 
   1067   @param  FileHandle             Handle of the file being invoked.
   1068   @param  PeiServices            Describes the list of possible PEI Services.
   1069 
   1070   @retval EFI_SUCCESS            The driver is successfully initialized.
   1071   @retval Others                 Can't initialize the driver.
   1072 
   1073 **/
   1074 EFI_STATUS
   1075 EFIAPI
   1076 InitializeUfsBlockIoPeim (
   1077   IN EFI_PEI_FILE_HANDLE        FileHandle,
   1078   IN CONST EFI_PEI_SERVICES     **PeiServices
   1079   )
   1080 {
   1081   EFI_STATUS                    Status;
   1082   UFS_PEIM_HC_PRIVATE_DATA      *Private;
   1083   EDKII_UFS_HOST_CONTROLLER_PPI *UfsHcPpi;
   1084   UINT32                        Index;
   1085   UFS_CONFIG_DESC               Config;
   1086   UINTN                         MmioBase;
   1087   UINT8                         Controller;
   1088 
   1089   //
   1090   // Shadow this PEIM to run from memory
   1091   //
   1092   if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
   1093     return EFI_SUCCESS;
   1094   }
   1095 
   1096   //
   1097   // locate ufs host controller PPI
   1098   //
   1099   Status = PeiServicesLocatePpi (
   1100              &gEdkiiPeiUfsHostControllerPpiGuid,
   1101              0,
   1102              NULL,
   1103              (VOID **) &UfsHcPpi
   1104              );
   1105   if (EFI_ERROR (Status)) {
   1106     return EFI_DEVICE_ERROR;
   1107   }
   1108 
   1109   Controller = 0;
   1110   MmioBase   = 0;
   1111   while (TRUE) {
   1112     Status = UfsHcPpi->GetUfsHcMmioBar (UfsHcPpi, Controller, &MmioBase);
   1113     //
   1114     // When status is error, meant no controller is found
   1115     //
   1116     if (EFI_ERROR (Status)) {
   1117       break;
   1118     }
   1119 
   1120     Private = AllocateCopyPool (sizeof (UFS_PEIM_HC_PRIVATE_DATA), &gUfsHcPeimTemplate);
   1121     if (Private == NULL) {
   1122       Status = EFI_OUT_OF_RESOURCES;
   1123       break;
   1124     }
   1125 
   1126     Private->BlkIoPpiList.Ppi  = &Private->BlkIoPpi;
   1127     Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;
   1128     Private->UfsHcBase         = MmioBase;
   1129 
   1130     //
   1131     // Initialize the memory pool which will be used in all transactions.
   1132     //
   1133     Status = UfsPeimInitMemPool (Private);
   1134     if (EFI_ERROR (Status)) {
   1135       Status = EFI_OUT_OF_RESOURCES;
   1136       break;
   1137     }
   1138 
   1139     //
   1140     // Initialize UFS Host Controller H/W.
   1141     //
   1142     Status = UfsControllerInit (Private);
   1143     if (EFI_ERROR (Status)) {
   1144       DEBUG ((EFI_D_ERROR, "UfsDevicePei: Host Controller Initialization Error, Status = %r\n", Status));
   1145       Controller++;
   1146       continue;
   1147     }
   1148 
   1149     //
   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.
   1153     //
   1154     Status = UfsExecNopCmds (Private);
   1155     if (EFI_ERROR (Status)) {
   1156       DEBUG ((EFI_D_ERROR, "Ufs Sending NOP IN command Error, Status = %r\n", Status));
   1157       Controller++;
   1158       continue;
   1159     }
   1160 
   1161     //
   1162     // The host enables the device initialization completion by setting fDeviceInit flag.
   1163     //
   1164     Status = UfsSetFlag (Private, UfsFlagDevInit);
   1165     if (EFI_ERROR (Status)) {
   1166       DEBUG ((EFI_D_ERROR, "Ufs Set fDeviceInit Flag Error, Status = %r\n", Status));
   1167       Controller++;
   1168       continue;
   1169     }
   1170 
   1171     //
   1172     // Get Ufs Device's Lun Info by reading Configuration Descriptor.
   1173     //
   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));
   1177       Controller++;
   1178       continue;
   1179     }
   1180 
   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));
   1185       }
   1186     }
   1187 
   1188     Status = PeiServicesInstallPpi (&Private->BlkIoPpiList);
   1189     Controller++;
   1190   }
   1191 
   1192   return EFI_SUCCESS;
   1193 }
   1194