Home | History | Annotate | Download | only in UsbBotPei
      1 /** @file
      2 
      3 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      4 
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions
      7 of the BSD License which accompanies this distribution.  The
      8 full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "UsbBotPeim.h"
     17 #include "BotPeim.h"
     18 
     19 //
     20 // Global function
     21 //
     22 EFI_PEI_NOTIFY_DESCRIPTOR        mNotifyList = {
     23   EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
     24   &gPeiUsbIoPpiGuid,
     25   NotifyOnUsbIoPpi
     26 };
     27 
     28 EFI_PEI_RECOVERY_BLOCK_IO_PPI    mRecoveryBlkIoPpi = {
     29   BotGetNumberOfBlockDevices,
     30   BotGetMediaInfo,
     31   BotReadBlocks
     32 };
     33 
     34 EFI_PEI_RECOVERY_BLOCK_IO2_PPI   mRecoveryBlkIo2Ppi = {
     35   EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,
     36   BotGetNumberOfBlockDevices2,
     37   BotGetMediaInfo2,
     38   BotReadBlocks2
     39 };
     40 
     41 EFI_PEI_PPI_DESCRIPTOR           mPpiList[2] = {
     42   {
     43     EFI_PEI_PPI_DESCRIPTOR_PPI,
     44     &gEfiPeiVirtualBlockIoPpiGuid,
     45     NULL
     46   },
     47   {
     48     EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
     49     &gEfiPeiVirtualBlockIo2PpiGuid,
     50     NULL
     51   }
     52 };
     53 
     54 /**
     55   Detect whether the removable media is present and whether it has changed.
     56 
     57   @param[in]  PeiServices   General-purpose services that are available to every
     58                             PEIM.
     59   @param[in]  PeiBotDev     Indicates the PEI_BOT_DEVICE instance.
     60 
     61   @retval EFI_SUCCESS       The media status is successfully checked.
     62   @retval Other             Failed to detect media.
     63 
     64 **/
     65 EFI_STATUS
     66 PeiBotDetectMedia (
     67   IN  EFI_PEI_SERVICES                          **PeiServices,
     68   IN  PEI_BOT_DEVICE                            *PeiBotDev
     69   );
     70 
     71 /**
     72   Initializes the Usb Bot.
     73 
     74   @param  FileHandle  Handle of the file being invoked.
     75   @param  PeiServices Describes the list of possible PEI Services.
     76 
     77   @retval EFI_SUCCESS            Usb bot driver is successfully initialized.
     78   @retval EFI_OUT_OF_RESOURCES   Can't initialize the driver.
     79 
     80 **/
     81 EFI_STATUS
     82 EFIAPI
     83 PeimInitializeUsbBot (
     84   IN EFI_PEI_FILE_HANDLE       FileHandle,
     85   IN CONST EFI_PEI_SERVICES    **PeiServices
     86   )
     87 {
     88   EFI_STATUS                  Status;
     89   UINTN                       UsbIoPpiInstance;
     90   EFI_PEI_PPI_DESCRIPTOR      *TempPpiDescriptor;
     91   PEI_USB_IO_PPI              *UsbIoPpi;
     92 
     93   //
     94   // Shadow this PEIM to run from memory
     95   //
     96   if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
     97     return EFI_SUCCESS;
     98   }
     99 
    100   //
    101   // locate all usb io PPIs
    102   //
    103   for (UsbIoPpiInstance = 0; UsbIoPpiInstance < PEI_FAT_MAX_USB_IO_PPI; UsbIoPpiInstance++) {
    104 
    105     Status = PeiServicesLocatePpi (
    106                               &gPeiUsbIoPpiGuid,
    107                               UsbIoPpiInstance,
    108                               &TempPpiDescriptor,
    109                               (VOID **) &UsbIoPpi
    110                               );
    111     if (EFI_ERROR (Status)) {
    112       break;
    113     }
    114   }
    115   //
    116   // Register a notify function
    117   //
    118   return PeiServicesNotifyPpi (&mNotifyList);
    119 }
    120 
    121 /**
    122   UsbIo installation notification function.
    123 
    124   This function finds out all the current USB IO PPIs in the system and add them
    125   into private data.
    126 
    127   @param  PeiServices      Indirect reference to the PEI Services Table.
    128   @param  NotifyDesc       Address of the notification descriptor data structure.
    129   @param  InvokePpi        Address of the PPI that was invoked.
    130 
    131   @retval EFI_SUCCESS      The function completes successfully.
    132 
    133 **/
    134 EFI_STATUS
    135 EFIAPI
    136 NotifyOnUsbIoPpi (
    137   IN  EFI_PEI_SERVICES                              **PeiServices,
    138   IN  EFI_PEI_NOTIFY_DESCRIPTOR                     *NotifyDesc,
    139   IN  VOID                                          *InvokePpi
    140   )
    141 {
    142   PEI_USB_IO_PPI  *UsbIoPpi;
    143 
    144   UsbIoPpi = (PEI_USB_IO_PPI *) InvokePpi;
    145 
    146   InitUsbBot (PeiServices, UsbIoPpi);
    147 
    148   return EFI_SUCCESS;
    149 }
    150 
    151 /**
    152   Initialize the usb bot device.
    153 
    154   @param[in]  PeiServices   General-purpose services that are available to every
    155                             PEIM.
    156   @param[in]  UsbIoPpi      Indicates the PEI_USB_IO_PPI instance.
    157 
    158   @retval EFI_SUCCESS       The usb bot device is initialized successfully.
    159   @retval Other             Failed to initialize media.
    160 
    161 **/
    162 EFI_STATUS
    163 InitUsbBot (
    164   IN  EFI_PEI_SERVICES                          **PeiServices,
    165   IN  PEI_USB_IO_PPI                            *UsbIoPpi
    166   )
    167 {
    168   PEI_BOT_DEVICE                *PeiBotDevice;
    169   EFI_STATUS                    Status;
    170   EFI_USB_INTERFACE_DESCRIPTOR  *InterfaceDesc;
    171   UINTN                         MemPages;
    172   EFI_PHYSICAL_ADDRESS          AllocateAddress;
    173   EFI_USB_ENDPOINT_DESCRIPTOR   *EndpointDesc;
    174   UINT8                         Index;
    175 
    176   //
    177   // Check its interface
    178   //
    179   Status = UsbIoPpi->UsbGetInterfaceDescriptor (
    180                       PeiServices,
    181                       UsbIoPpi,
    182                       &InterfaceDesc
    183                       );
    184   if (EFI_ERROR (Status)) {
    185     return Status;
    186   }
    187   //
    188   // Check if it is the BOT device we support
    189   //
    190   if ((InterfaceDesc->InterfaceClass != 0x08) || (InterfaceDesc->InterfaceProtocol != 0x50)) {
    191 
    192     return EFI_NOT_FOUND;
    193   }
    194 
    195   MemPages = sizeof (PEI_BOT_DEVICE) / EFI_PAGE_SIZE + 1;
    196   Status = PeiServicesAllocatePages (
    197              EfiBootServicesCode,
    198              MemPages,
    199              &AllocateAddress
    200              );
    201   if (EFI_ERROR (Status)) {
    202     return Status;
    203   }
    204 
    205   PeiBotDevice                  = (PEI_BOT_DEVICE *) ((UINTN) AllocateAddress);
    206 
    207   PeiBotDevice->Signature       = PEI_BOT_DEVICE_SIGNATURE;
    208   PeiBotDevice->UsbIoPpi        = UsbIoPpi;
    209   PeiBotDevice->AllocateAddress = (UINTN) AllocateAddress;
    210   PeiBotDevice->BotInterface    = InterfaceDesc;
    211 
    212   //
    213   // Default value
    214   //
    215   PeiBotDevice->Media.DeviceType  = UsbMassStorage;
    216   PeiBotDevice->Media.BlockSize   = 0x200;
    217   PeiBotDevice->Media2.InterfaceType = MSG_USB_DP;
    218   PeiBotDevice->Media2.BlockSize     = 0x200;
    219   PeiBotDevice->Media2.RemovableMedia = FALSE;
    220   PeiBotDevice->Media2.ReadOnly       = FALSE;
    221 
    222   //
    223   // Check its Bulk-in/Bulk-out endpoint
    224   //
    225   for (Index = 0; Index < 2; Index++) {
    226     Status = UsbIoPpi->UsbGetEndpointDescriptor (
    227                         PeiServices,
    228                         UsbIoPpi,
    229                         Index,
    230                         &EndpointDesc
    231                         );
    232 
    233     if (EFI_ERROR (Status)) {
    234       return Status;
    235     }
    236 
    237     if ((EndpointDesc->EndpointAddress & 0x80) != 0) {
    238       PeiBotDevice->BulkInEndpoint = EndpointDesc;
    239     } else {
    240       PeiBotDevice->BulkOutEndpoint = EndpointDesc;
    241     }
    242   }
    243 
    244   CopyMem (
    245     &(PeiBotDevice->BlkIoPpi),
    246     &mRecoveryBlkIoPpi,
    247     sizeof (EFI_PEI_RECOVERY_BLOCK_IO_PPI)
    248     );
    249   CopyMem (
    250     &(PeiBotDevice->BlkIo2Ppi),
    251     &mRecoveryBlkIo2Ppi,
    252     sizeof (EFI_PEI_RECOVERY_BLOCK_IO2_PPI)
    253     );
    254   CopyMem (
    255     &(PeiBotDevice->BlkIoPpiList),
    256     &mPpiList[0],
    257     sizeof (EFI_PEI_PPI_DESCRIPTOR)
    258     );
    259   CopyMem (
    260     &(PeiBotDevice->BlkIo2PpiList),
    261     &mPpiList[1],
    262     sizeof (EFI_PEI_PPI_DESCRIPTOR)
    263     );
    264   PeiBotDevice->BlkIoPpiList.Ppi  = &PeiBotDevice->BlkIoPpi;
    265   PeiBotDevice->BlkIo2PpiList.Ppi = &PeiBotDevice->BlkIo2Ppi;
    266 
    267   Status                          = PeiUsbInquiry (PeiServices, PeiBotDevice);
    268   if (EFI_ERROR (Status)) {
    269     return Status;
    270   }
    271 
    272   Status = PeiServicesAllocatePages (
    273              EfiBootServicesCode,
    274              1,
    275              &AllocateAddress
    276              );
    277   if (EFI_ERROR (Status)) {
    278     return Status;
    279   }
    280 
    281   PeiBotDevice->SensePtr = (ATAPI_REQUEST_SENSE_DATA *) ((UINTN) AllocateAddress);
    282 
    283   Status = PeiServicesInstallPpi (&PeiBotDevice->BlkIoPpiList);
    284 
    285   if (EFI_ERROR (Status)) {
    286     return Status;
    287   }
    288 
    289   return EFI_SUCCESS;
    290 }
    291 
    292 /**
    293   Gets the count of block I/O devices that one specific block driver detects.
    294 
    295   This function is used for getting the count of block I/O devices that one
    296   specific block driver detects.  To the PEI ATAPI driver, it returns the number
    297   of all the detected ATAPI devices it detects during the enumeration process.
    298   To the PEI legacy floppy driver, it returns the number of all the legacy
    299   devices it finds during its enumeration process. If no device is detected,
    300   then the function will return zero.
    301 
    302   @param[in]  PeiServices          General-purpose services that are available
    303                                    to every PEIM.
    304   @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
    305                                    instance.
    306   @param[out] NumberBlockDevices   The number of block I/O devices discovered.
    307 
    308   @retval     EFI_SUCCESS          Operation performed successfully.
    309 
    310 **/
    311 EFI_STATUS
    312 EFIAPI
    313 BotGetNumberOfBlockDevices (
    314   IN  EFI_PEI_SERVICES                         **PeiServices,
    315   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI            *This,
    316   OUT UINTN                                    *NumberBlockDevices
    317   )
    318 {
    319   //
    320   // For Usb devices, this value should be always 1
    321   //
    322   *NumberBlockDevices = 1;
    323   return EFI_SUCCESS;
    324 }
    325 
    326 /**
    327   Gets a block device's media information.
    328 
    329   This function will provide the caller with the specified block device's media
    330   information. If the media changes, calling this function will update the media
    331   information accordingly.
    332 
    333   @param[in]  PeiServices   General-purpose services that are available to every
    334                             PEIM
    335   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
    336   @param[in]  DeviceIndex   Specifies the block device to which the function wants
    337                             to talk. Because the driver that implements Block I/O
    338                             PPIs will manage multiple block devices, the PPIs that
    339                             want to talk to a single device must specify the
    340                             device index that was assigned during the enumeration
    341                             process. This index is a number from one to
    342                             NumberBlockDevices.
    343   @param[out] MediaInfo     The media information of the specified block media.
    344                             The caller is responsible for the ownership of this
    345                             data structure.
    346 
    347   @retval EFI_SUCCESS        Media information about the specified block device
    348                              was obtained successfully.
    349   @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware
    350                              error.
    351 
    352 **/
    353 EFI_STATUS
    354 EFIAPI
    355 BotGetMediaInfo (
    356   IN  EFI_PEI_SERVICES                          **PeiServices,
    357   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI             *This,
    358   IN  UINTN                                     DeviceIndex,
    359   OUT EFI_PEI_BLOCK_IO_MEDIA                    *MediaInfo
    360   )
    361 {
    362   PEI_BOT_DEVICE  *PeiBotDev;
    363   EFI_STATUS      Status;
    364 
    365   PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This);
    366 
    367   //
    368   // First test unit ready
    369   //
    370   PeiUsbTestUnitReady (
    371     PeiServices,
    372     PeiBotDev
    373     );
    374 
    375   Status = PeiBotDetectMedia (
    376             PeiServices,
    377             PeiBotDev
    378             );
    379 
    380   if (EFI_ERROR (Status)) {
    381     return EFI_DEVICE_ERROR;
    382   }
    383 
    384   CopyMem (
    385     MediaInfo,
    386     &(PeiBotDev->Media),
    387     sizeof (EFI_PEI_BLOCK_IO_MEDIA)
    388     );
    389 
    390   return EFI_SUCCESS;
    391 }
    392 
    393 /**
    394   Reads the requested number of blocks from the specified block device.
    395 
    396   The function reads the requested number of blocks from the device. All the
    397   blocks are read, or an error is returned. If there is no media in the device,
    398   the function returns EFI_NO_MEDIA.
    399 
    400   @param[in]  PeiServices   General-purpose services that are available to
    401                             every PEIM.
    402   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
    403   @param[in]  DeviceIndex   Specifies the block device to which the function wants
    404                             to talk. Because the driver that implements Block I/O
    405                             PPIs will manage multiple block devices, the PPIs that
    406                             want to talk to a single device must specify the device
    407                             index that was assigned during the enumeration process.
    408                             This index is a number from one to NumberBlockDevices.
    409   @param[in]  StartLBA      The starting logical block address (LBA) to read from
    410                             on the device
    411   @param[in]  BufferSize    The size of the Buffer in bytes. This number must be
    412                             a multiple of the intrinsic block size of the device.
    413   @param[out] Buffer        A pointer to the destination buffer for the data.
    414                             The caller is responsible for the ownership of the
    415                             buffer.
    416 
    417   @retval EFI_SUCCESS             The data was read correctly from the device.
    418   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
    419                                   to perform the read operation.
    420   @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not
    421                                   valid, or the buffer is not properly aligned.
    422   @retval EFI_NO_MEDIA            There is no media in the device.
    423   @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
    424                                   the intrinsic block size of the device.
    425 
    426 **/
    427 EFI_STATUS
    428 EFIAPI
    429 BotReadBlocks (
    430   IN  EFI_PEI_SERVICES                          **PeiServices,
    431   IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI             *This,
    432   IN  UINTN                                     DeviceIndex,
    433   IN  EFI_PEI_LBA                               StartLBA,
    434   IN  UINTN                                     BufferSize,
    435   OUT VOID                                      *Buffer
    436   )
    437 {
    438   PEI_BOT_DEVICE  *PeiBotDev;
    439   EFI_STATUS      Status;
    440   UINTN           BlockSize;
    441   UINTN           NumberOfBlocks;
    442 
    443   Status    = EFI_SUCCESS;
    444   PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This);
    445 
    446   //
    447   // Check parameters
    448   //
    449   if (Buffer == NULL) {
    450     return EFI_INVALID_PARAMETER;
    451   }
    452 
    453   if (BufferSize == 0) {
    454     return EFI_SUCCESS;
    455   }
    456 
    457   if (!PeiBotDev->Media.MediaPresent) {
    458     return EFI_NO_MEDIA;
    459   }
    460 
    461   BlockSize = PeiBotDev->Media.BlockSize;
    462 
    463   if (BufferSize % BlockSize != 0) {
    464     Status = EFI_BAD_BUFFER_SIZE;
    465   }
    466 
    467   if (StartLBA > PeiBotDev->Media2.LastBlock) {
    468     Status = EFI_INVALID_PARAMETER;
    469   }
    470 
    471   NumberOfBlocks = BufferSize / (PeiBotDev->Media.BlockSize);
    472 
    473   if (Status == EFI_SUCCESS) {
    474 
    475     Status = PeiUsbTestUnitReady (
    476               PeiServices,
    477               PeiBotDev
    478               );
    479     if (Status == EFI_SUCCESS) {
    480       Status = PeiUsbRead10 (
    481                 PeiServices,
    482                 PeiBotDev,
    483                 Buffer,
    484                 StartLBA,
    485                 1
    486                 );
    487     }
    488   } else {
    489     //
    490     // To generate sense data for DetectMedia use.
    491     //
    492     PeiUsbTestUnitReady (
    493       PeiServices,
    494       PeiBotDev
    495       );
    496   }
    497 
    498   if (EFI_ERROR (Status)) {
    499     //
    500     // if any error encountered, detect what happened to the media and
    501     // update the media info accordingly.
    502     //
    503     Status = PeiBotDetectMedia (
    504               PeiServices,
    505               PeiBotDev
    506               );
    507     if (Status != EFI_SUCCESS) {
    508       return EFI_DEVICE_ERROR;
    509     }
    510 
    511     NumberOfBlocks = BufferSize / PeiBotDev->Media.BlockSize;
    512 
    513     if (!(PeiBotDev->Media.MediaPresent)) {
    514       return EFI_NO_MEDIA;
    515     }
    516 
    517     if (BufferSize % (PeiBotDev->Media.BlockSize) != 0) {
    518       return EFI_BAD_BUFFER_SIZE;
    519     }
    520 
    521     if (StartLBA > PeiBotDev->Media2.LastBlock) {
    522       return EFI_INVALID_PARAMETER;
    523     }
    524 
    525     if ((StartLBA + NumberOfBlocks - 1) > PeiBotDev->Media2.LastBlock) {
    526       return EFI_INVALID_PARAMETER;
    527     }
    528 
    529     Status = PeiUsbRead10 (
    530               PeiServices,
    531               PeiBotDev,
    532               Buffer,
    533               StartLBA,
    534               NumberOfBlocks
    535               );
    536 
    537     switch (Status) {
    538 
    539     case EFI_SUCCESS:
    540       return EFI_SUCCESS;
    541 
    542     default:
    543       return EFI_DEVICE_ERROR;
    544     }
    545   } else {
    546     StartLBA += 1;
    547     NumberOfBlocks -= 1;
    548     Buffer = (UINT8 *) Buffer + PeiBotDev->Media.BlockSize;
    549 
    550     if (NumberOfBlocks == 0) {
    551       return EFI_SUCCESS;
    552     }
    553 
    554     Status = PeiUsbRead10 (
    555               PeiServices,
    556               PeiBotDev,
    557               Buffer,
    558               StartLBA,
    559               NumberOfBlocks
    560               );
    561     switch (Status) {
    562 
    563     case EFI_SUCCESS:
    564       return EFI_SUCCESS;
    565 
    566     default:
    567       return EFI_DEVICE_ERROR;
    568 
    569     }
    570   }
    571 }
    572 
    573 /**
    574   Gets the count of block I/O devices that one specific block driver detects.
    575 
    576   This function is used for getting the count of block I/O devices that one
    577   specific block driver detects.  To the PEI ATAPI driver, it returns the number
    578   of all the detected ATAPI devices it detects during the enumeration process.
    579   To the PEI legacy floppy driver, it returns the number of all the legacy
    580   devices it finds during its enumeration process. If no device is detected,
    581   then the function will return zero.
    582 
    583   @param[in]  PeiServices          General-purpose services that are available
    584                                    to every PEIM.
    585   @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
    586                                    instance.
    587   @param[out] NumberBlockDevices   The number of block I/O devices discovered.
    588 
    589   @retval     EFI_SUCCESS          Operation performed successfully.
    590 
    591 **/
    592 EFI_STATUS
    593 EFIAPI
    594 BotGetNumberOfBlockDevices2 (
    595   IN  EFI_PEI_SERVICES                         **PeiServices,
    596   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI           *This,
    597   OUT UINTN                                    *NumberBlockDevices
    598   )
    599 {
    600   //
    601   // For Usb devices, this value should be always 1
    602   //
    603   *NumberBlockDevices = 1;
    604   return EFI_SUCCESS;
    605 }
    606 
    607 /**
    608   Gets a block device's media information.
    609 
    610   This function will provide the caller with the specified block device's media
    611   information. If the media changes, calling this function will update the media
    612   information accordingly.
    613 
    614   @param[in]  PeiServices   General-purpose services that are available to every
    615                             PEIM
    616   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
    617   @param[in]  DeviceIndex   Specifies the block device to which the function wants
    618                             to talk. Because the driver that implements Block I/O
    619                             PPIs will manage multiple block devices, the PPIs that
    620                             want to talk to a single device must specify the
    621                             device index that was assigned during the enumeration
    622                             process. This index is a number from one to
    623                             NumberBlockDevices.
    624   @param[out] MediaInfo     The media information of the specified block media.
    625                             The caller is responsible for the ownership of this
    626                             data structure.
    627 
    628   @retval EFI_SUCCESS        Media information about the specified block device
    629                              was obtained successfully.
    630   @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware
    631                              error.
    632 
    633 **/
    634 EFI_STATUS
    635 EFIAPI
    636 BotGetMediaInfo2 (
    637   IN  EFI_PEI_SERVICES                          **PeiServices,
    638   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI            *This,
    639   IN  UINTN                                     DeviceIndex,
    640   OUT EFI_PEI_BLOCK_IO2_MEDIA                   *MediaInfo
    641   )
    642 {
    643   PEI_BOT_DEVICE  *PeiBotDev;
    644   EFI_STATUS      Status;
    645 
    646   PeiBotDev = PEI_BOT_DEVICE2_FROM_THIS (This);
    647 
    648   Status = BotGetMediaInfo (
    649              PeiServices,
    650              &PeiBotDev->BlkIoPpi,
    651              DeviceIndex,
    652              &PeiBotDev->Media
    653              );
    654 
    655   if (EFI_ERROR (Status)) {
    656     return Status;
    657   }
    658 
    659   CopyMem (
    660     MediaInfo,
    661     &(PeiBotDev->Media2),
    662     sizeof (EFI_PEI_BLOCK_IO2_MEDIA)
    663     );
    664 
    665   return EFI_SUCCESS;
    666 }
    667 
    668 /**
    669   Reads the requested number of blocks from the specified block device.
    670 
    671   The function reads the requested number of blocks from the device. All the
    672   blocks are read, or an error is returned. If there is no media in the device,
    673   the function returns EFI_NO_MEDIA.
    674 
    675   @param[in]  PeiServices   General-purpose services that are available to
    676                             every PEIM.
    677   @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
    678   @param[in]  DeviceIndex   Specifies the block device to which the function wants
    679                             to talk. Because the driver that implements Block I/O
    680                             PPIs will manage multiple block devices, the PPIs that
    681                             want to talk to a single device must specify the device
    682                             index that was assigned during the enumeration process.
    683                             This index is a number from one to NumberBlockDevices.
    684   @param[in]  StartLBA      The starting logical block address (LBA) to read from
    685                             on the device
    686   @param[in]  BufferSize    The size of the Buffer in bytes. This number must be
    687                             a multiple of the intrinsic block size of the device.
    688   @param[out] Buffer        A pointer to the destination buffer for the data.
    689                             The caller is responsible for the ownership of the
    690                             buffer.
    691 
    692   @retval EFI_SUCCESS             The data was read correctly from the device.
    693   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
    694                                   to perform the read operation.
    695   @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not
    696                                   valid, or the buffer is not properly aligned.
    697   @retval EFI_NO_MEDIA            There is no media in the device.
    698   @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
    699                                   the intrinsic block size of the device.
    700 
    701 **/
    702 EFI_STATUS
    703 EFIAPI
    704 BotReadBlocks2 (
    705   IN  EFI_PEI_SERVICES                          **PeiServices,
    706   IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI            *This,
    707   IN  UINTN                                     DeviceIndex,
    708   IN  EFI_PEI_LBA                               StartLBA,
    709   IN  UINTN                                     BufferSize,
    710   OUT VOID                                      *Buffer
    711   )
    712 {
    713   PEI_BOT_DEVICE  *PeiBotDev;
    714   EFI_STATUS      Status;
    715 
    716   if (This == NULL) {
    717     return EFI_INVALID_PARAMETER;
    718   }
    719 
    720   Status    = EFI_SUCCESS;
    721   PeiBotDev = PEI_BOT_DEVICE2_FROM_THIS (This);
    722 
    723   Status = BotReadBlocks (
    724              PeiServices,
    725              &PeiBotDev->BlkIoPpi,
    726              DeviceIndex,
    727              StartLBA,
    728              BufferSize,
    729              Buffer
    730              );
    731 
    732   return Status;
    733 }
    734 
    735 /**
    736   Detect whether the removable media is present and whether it has changed.
    737 
    738   @param[in]  PeiServices   General-purpose services that are available to every
    739                             PEIM.
    740   @param[in]  PeiBotDev     Indicates the PEI_BOT_DEVICE instance.
    741 
    742   @retval EFI_SUCCESS       The media status is successfully checked.
    743   @retval Other             Failed to detect media.
    744 
    745 **/
    746 EFI_STATUS
    747 PeiBotDetectMedia (
    748   IN  EFI_PEI_SERVICES        **PeiServices,
    749   IN  PEI_BOT_DEVICE          *PeiBotDev
    750   )
    751 {
    752   EFI_STATUS                  Status;
    753   EFI_STATUS                  FloppyStatus;
    754   UINTN                       SenseCounts;
    755   BOOLEAN                     NeedReadCapacity;
    756   EFI_PHYSICAL_ADDRESS        AllocateAddress;
    757   ATAPI_REQUEST_SENSE_DATA    *SensePtr;
    758   UINTN                       Retry;
    759 
    760   //
    761   // if there is no media present,or media not changed,
    762   // the request sense command will detect faster than read capacity command.
    763   // read capacity command can be bypassed, thus improve performance.
    764   //
    765   SenseCounts       = 0;
    766   NeedReadCapacity  = TRUE;
    767 
    768   Status = PeiServicesAllocatePages (
    769              EfiBootServicesCode,
    770              1,
    771              &AllocateAddress
    772              );
    773   if (EFI_ERROR (Status)) {
    774     return Status;
    775   }
    776 
    777   SensePtr = PeiBotDev->SensePtr;
    778   ZeroMem (SensePtr, EFI_PAGE_SIZE);
    779 
    780   Status = PeiUsbRequestSense (
    781             PeiServices,
    782             PeiBotDev,
    783             &SenseCounts,
    784             (UINT8 *) SensePtr
    785             );
    786 
    787   if (Status == EFI_SUCCESS) {
    788     //
    789     // No Media
    790     //
    791     if (IsNoMedia (SensePtr, SenseCounts)) {
    792       NeedReadCapacity              = FALSE;
    793       PeiBotDev->Media.MediaPresent = FALSE;
    794       PeiBotDev->Media.LastBlock    = 0;
    795       PeiBotDev->Media2.MediaPresent = FALSE;
    796       PeiBotDev->Media2.LastBlock    = 0;
    797     } else {
    798       //
    799       // Media Changed
    800       //
    801       if (IsMediaChange (SensePtr, SenseCounts)) {
    802         PeiBotDev->Media.MediaPresent  = TRUE;
    803         PeiBotDev->Media2.MediaPresent = TRUE;
    804       }
    805       //
    806       // Media Error
    807       //
    808       if (IsMediaError (SensePtr, SenseCounts)) {
    809         //
    810         // if media error encountered, make it look like no media present.
    811         //
    812         PeiBotDev->Media.MediaPresent = FALSE;
    813         PeiBotDev->Media.LastBlock    = 0;
    814         PeiBotDev->Media2.MediaPresent = FALSE;
    815         PeiBotDev->Media2.LastBlock    = 0;
    816       }
    817 
    818     }
    819 
    820   }
    821 
    822   if (NeedReadCapacity) {
    823     //
    824     // Retry at most 4 times to detect media info
    825     //
    826     for (Retry = 0; Retry < 4; Retry++) {
    827       switch (PeiBotDev->DeviceType) {
    828       case USBCDROM:
    829         Status = PeiUsbReadCapacity (
    830                   PeiServices,
    831                   PeiBotDev
    832                   );
    833         break;
    834 
    835       case USBFLOPPY2:
    836         Status = PeiUsbReadFormattedCapacity (
    837                   PeiServices,
    838                   PeiBotDev
    839                   );
    840           if (EFI_ERROR(Status)||
    841               !PeiBotDev->Media.MediaPresent) {
    842           //
    843           // retry the ReadCapacity command
    844           //
    845           PeiBotDev->DeviceType = USBFLOPPY;
    846           Status = EFI_DEVICE_ERROR;
    847         }
    848         break;
    849 
    850       case USBFLOPPY:
    851         Status = PeiUsbReadCapacity (
    852                   PeiServices,
    853                   PeiBotDev
    854                   );
    855         if (EFI_ERROR (Status)) {
    856           //
    857           // retry the ReadFormatCapacity command
    858           //
    859           PeiBotDev->DeviceType = USBFLOPPY2;
    860         }
    861         break;
    862 
    863       default:
    864         return EFI_INVALID_PARAMETER;
    865       }
    866 
    867       SenseCounts = 0;
    868       ZeroMem (SensePtr, EFI_PAGE_SIZE);
    869 
    870       if (Status == EFI_SUCCESS) {
    871         break;
    872       }
    873 
    874       FloppyStatus = PeiUsbRequestSense (
    875                       PeiServices,
    876                       PeiBotDev,
    877                       &SenseCounts,
    878                       (UINT8 *) SensePtr
    879                       );
    880 
    881       //
    882       // If Request Sense data failed,retry.
    883       //
    884       if (EFI_ERROR (FloppyStatus)) {
    885         continue;
    886       }
    887       //
    888       // No Media
    889       //
    890       if (IsNoMedia (SensePtr, SenseCounts)) {
    891         PeiBotDev->Media.MediaPresent = FALSE;
    892         PeiBotDev->Media.LastBlock    = 0;
    893         PeiBotDev->Media2.MediaPresent = FALSE;
    894         PeiBotDev->Media2.LastBlock    = 0;
    895         break;
    896       }
    897 
    898       if (IsMediaError (SensePtr, SenseCounts)) {
    899         //
    900         // if media error encountered, make it look like no media present.
    901         //
    902         PeiBotDev->Media.MediaPresent = FALSE;
    903         PeiBotDev->Media.LastBlock    = 0;
    904         PeiBotDev->Media2.MediaPresent = FALSE;
    905         PeiBotDev->Media2.LastBlock    = 0;
    906         break;
    907       }
    908     }
    909     //
    910     // ENDFOR
    911     //
    912     // tell whether the readcapacity process is successful or not
    913     // ("Status" variable record the latest status returned
    914     // by ReadCapacity )
    915     //
    916     if (Status != EFI_SUCCESS) {
    917       return EFI_DEVICE_ERROR;
    918     }
    919   }
    920 
    921   return EFI_SUCCESS;
    922 }
    923