Home | History | Annotate | Download | only in UsbMassStorageDxe
      1 /** @file
      2   USB Mass Storage Driver that manages USB Mass Storage Device and produces Block I/O Protocol.
      3 
      4 Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "UsbMass.h"
     16 
     17 #define USB_MASS_TRANSPORT_COUNT    3
     18 //
     19 // Array of USB transport interfaces.
     20 //
     21 USB_MASS_TRANSPORT *mUsbMassTransport[USB_MASS_TRANSPORT_COUNT] = {
     22   &mUsbCbi0Transport,
     23   &mUsbCbi1Transport,
     24   &mUsbBotTransport,
     25 };
     26 
     27 EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
     28   USBMassDriverBindingSupported,
     29   USBMassDriverBindingStart,
     30   USBMassDriverBindingStop,
     31   0x11,
     32   NULL,
     33   NULL
     34 };
     35 
     36 /**
     37   Reset the block device.
     38 
     39   This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
     40   It resets the block device hardware.
     41   ExtendedVerification is ignored in this implementation.
     42 
     43   @param  This                   Indicates a pointer to the calling context.
     44   @param  ExtendedVerification   Indicates that the driver may perform a more exhaustive
     45                                  verification operation of the device during reset.
     46 
     47   @retval EFI_SUCCESS            The block device was reset.
     48   @retval EFI_DEVICE_ERROR       The block device is not functioning correctly and could not be reset.
     49 
     50 **/
     51 EFI_STATUS
     52 EFIAPI
     53 UsbMassReset (
     54   IN EFI_BLOCK_IO_PROTOCOL    *This,
     55   IN BOOLEAN                  ExtendedVerification
     56   )
     57 {
     58   USB_MASS_DEVICE *UsbMass;
     59   EFI_TPL         OldTpl;
     60   EFI_STATUS      Status;
     61 
     62   //
     63   // Raise TPL to TPL_NOTIFY to serialize all its operations
     64   // to protect shared data structures.
     65   //
     66   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
     67 
     68   UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
     69   Status  = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);
     70 
     71   gBS->RestoreTPL (OldTpl);
     72 
     73   return Status;
     74 }
     75 
     76 /**
     77   Reads the requested number of blocks from the device.
     78 
     79   This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
     80   It reads the requested number of blocks from the device.
     81   All the blocks are read, or an error is returned.
     82 
     83   @param  This                   Indicates a pointer to the calling context.
     84   @param  MediaId                The media ID that the read request is for.
     85   @param  Lba                    The starting logical block address to read from on the device.
     86   @param  BufferSize             The size of the Buffer in bytes.
     87                                  This must be a multiple of the intrinsic block size of the device.
     88   @param  Buffer                 A pointer to the destination buffer for the data. The caller is
     89                                  responsible for either having implicit or explicit ownership of the buffer.
     90 
     91   @retval EFI_SUCCESS            The data was read correctly from the device.
     92   @retval EFI_DEVICE_ERROR       The device reported an error while attempting to perform the read operation.
     93   @retval EFI_NO_MEDIA           There is no media in the device.
     94   @retval EFI_MEDIA_CHANGED      The MediaId is not for the current media.
     95   @retval EFI_BAD_BUFFER_SIZE    The BufferSize parameter is not a multiple of the intrinsic block size of the device.
     96   @retval EFI_INVALID_PARAMETER  The read request contains LBAs that are not valid,
     97                                  or the buffer is not on proper alignment.
     98 
     99 **/
    100 EFI_STATUS
    101 EFIAPI
    102 UsbMassReadBlocks (
    103   IN EFI_BLOCK_IO_PROTOCOL    *This,
    104   IN UINT32                   MediaId,
    105   IN EFI_LBA                  Lba,
    106   IN UINTN                    BufferSize,
    107   OUT VOID                    *Buffer
    108   )
    109 {
    110   USB_MASS_DEVICE     *UsbMass;
    111   EFI_BLOCK_IO_MEDIA  *Media;
    112   EFI_STATUS          Status;
    113   EFI_TPL             OldTpl;
    114   UINTN               TotalBlock;
    115 
    116   //
    117   // Raise TPL to TPL_NOTIFY to serialize all its operations
    118   // to protect shared data structures.
    119   //
    120   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
    121   UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
    122   Media   = &UsbMass->BlockIoMedia;
    123 
    124   //
    125   // If it is a removable media, such as CD-Rom or Usb-Floppy,
    126   // need to detect the media before each read/write. While some of
    127   // Usb-Flash is marked as removable media.
    128   //
    129   if (Media->RemovableMedia) {
    130     Status = UsbBootDetectMedia (UsbMass);
    131     if (EFI_ERROR (Status)) {
    132       goto ON_EXIT;
    133     }
    134   }
    135 
    136   if (!(Media->MediaPresent)) {
    137     Status = EFI_NO_MEDIA;
    138     goto ON_EXIT;
    139   }
    140 
    141   if (MediaId != Media->MediaId) {
    142     Status = EFI_MEDIA_CHANGED;
    143     goto ON_EXIT;
    144   }
    145 
    146   if (BufferSize == 0) {
    147     Status = EFI_SUCCESS;
    148     goto ON_EXIT;
    149   }
    150 
    151   if (Buffer == NULL) {
    152     Status = EFI_INVALID_PARAMETER;
    153     goto ON_EXIT;
    154   }
    155 
    156   //
    157   // BufferSize must be a multiple of the intrinsic block size of the device.
    158   //
    159   if ((BufferSize % Media->BlockSize) != 0) {
    160     Status = EFI_BAD_BUFFER_SIZE;
    161     goto ON_EXIT;
    162   }
    163 
    164   TotalBlock = BufferSize / Media->BlockSize;
    165 
    166   //
    167   // Make sure the range to read is valid.
    168   //
    169   if (Lba + TotalBlock - 1 > Media->LastBlock) {
    170     Status = EFI_INVALID_PARAMETER;
    171     goto ON_EXIT;
    172   }
    173 
    174   if (UsbMass->Cdb16Byte) {
    175     Status = UsbBootReadBlocks16 (UsbMass, Lba, TotalBlock, Buffer);
    176   } else {
    177     Status = UsbBootReadBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
    178   }
    179 
    180   if (EFI_ERROR (Status)) {
    181     DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));
    182     UsbMassReset (This, TRUE);
    183   }
    184 
    185 ON_EXIT:
    186   gBS->RestoreTPL (OldTpl);
    187   return Status;
    188 }
    189 
    190 
    191 /**
    192   Writes a specified number of blocks to the device.
    193 
    194   This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
    195   It writes a specified number of blocks to the device.
    196   All blocks are written, or an error is returned.
    197 
    198   @param  This                   Indicates a pointer to the calling context.
    199   @param  MediaId                The media ID that the write request is for.
    200   @param  Lba                    The starting logical block address to be written.
    201   @param  BufferSize             The size of the Buffer in bytes.
    202                                  This must be a multiple of the intrinsic block size of the device.
    203   @param  Buffer                 Pointer to the source buffer for the data.
    204 
    205   @retval EFI_SUCCESS            The data were written correctly to the device.
    206   @retval EFI_WRITE_PROTECTED    The device cannot be written to.
    207   @retval EFI_NO_MEDIA           There is no media in the device.
    208   @retval EFI_MEDIA_CHANGED      The MediaId is not for the current media.
    209   @retval EFI_DEVICE_ERROR       The device reported an error while attempting to perform the write operation.
    210   @retval EFI_BAD_BUFFER_SIZE    The BufferSize parameter is not a multiple of the intrinsic
    211                                  block size of the device.
    212   @retval EFI_INVALID_PARAMETER  The write request contains LBAs that are not valid,
    213                                  or the buffer is not on proper alignment.
    214 
    215 **/
    216 EFI_STATUS
    217 EFIAPI
    218 UsbMassWriteBlocks (
    219   IN EFI_BLOCK_IO_PROTOCOL    *This,
    220   IN UINT32                   MediaId,
    221   IN EFI_LBA                  Lba,
    222   IN UINTN                    BufferSize,
    223   IN VOID                     *Buffer
    224   )
    225 {
    226   USB_MASS_DEVICE     *UsbMass;
    227   EFI_BLOCK_IO_MEDIA  *Media;
    228   EFI_STATUS          Status;
    229   EFI_TPL             OldTpl;
    230   UINTN               TotalBlock;
    231 
    232   //
    233   // Raise TPL to TPL_NOTIFY to serialize all its operations
    234   // to protect shared data structures.
    235   //
    236   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
    237   UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
    238   Media   = &UsbMass->BlockIoMedia;
    239 
    240   //
    241   // If it is a removable media, such as CD-Rom or Usb-Floppy,
    242   // need to detect the media before each read/write. Some of
    243   // USB Flash is marked as removable media.
    244   //
    245   if (Media->RemovableMedia) {
    246     Status = UsbBootDetectMedia (UsbMass);
    247     if (EFI_ERROR (Status)) {
    248       goto ON_EXIT;
    249     }
    250   }
    251 
    252   if (!(Media->MediaPresent)) {
    253     Status = EFI_NO_MEDIA;
    254     goto ON_EXIT;
    255   }
    256 
    257   if (MediaId != Media->MediaId) {
    258     Status = EFI_MEDIA_CHANGED;
    259     goto ON_EXIT;
    260   }
    261 
    262   if (BufferSize == 0) {
    263     Status = EFI_SUCCESS;
    264     goto ON_EXIT;
    265   }
    266 
    267   if (Buffer == NULL) {
    268     Status = EFI_INVALID_PARAMETER;
    269     goto ON_EXIT;
    270   }
    271 
    272   //
    273   // BufferSize must be a multiple of the intrinsic block size of the device.
    274   //
    275   if ((BufferSize % Media->BlockSize) != 0) {
    276     Status = EFI_BAD_BUFFER_SIZE;
    277     goto ON_EXIT;
    278   }
    279 
    280   TotalBlock = BufferSize / Media->BlockSize;
    281 
    282   //
    283   // Make sure the range to write is valid.
    284   //
    285   if (Lba + TotalBlock - 1 > Media->LastBlock) {
    286     Status = EFI_INVALID_PARAMETER;
    287     goto ON_EXIT;
    288   }
    289 
    290   //
    291   // Try to write the data even the device is marked as ReadOnly,
    292   // and clear the status should the write succeed.
    293   //
    294   if (UsbMass->Cdb16Byte) {
    295     Status = UsbBootWriteBlocks16 (UsbMass, Lba, TotalBlock, Buffer);
    296   } else {
    297     Status = UsbBootWriteBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
    298   }
    299 
    300   if (EFI_ERROR (Status)) {
    301     DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));
    302     UsbMassReset (This, TRUE);
    303   }
    304 
    305 ON_EXIT:
    306   gBS->RestoreTPL (OldTpl);
    307   return Status;
    308 }
    309 
    310 /**
    311   Flushes all modified data to a physical block device.
    312 
    313   This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks().
    314   USB mass storage device doesn't support write cache,
    315   so return EFI_SUCCESS directly.
    316 
    317   @param  This                   Indicates a pointer to the calling context.
    318 
    319   @retval EFI_SUCCESS            All outstanding data were written correctly to the device.
    320   @retval EFI_DEVICE_ERROR       The device reported an error while attempting to write data.
    321   @retval EFI_NO_MEDIA           There is no media in the device.
    322 
    323 **/
    324 EFI_STATUS
    325 EFIAPI
    326 UsbMassFlushBlocks (
    327   IN EFI_BLOCK_IO_PROTOCOL  *This
    328   )
    329 {
    330   return EFI_SUCCESS;
    331 }
    332 
    333 /**
    334   Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
    335 
    336   @param  UsbMass                The USB mass storage device
    337 
    338   @retval EFI_SUCCESS            The media parameters are updated successfully.
    339   @retval Others                 Failed to get the media parameters.
    340 
    341 **/
    342 EFI_STATUS
    343 UsbMassInitMedia (
    344   IN USB_MASS_DEVICE          *UsbMass
    345   )
    346 {
    347   EFI_BLOCK_IO_MEDIA          *Media;
    348   EFI_STATUS                  Status;
    349 
    350   Media = &UsbMass->BlockIoMedia;
    351 
    352   //
    353   // Fields of EFI_BLOCK_IO_MEDIA are defined in UEFI 2.0 spec,
    354   // section for Block I/O Protocol.
    355   //
    356   Media->MediaPresent     = FALSE;
    357   Media->LogicalPartition = FALSE;
    358   Media->ReadOnly         = FALSE;
    359   Media->WriteCaching     = FALSE;
    360   Media->IoAlign          = 0;
    361   Media->MediaId          = 1;
    362 
    363   Status = UsbBootGetParams (UsbMass);
    364   return Status;
    365 }
    366 
    367 /**
    368   Initilize the USB Mass Storage transport.
    369 
    370   This function tries to find the matching USB Mass Storage transport
    371   protocol for USB device. If found, initializes the matching transport.
    372 
    373   @param  This            The USB mass driver's driver binding.
    374   @param  Controller      The device to test.
    375   @param  Transport       The pointer to pointer to USB_MASS_TRANSPORT.
    376   @param  Context         The parameter for USB_MASS_DEVICE.Context.
    377   @param  MaxLun          Get the MaxLun if is BOT dev.
    378 
    379   @retval EFI_SUCCESS     The initialization is successful.
    380   @retval EFI_UNSUPPORTED No matching transport protocol is found.
    381   @retval Others          Failed to initialize dev.
    382 
    383 **/
    384 EFI_STATUS
    385 UsbMassInitTransport (
    386   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    387   IN  EFI_HANDLE                   Controller,
    388   OUT USB_MASS_TRANSPORT           **Transport,
    389   OUT VOID                         **Context,
    390   OUT UINT8                        *MaxLun
    391   )
    392 {
    393   EFI_USB_IO_PROTOCOL           *UsbIo;
    394   EFI_USB_INTERFACE_DESCRIPTOR  Interface;
    395   UINT8                         Index;
    396   EFI_STATUS                    Status;
    397 
    398   Status = gBS->OpenProtocol (
    399                   Controller,
    400                   &gEfiUsbIoProtocolGuid,
    401                   (VOID **) &UsbIo,
    402                   This->DriverBindingHandle,
    403                   Controller,
    404                   EFI_OPEN_PROTOCOL_BY_DRIVER
    405                   );
    406 
    407   if (EFI_ERROR (Status)) {
    408     return Status;
    409   }
    410 
    411   Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
    412   if (EFI_ERROR (Status)) {
    413     goto ON_EXIT;
    414   }
    415 
    416   Status = EFI_UNSUPPORTED;
    417 
    418   //
    419   // Traverse the USB_MASS_TRANSPORT arrary and try to find the
    420   // matching transport protocol.
    421   // If not found, return EFI_UNSUPPORTED.
    422   // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
    423   //
    424   for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {
    425     *Transport = mUsbMassTransport[Index];
    426 
    427     if (Interface.InterfaceProtocol == (*Transport)->Protocol) {
    428       Status  = (*Transport)->Init (UsbIo, Context);
    429       break;
    430     }
    431   }
    432 
    433   if (EFI_ERROR (Status)) {
    434     goto ON_EXIT;
    435   }
    436 
    437   //
    438   // For BOT device, try to get its max LUN.
    439   // If max LUN is 0, then it is a non-lun device.
    440   // Otherwise, it is a multi-lun device.
    441   //
    442   if ((*Transport)->Protocol == USB_MASS_STORE_BOT) {
    443     (*Transport)->GetMaxLun (*Context, MaxLun);
    444   }
    445 
    446 ON_EXIT:
    447   gBS->CloseProtocol (
    448          Controller,
    449          &gEfiUsbIoProtocolGuid,
    450          This->DriverBindingHandle,
    451          Controller
    452          );
    453   return Status;
    454 }
    455 
    456 /**
    457   Initialize data for device that supports multiple LUNSs.
    458 
    459   @param  This                 The Driver Binding Protocol instance.
    460   @param  Controller           The device to initialize.
    461   @param  Transport            Pointer to USB_MASS_TRANSPORT.
    462   @param  Context              Parameter for USB_MASS_DEVICE.Context.
    463   @param  DevicePath           The remaining device path.
    464   @param  MaxLun               The max LUN number.
    465 
    466   @retval EFI_SUCCESS          At least one LUN is initialized successfully.
    467   @retval EFI_NOT_FOUND        Fail to initialize any of multiple LUNs.
    468 
    469 **/
    470 EFI_STATUS
    471 UsbMassInitMultiLun (
    472   IN EFI_DRIVER_BINDING_PROTOCOL   *This,
    473   IN EFI_HANDLE                    Controller,
    474   IN USB_MASS_TRANSPORT            *Transport,
    475   IN VOID                          *Context,
    476   IN EFI_DEVICE_PATH_PROTOCOL      *DevicePath,
    477   IN UINT8                         MaxLun
    478   )
    479 {
    480   USB_MASS_DEVICE                  *UsbMass;
    481   EFI_USB_IO_PROTOCOL              *UsbIo;
    482   DEVICE_LOGICAL_UNIT_DEVICE_PATH  LunNode;
    483   UINT8                            Index;
    484   EFI_STATUS                       Status;
    485   EFI_STATUS                       ReturnStatus;
    486 
    487   ASSERT (MaxLun > 0);
    488   ReturnStatus = EFI_NOT_FOUND;
    489 
    490   for (Index = 0; Index <= MaxLun; Index++) {
    491 
    492     DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Start to initialize No.%d logic unit\n", Index));
    493 
    494     UsbIo   = NULL;
    495     UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
    496     ASSERT (UsbMass != NULL);
    497 
    498     UsbMass->Signature            = USB_MASS_SIGNATURE;
    499     UsbMass->UsbIo                = UsbIo;
    500     UsbMass->BlockIo.Media        = &UsbMass->BlockIoMedia;
    501     UsbMass->BlockIo.Reset        = UsbMassReset;
    502     UsbMass->BlockIo.ReadBlocks   = UsbMassReadBlocks;
    503     UsbMass->BlockIo.WriteBlocks  = UsbMassWriteBlocks;
    504     UsbMass->BlockIo.FlushBlocks  = UsbMassFlushBlocks;
    505     UsbMass->OpticalStorage       = FALSE;
    506     UsbMass->Transport            = Transport;
    507     UsbMass->Context              = Context;
    508     UsbMass->Lun                  = Index;
    509 
    510     //
    511     // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
    512     //
    513     Status = UsbMassInitMedia (UsbMass);
    514     if ((EFI_ERROR (Status)) && (Status != EFI_NO_MEDIA)) {
    515       DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: UsbMassInitMedia (%r)\n", Status));
    516       FreePool (UsbMass);
    517       continue;
    518     }
    519 
    520     //
    521     // Create a device path node for device logic unit, and append it.
    522     //
    523     LunNode.Header.Type    = MESSAGING_DEVICE_PATH;
    524     LunNode.Header.SubType = MSG_DEVICE_LOGICAL_UNIT_DP;
    525     LunNode.Lun            = UsbMass->Lun;
    526 
    527     SetDevicePathNodeLength (&LunNode.Header, sizeof (LunNode));
    528 
    529     UsbMass->DevicePath = AppendDevicePathNode (DevicePath, &LunNode.Header);
    530 
    531     if (UsbMass->DevicePath == NULL) {
    532       DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: failed to create device logic unit device path\n"));
    533       Status = EFI_OUT_OF_RESOURCES;
    534       FreePool (UsbMass);
    535       continue;
    536     }
    537 
    538     InitializeDiskInfo (UsbMass);
    539 
    540     //
    541     // Create a new handle for each LUN, and install Block I/O Protocol and Device Path Protocol.
    542     //
    543     Status = gBS->InstallMultipleProtocolInterfaces (
    544                     &UsbMass->Controller,
    545                     &gEfiDevicePathProtocolGuid,
    546                     UsbMass->DevicePath,
    547                     &gEfiBlockIoProtocolGuid,
    548                     &UsbMass->BlockIo,
    549                     &gEfiDiskInfoProtocolGuid,
    550                     &UsbMass->DiskInfo,
    551                     NULL
    552                     );
    553 
    554     if (EFI_ERROR (Status)) {
    555       DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: InstallMultipleProtocolInterfaces (%r)\n", Status));
    556       FreePool (UsbMass->DevicePath);
    557       FreePool (UsbMass);
    558       continue;
    559     }
    560 
    561     //
    562     // Open USB I/O Protocol by child to setup a parent-child relationship.
    563     //
    564     Status = gBS->OpenProtocol (
    565                     Controller,
    566                     &gEfiUsbIoProtocolGuid,
    567                     (VOID **) &UsbIo,
    568                     This->DriverBindingHandle,
    569                     UsbMass->Controller,
    570                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    571                     );
    572 
    573     if (EFI_ERROR (Status)) {
    574       DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: OpenUsbIoProtocol By Child (%r)\n", Status));
    575       gBS->UninstallMultipleProtocolInterfaces (
    576              &UsbMass->Controller,
    577              &gEfiDevicePathProtocolGuid,
    578              UsbMass->DevicePath,
    579              &gEfiBlockIoProtocolGuid,
    580              &UsbMass->BlockIo,
    581              &gEfiDiskInfoProtocolGuid,
    582              &UsbMass->DiskInfo,
    583              NULL
    584              );
    585       FreePool (UsbMass->DevicePath);
    586       FreePool (UsbMass);
    587       continue;
    588     }
    589     ReturnStatus = EFI_SUCCESS;
    590     DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Success to initialize No.%d logic unit\n", Index));
    591   }
    592 
    593   return ReturnStatus;
    594 }
    595 
    596 /**
    597   Initialize data for device that does not support multiple LUNSs.
    598 
    599   @param  This            The Driver Binding Protocol instance.
    600   @param  Controller      The device to initialize.
    601   @param  Transport       Pointer to USB_MASS_TRANSPORT.
    602   @param  Context         Parameter for USB_MASS_DEVICE.Context.
    603 
    604   @retval EFI_SUCCESS     Initialization succeeds.
    605   @retval Other           Initialization fails.
    606 
    607 **/
    608 EFI_STATUS
    609 UsbMassInitNonLun (
    610   IN EFI_DRIVER_BINDING_PROTOCOL   *This,
    611   IN EFI_HANDLE                    Controller,
    612   IN USB_MASS_TRANSPORT            *Transport,
    613   IN VOID                          *Context
    614   )
    615 {
    616   USB_MASS_DEVICE             *UsbMass;
    617   EFI_USB_IO_PROTOCOL         *UsbIo;
    618   EFI_STATUS                  Status;
    619 
    620   UsbIo   = NULL;
    621   UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
    622   ASSERT (UsbMass != NULL);
    623 
    624   Status = gBS->OpenProtocol (
    625                   Controller,
    626                   &gEfiUsbIoProtocolGuid,
    627                   (VOID **) &UsbIo,
    628                   This->DriverBindingHandle,
    629                   Controller,
    630                   EFI_OPEN_PROTOCOL_BY_DRIVER
    631                   );
    632 
    633   if (EFI_ERROR (Status)) {
    634     DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: OpenUsbIoProtocol By Driver (%r)\n", Status));
    635     goto ON_ERROR;
    636   }
    637 
    638   UsbMass->Signature            = USB_MASS_SIGNATURE;
    639   UsbMass->Controller           = Controller;
    640   UsbMass->UsbIo                = UsbIo;
    641   UsbMass->BlockIo.Media        = &UsbMass->BlockIoMedia;
    642   UsbMass->BlockIo.Reset        = UsbMassReset;
    643   UsbMass->BlockIo.ReadBlocks   = UsbMassReadBlocks;
    644   UsbMass->BlockIo.WriteBlocks  = UsbMassWriteBlocks;
    645   UsbMass->BlockIo.FlushBlocks  = UsbMassFlushBlocks;
    646   UsbMass->OpticalStorage       = FALSE;
    647   UsbMass->Transport            = Transport;
    648   UsbMass->Context              = Context;
    649 
    650   //
    651   // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
    652   //
    653   Status = UsbMassInitMedia (UsbMass);
    654   if ((EFI_ERROR (Status)) && (Status != EFI_NO_MEDIA)) {
    655     DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: UsbMassInitMedia (%r)\n", Status));
    656     goto ON_ERROR;
    657   }
    658 
    659   InitializeDiskInfo (UsbMass);
    660 
    661   Status = gBS->InstallMultipleProtocolInterfaces (
    662                   &Controller,
    663                   &gEfiBlockIoProtocolGuid,
    664                   &UsbMass->BlockIo,
    665                   &gEfiDiskInfoProtocolGuid,
    666                   &UsbMass->DiskInfo,
    667                   NULL
    668                   );
    669   if (EFI_ERROR (Status)) {
    670     goto ON_ERROR;
    671   }
    672 
    673   return EFI_SUCCESS;
    674 
    675 ON_ERROR:
    676   if (UsbMass != NULL) {
    677     FreePool (UsbMass);
    678   }
    679   if (UsbIo != NULL) {
    680     gBS->CloseProtocol (
    681            Controller,
    682            &gEfiUsbIoProtocolGuid,
    683            This->DriverBindingHandle,
    684            Controller
    685            );
    686   }
    687   return Status;
    688 }
    689 
    690 
    691 /**
    692   Check whether the controller is a supported USB mass storage.
    693 
    694   @param  This                   The USB mass storage driver binding protocol.
    695   @param  Controller             The controller handle to check.
    696   @param  RemainingDevicePath    The remaining device path.
    697 
    698   @retval EFI_SUCCESS            The driver supports this controller.
    699   @retval other                  This device isn't supported.
    700 
    701 **/
    702 EFI_STATUS
    703 EFIAPI
    704 USBMassDriverBindingSupported (
    705   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    706   IN EFI_HANDLE                   Controller,
    707   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    708   )
    709 {
    710   EFI_USB_IO_PROTOCOL           *UsbIo;
    711   EFI_USB_INTERFACE_DESCRIPTOR  Interface;
    712   USB_MASS_TRANSPORT            *Transport;
    713   EFI_STATUS                    Status;
    714   UINTN                         Index;
    715 
    716   Status = gBS->OpenProtocol (
    717                   Controller,
    718                   &gEfiUsbIoProtocolGuid,
    719                   (VOID **) &UsbIo,
    720                   This->DriverBindingHandle,
    721                   Controller,
    722                   EFI_OPEN_PROTOCOL_BY_DRIVER
    723                   );
    724   if (EFI_ERROR (Status)) {
    725     return Status;
    726   }
    727 
    728   //
    729   // Get the interface descriptor to check the USB class and find a transport
    730   // protocol handler.
    731   //
    732   Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
    733   if (EFI_ERROR (Status)) {
    734     goto ON_EXIT;
    735   }
    736 
    737   Status = EFI_UNSUPPORTED;
    738 
    739   if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {
    740     goto ON_EXIT;
    741   }
    742 
    743   //
    744   // Traverse the USB_MASS_TRANSPORT arrary and try to find the
    745   // matching transport method.
    746   // If not found, return EFI_UNSUPPORTED.
    747   // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
    748   //
    749   for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {
    750     Transport = mUsbMassTransport[Index];
    751     if (Interface.InterfaceProtocol == Transport->Protocol) {
    752       Status = Transport->Init (UsbIo, NULL);
    753       break;
    754     }
    755   }
    756 
    757 ON_EXIT:
    758   gBS->CloseProtocol (
    759          Controller,
    760          &gEfiUsbIoProtocolGuid,
    761          This->DriverBindingHandle,
    762          Controller
    763          );
    764 
    765   return Status;
    766 }
    767 
    768 /**
    769   Starts the USB mass storage device with this driver.
    770 
    771   This function consumes USB I/O Portocol, intializes USB mass storage device,
    772   installs Block I/O Protocol, and submits Asynchronous Interrupt
    773   Transfer to manage the USB mass storage device.
    774 
    775   @param  This                  The USB mass storage driver binding protocol.
    776   @param  Controller            The USB mass storage device to start on
    777   @param  RemainingDevicePath   The remaining device path.
    778 
    779   @retval EFI_SUCCESS           This driver supports this device.
    780   @retval EFI_UNSUPPORTED       This driver does not support this device.
    781   @retval EFI_DEVICE_ERROR      This driver cannot be started due to device Error.
    782   @retval EFI_OUT_OF_RESOURCES  Can't allocate memory resources.
    783   @retval EFI_ALREADY_STARTED   This driver has been started.
    784 
    785 **/
    786 EFI_STATUS
    787 EFIAPI
    788 USBMassDriverBindingStart (
    789   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    790   IN EFI_HANDLE                   Controller,
    791   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    792   )
    793 {
    794   USB_MASS_TRANSPORT            *Transport;
    795   EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
    796   VOID                          *Context;
    797   UINT8                         MaxLun;
    798   EFI_STATUS                    Status;
    799   EFI_USB_IO_PROTOCOL           *UsbIo;
    800   EFI_TPL                       OldTpl;
    801 
    802   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    803 
    804   Transport = NULL;
    805   Context   = NULL;
    806   MaxLun    = 0;
    807 
    808   Status = UsbMassInitTransport (This, Controller, &Transport, &Context, &MaxLun);
    809 
    810   if (EFI_ERROR (Status)) {
    811     DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitTransport (%r)\n", Status));
    812     goto Exit;
    813   }
    814   if (MaxLun == 0) {
    815     //
    816     // Initialize data for device that does not support multiple LUNSs.
    817     //
    818     Status = UsbMassInitNonLun (This, Controller, Transport, Context);
    819     if (EFI_ERROR (Status)) {
    820       DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitNonLun (%r)\n", Status));
    821     }
    822   } else {
    823     //
    824     // Open device path to prepare for appending Device Logic Unit node.
    825     //
    826     Status = gBS->OpenProtocol (
    827                     Controller,
    828                     &gEfiDevicePathProtocolGuid,
    829                     (VOID **) &DevicePath,
    830                     This->DriverBindingHandle,
    831                     Controller,
    832                     EFI_OPEN_PROTOCOL_BY_DRIVER
    833                     );
    834 
    835     if (EFI_ERROR (Status)) {
    836       DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenDevicePathProtocol By Driver (%r)\n", Status));
    837       goto Exit;
    838     }
    839 
    840     Status = gBS->OpenProtocol (
    841                     Controller,
    842                     &gEfiUsbIoProtocolGuid,
    843                     (VOID **) &UsbIo,
    844                     This->DriverBindingHandle,
    845                     Controller,
    846                     EFI_OPEN_PROTOCOL_BY_DRIVER
    847                     );
    848 
    849     if (EFI_ERROR (Status)) {
    850       DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenUsbIoProtocol By Driver (%r)\n", Status));
    851       gBS->CloseProtocol (
    852              Controller,
    853              &gEfiDevicePathProtocolGuid,
    854              This->DriverBindingHandle,
    855              Controller
    856              );
    857       goto Exit;
    858     }
    859 
    860     //
    861     // Initialize data for device that supports multiple LUNs.
    862     // EFI_SUCCESS is returned if at least 1 LUN is initialized successfully.
    863     //
    864     Status = UsbMassInitMultiLun (This, Controller, Transport, Context, DevicePath, MaxLun);
    865     if (EFI_ERROR (Status)) {
    866       gBS->CloseProtocol (
    867               Controller,
    868               &gEfiDevicePathProtocolGuid,
    869               This->DriverBindingHandle,
    870               Controller
    871               );
    872       gBS->CloseProtocol (
    873               Controller,
    874               &gEfiUsbIoProtocolGuid,
    875               This->DriverBindingHandle,
    876               Controller
    877               );
    878       DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitMultiLun (%r) with Maxlun=%d\n", Status, MaxLun));
    879     }
    880   }
    881 Exit:
    882   gBS->RestoreTPL (OldTpl);
    883   return Status;
    884 }
    885 
    886 
    887 /**
    888   Stop controlling the device.
    889 
    890   @param  This                   The USB mass storage driver binding
    891   @param  Controller             The device controller controlled by the driver.
    892   @param  NumberOfChildren       The number of children of this device
    893   @param  ChildHandleBuffer      The buffer of children handle.
    894 
    895   @retval EFI_SUCCESS            The driver stopped from controlling the device.
    896   @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.
    897   @retval EFI_UNSUPPORTED        Block I/O Protocol is not installed on Controller.
    898   @retval Others                 Failed to stop the driver
    899 
    900 **/
    901 EFI_STATUS
    902 EFIAPI
    903 USBMassDriverBindingStop (
    904   IN  EFI_DRIVER_BINDING_PROTOCOL *This,
    905   IN  EFI_HANDLE                  Controller,
    906   IN  UINTN                       NumberOfChildren,
    907   IN  EFI_HANDLE                  *ChildHandleBuffer
    908   )
    909 {
    910   EFI_STATUS            Status;
    911   USB_MASS_DEVICE       *UsbMass;
    912   EFI_USB_IO_PROTOCOL   *UsbIo;
    913   EFI_BLOCK_IO_PROTOCOL *BlockIo;
    914   UINTN                 Index;
    915   BOOLEAN               AllChildrenStopped;
    916 
    917   //
    918   // This is a bus driver stop function since multi-lun is supported.
    919   // There are three kinds of device handles that might be passed:
    920   // 1st is a handle with USB I/O & Block I/O installed (non-multi-lun)
    921   // 2nd is a handle with Device Path & USB I/O installed (multi-lun root)
    922   // 3rd is a handle with Device Path & USB I/O & Block I/O installed (multi-lun).
    923   //
    924   if (NumberOfChildren == 0) {
    925     //
    926     // A handle without any children, might be 1st and 2nd type.
    927     //
    928     Status = gBS->OpenProtocol (
    929                     Controller,
    930                     &gEfiBlockIoProtocolGuid,
    931                     (VOID **) &BlockIo,
    932                     This->DriverBindingHandle,
    933                     Controller,
    934                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    935                     );
    936 
    937     if (EFI_ERROR(Status)) {
    938       //
    939       // This is a 2nd type handle(multi-lun root), it needs to close devicepath
    940       // and usbio protocol.
    941       //
    942       gBS->CloseProtocol (
    943             Controller,
    944             &gEfiDevicePathProtocolGuid,
    945             This->DriverBindingHandle,
    946             Controller
    947             );
    948       gBS->CloseProtocol (
    949             Controller,
    950             &gEfiUsbIoProtocolGuid,
    951             This->DriverBindingHandle,
    952             Controller
    953             );
    954       DEBUG ((EFI_D_INFO, "Success to stop multi-lun root handle\n"));
    955       return EFI_SUCCESS;
    956     }
    957 
    958     //
    959     // This is a 1st type handle(non-multi-lun), which only needs to uninstall
    960     // Block I/O Protocol, close USB I/O Protocol and free mass device.
    961     //
    962     UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
    963 
    964     //
    965     // Uninstall Block I/O protocol from the device handle,
    966     // then call the transport protocol to stop itself.
    967     //
    968     Status = gBS->UninstallMultipleProtocolInterfaces (
    969                     Controller,
    970                     &gEfiBlockIoProtocolGuid,
    971                     &UsbMass->BlockIo,
    972                     &gEfiDiskInfoProtocolGuid,
    973                     &UsbMass->DiskInfo,
    974                     NULL
    975                     );
    976     if (EFI_ERROR (Status)) {
    977       return Status;
    978     }
    979 
    980     gBS->CloseProtocol (
    981           Controller,
    982           &gEfiUsbIoProtocolGuid,
    983           This->DriverBindingHandle,
    984           Controller
    985           );
    986 
    987     UsbMass->Transport->CleanUp (UsbMass->Context);
    988     FreePool (UsbMass);
    989 
    990     DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n"));
    991     return EFI_SUCCESS;
    992   }
    993 
    994   //
    995   // This is a 3rd type handle(multi-lun), which needs uninstall
    996   // Block I/O Protocol and Device Path Protocol, close USB I/O Protocol and
    997   // free mass device for all children.
    998   //
    999   AllChildrenStopped = TRUE;
   1000 
   1001   for (Index = 0; Index < NumberOfChildren; Index++) {
   1002 
   1003     Status = gBS->OpenProtocol (
   1004                     ChildHandleBuffer[Index],
   1005                     &gEfiBlockIoProtocolGuid,
   1006                     (VOID **) &BlockIo,
   1007                     This->DriverBindingHandle,
   1008                     Controller,
   1009                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1010                     );
   1011     if (EFI_ERROR (Status)) {
   1012       AllChildrenStopped = FALSE;
   1013       DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening blockio\n", (UINT32)Index));
   1014       continue;
   1015     }
   1016 
   1017     UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
   1018 
   1019     gBS->CloseProtocol (
   1020            Controller,
   1021            &gEfiUsbIoProtocolGuid,
   1022            This->DriverBindingHandle,
   1023            ChildHandleBuffer[Index]
   1024            );
   1025 
   1026     Status = gBS->UninstallMultipleProtocolInterfaces (
   1027                     ChildHandleBuffer[Index],
   1028                     &gEfiDevicePathProtocolGuid,
   1029                     UsbMass->DevicePath,
   1030                     &gEfiBlockIoProtocolGuid,
   1031                     &UsbMass->BlockIo,
   1032                     &gEfiDiskInfoProtocolGuid,
   1033                     &UsbMass->DiskInfo,
   1034                     NULL
   1035                     );
   1036 
   1037     if (EFI_ERROR (Status)) {
   1038       //
   1039       // Fail to uninstall Block I/O Protocol and Device Path Protocol, so re-open USB I/O Protocol by child.
   1040       //
   1041       AllChildrenStopped = FALSE;
   1042       DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when uninstalling blockio and devicepath\n", (UINT32)Index));
   1043 
   1044       gBS->OpenProtocol (
   1045              Controller,
   1046              &gEfiUsbIoProtocolGuid,
   1047              (VOID **) &UsbIo,
   1048              This->DriverBindingHandle,
   1049              ChildHandleBuffer[Index],
   1050              EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
   1051              );
   1052     } else {
   1053       //
   1054       // Succeed to stop this multi-lun handle, so go on with next child.
   1055       //
   1056       if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) {
   1057         UsbMass->Transport->CleanUp (UsbMass->Context);
   1058       }
   1059       FreePool (UsbMass);
   1060     }
   1061   }
   1062 
   1063   if (!AllChildrenStopped) {
   1064     return EFI_DEVICE_ERROR;
   1065   }
   1066 
   1067   DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", (UINT32) NumberOfChildren));
   1068   return EFI_SUCCESS;
   1069 }
   1070 
   1071 /**
   1072   Entrypoint of USB Mass Storage Driver.
   1073 
   1074   This function is the entrypoint of USB Mass Storage Driver. It installs Driver Binding
   1075   Protocol together with Component Name Protocols.
   1076 
   1077   @param  ImageHandle       The firmware allocated handle for the EFI image.
   1078   @param  SystemTable       A pointer to the EFI System Table.
   1079 
   1080   @retval EFI_SUCCESS       The entry point is executed successfully.
   1081 
   1082 **/
   1083 EFI_STATUS
   1084 EFIAPI
   1085 USBMassStorageEntryPoint (
   1086   IN EFI_HANDLE               ImageHandle,
   1087   IN EFI_SYSTEM_TABLE         *SystemTable
   1088   )
   1089 {
   1090   EFI_STATUS  Status;
   1091 
   1092   //
   1093   // Install driver binding protocol
   1094   //
   1095   Status = EfiLibInstallDriverBindingComponentName2 (
   1096              ImageHandle,
   1097              SystemTable,
   1098              &gUSBMassDriverBinding,
   1099              ImageHandle,
   1100              &gUsbMassStorageComponentName,
   1101              &gUsbMassStorageComponentName2
   1102              );
   1103   ASSERT_EFI_ERROR (Status);
   1104 
   1105   return EFI_SUCCESS;
   1106 }
   1107