Home | History | Annotate | Download | only in UsbMassStorageDxe
      1 /** @file
      2   Implementation of the command set of USB Mass Storage Specification
      3   for Bootability, Revision 1.0.
      4 
      5 Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The 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 "UsbMass.h"
     17 
     18 /**
     19   Execute REQUEST SENSE Command to retrieve sense data from device.
     20 
     21   @param  UsbMass                The device whose sense data is requested.
     22 
     23   @retval EFI_SUCCESS            The command is excuted successfully.
     24   @retval EFI_DEVICE_ERROR       Failed to request sense.
     25   @retval EFI_NO_RESPONSE        The device media doesn't response this request.
     26   @retval EFI_INVALID_PARAMETER  The command has some invalid parameters.
     27   @retval EFI_WRITE_PROTECTED    The device is write protected.
     28   @retval EFI_MEDIA_CHANGED      The device media has been changed.
     29 
     30 **/
     31 EFI_STATUS
     32 UsbBootRequestSense (
     33   IN USB_MASS_DEVICE          *UsbMass
     34   )
     35 {
     36   USB_BOOT_REQUEST_SENSE_CMD  SenseCmd;
     37   USB_BOOT_REQUEST_SENSE_DATA SenseData;
     38   EFI_BLOCK_IO_MEDIA          *Media;
     39   USB_MASS_TRANSPORT          *Transport;
     40   EFI_STATUS                  Status;
     41   UINT32                      CmdResult;
     42 
     43   Transport = UsbMass->Transport;
     44 
     45   //
     46   // Request the sense data from the device
     47   //
     48   ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD));
     49   ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA));
     50 
     51   SenseCmd.OpCode   = USB_BOOT_REQUEST_SENSE_OPCODE;
     52   SenseCmd.Lun      = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
     53   SenseCmd.AllocLen = (UINT8) sizeof (USB_BOOT_REQUEST_SENSE_DATA);
     54 
     55   Status = Transport->ExecCommand (
     56                         UsbMass->Context,
     57                         &SenseCmd,
     58                         sizeof (USB_BOOT_REQUEST_SENSE_CMD),
     59                         EfiUsbDataIn,
     60                         &SenseData,
     61                         sizeof (USB_BOOT_REQUEST_SENSE_DATA),
     62                         UsbMass->Lun,
     63                         USB_BOOT_GENERAL_CMD_TIMEOUT,
     64                         &CmdResult
     65                         );
     66   if (EFI_ERROR (Status) || CmdResult != USB_MASS_CMD_SUCCESS) {
     67     DEBUG ((EFI_D_ERROR, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status, CmdResult));
     68     if (!EFI_ERROR (Status)) {
     69       Status = EFI_DEVICE_ERROR;
     70     }
     71     return Status;
     72   }
     73 
     74   //
     75   // If sense data is retrieved successfully, interpret the sense data
     76   // and update the media status if necessary.
     77   //
     78   Media = &UsbMass->BlockIoMedia;
     79 
     80   switch (USB_BOOT_SENSE_KEY (SenseData.SenseKey)) {
     81 
     82   case USB_BOOT_SENSE_NO_SENSE:
     83     Status = EFI_NO_RESPONSE;
     84     break;
     85 
     86   case USB_BOOT_SENSE_RECOVERED:
     87     //
     88     // Suppose hardware can handle this case, and recover later by itself
     89     //
     90     Status = EFI_NOT_READY;
     91     break;
     92 
     93   case USB_BOOT_SENSE_NOT_READY:
     94     Status = EFI_DEVICE_ERROR;
     95     if (SenseData.Asc == USB_BOOT_ASC_NO_MEDIA) {
     96       Media->MediaPresent = FALSE;
     97       Status = EFI_NO_MEDIA;
     98     } else if (SenseData.Asc == USB_BOOT_ASC_NOT_READY) {
     99       Status = EFI_NOT_READY;
    100     }
    101     break;
    102 
    103   case USB_BOOT_SENSE_ILLEGAL_REQUEST:
    104     Status = EFI_INVALID_PARAMETER;
    105     break;
    106 
    107   case USB_BOOT_SENSE_UNIT_ATTENTION:
    108     Status = EFI_DEVICE_ERROR;
    109     if (SenseData.Asc == USB_BOOT_ASC_MEDIA_CHANGE) {
    110       //
    111       // If MediaChange, reset ReadOnly and new MediaId
    112       //
    113       Status = EFI_MEDIA_CHANGED;
    114       Media->ReadOnly = FALSE;
    115       Media->MediaId++;
    116     }
    117     break;
    118 
    119   case USB_BOOT_SENSE_DATA_PROTECT:
    120     Status = EFI_WRITE_PROTECTED;
    121     Media->ReadOnly = TRUE;
    122     break;
    123 
    124   default:
    125     Status = EFI_DEVICE_ERROR;
    126     break;
    127   }
    128 
    129   DEBUG ((EFI_D_INFO, "UsbBootRequestSense: (%r) with sense key %x/%x/%x\n",
    130           Status,
    131           USB_BOOT_SENSE_KEY (SenseData.SenseKey),
    132           SenseData.Asc,
    133           SenseData.Ascq
    134           ));
    135 
    136   return Status;
    137 }
    138 
    139 
    140 /**
    141   Execute the USB mass storage bootability commands.
    142 
    143   This function executes the USB mass storage bootability commands.
    144   If execution failed, retrieve the error by REQUEST_SENSE, then
    145   update the device's status, such as ReadyOnly.
    146 
    147   @param  UsbMass                The device to issue commands to
    148   @param  Cmd                    The command to execute
    149   @param  CmdLen                 The length of the command
    150   @param  DataDir                The direction of data transfer
    151   @param  Data                   The buffer to hold the data
    152   @param  DataLen                The length of expected data
    153   @param  Timeout                The timeout used to transfer
    154 
    155   @retval EFI_SUCCESS            Command is excuted successfully
    156   @retval Others                 Command execution failed.
    157 
    158 **/
    159 EFI_STATUS
    160 UsbBootExecCmd (
    161   IN USB_MASS_DEVICE            *UsbMass,
    162   IN VOID                       *Cmd,
    163   IN UINT8                      CmdLen,
    164   IN EFI_USB_DATA_DIRECTION     DataDir,
    165   IN VOID                       *Data,
    166   IN UINT32                     DataLen,
    167   IN UINT32                     Timeout
    168   )
    169 {
    170   USB_MASS_TRANSPORT          *Transport;
    171   EFI_STATUS                  Status;
    172   UINT32                      CmdResult;
    173 
    174   Transport = UsbMass->Transport;
    175   Status    = Transport->ExecCommand (
    176                            UsbMass->Context,
    177                            Cmd,
    178                            CmdLen,
    179                            DataDir,
    180                            Data,
    181                            DataLen,
    182                            UsbMass->Lun,
    183                            Timeout,
    184                            &CmdResult
    185                            );
    186 
    187   if (Status == EFI_TIMEOUT) {
    188     DEBUG ((EFI_D_ERROR, "UsbBootExecCmd: Timeout to Exec 0x%x Cmd\n", *(UINT8 *)Cmd));
    189     return EFI_TIMEOUT;
    190   }
    191 
    192   //
    193   // If ExecCommand() returns no error and CmdResult is success,
    194   // then the commnad transfer is successful.
    195   //
    196   if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR (Status)) {
    197     return EFI_SUCCESS;
    198   }
    199 
    200   //
    201   // If command execution failed, then retrieve error info via sense request.
    202   //
    203   return UsbBootRequestSense (UsbMass);
    204 }
    205 
    206 
    207 /**
    208   Execute the USB mass storage bootability commands with retrial.
    209 
    210   This function executes USB mass storage bootability commands.
    211   If the device isn't ready, wait for it. If the device is ready
    212   and error occurs, retry the command again until it exceeds the
    213   limit of retrial times.
    214 
    215   @param  UsbMass                The device to issue commands to
    216   @param  Cmd                    The command to execute
    217   @param  CmdLen                 The length of the command
    218   @param  DataDir                The direction of data transfer
    219   @param  Data                   The buffer to hold the data
    220   @param  DataLen                The length of expected data
    221   @param  Timeout                The timeout used to transfer
    222 
    223   @retval EFI_SUCCESS            The command is executed successfully.
    224   @retval EFI_MEDIA_CHANGED      The device media has been changed.
    225   @retval Others                 Command execution failed after retrial.
    226 
    227 **/
    228 EFI_STATUS
    229 UsbBootExecCmdWithRetry (
    230   IN USB_MASS_DEVICE          *UsbMass,
    231   IN VOID                     *Cmd,
    232   IN UINT8                    CmdLen,
    233   IN EFI_USB_DATA_DIRECTION   DataDir,
    234   IN VOID                     *Data,
    235   IN UINT32                   DataLen,
    236   IN UINT32                   Timeout
    237   )
    238 {
    239   EFI_STATUS                  Status;
    240   UINTN                       Retry;
    241   EFI_EVENT                   TimeoutEvt;
    242 
    243   Retry  = 0;
    244   Status = EFI_SUCCESS;
    245   Status = gBS->CreateEvent (
    246                   EVT_TIMER,
    247                   TPL_CALLBACK,
    248                   NULL,
    249                   NULL,
    250                   &TimeoutEvt
    251                   );
    252   if (EFI_ERROR (Status)) {
    253     return Status;
    254   }
    255 
    256   Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(60));
    257   if (EFI_ERROR (Status)) {
    258     goto EXIT;
    259   }
    260 
    261   //
    262   // Execute the cmd and retry if it fails.
    263   //
    264   while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
    265     Status = UsbBootExecCmd (
    266                UsbMass,
    267                Cmd,
    268                CmdLen,
    269                DataDir,
    270                Data,
    271                DataLen,
    272                Timeout
    273                );
    274     if (Status == EFI_SUCCESS || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {
    275       break;
    276     }
    277     //
    278     // If the sense data shows the drive is not ready, we need execute the cmd again.
    279     // We limit the upper boundary to 60 seconds.
    280     //
    281     if (Status == EFI_NOT_READY) {
    282       continue;
    283     }
    284     //
    285     // If the status is other error, then just retry 5 times.
    286     //
    287     if (Retry++ >= USB_BOOT_COMMAND_RETRY) {
    288       break;
    289     }
    290   }
    291 
    292 EXIT:
    293   if (TimeoutEvt != NULL) {
    294     gBS->CloseEvent (TimeoutEvt);
    295   }
    296 
    297   return Status;
    298 }
    299 
    300 
    301 /**
    302   Execute TEST UNIT READY command to check if the device is ready.
    303 
    304   @param  UsbMass                The device to test
    305 
    306   @retval EFI_SUCCESS            The device is ready.
    307   @retval Others                 Device not ready.
    308 
    309 **/
    310 EFI_STATUS
    311 UsbBootIsUnitReady (
    312   IN USB_MASS_DEVICE            *UsbMass
    313   )
    314 {
    315   USB_BOOT_TEST_UNIT_READY_CMD  TestCmd;
    316 
    317   ZeroMem (&TestCmd, sizeof (USB_BOOT_TEST_UNIT_READY_CMD));
    318 
    319   TestCmd.OpCode  = USB_BOOT_TEST_UNIT_READY_OPCODE;
    320   TestCmd.Lun     = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
    321 
    322   return UsbBootExecCmdWithRetry (
    323            UsbMass,
    324            &TestCmd,
    325            (UINT8) sizeof (USB_BOOT_TEST_UNIT_READY_CMD),
    326            EfiUsbNoData,
    327            NULL,
    328            0,
    329            USB_BOOT_GENERAL_CMD_TIMEOUT
    330            );
    331 }
    332 
    333 
    334 /**
    335   Execute INQUIRY Command to request information regarding parameters of
    336   the device be sent to the host computer.
    337 
    338   @param  UsbMass                The device to inquire.
    339 
    340   @retval EFI_SUCCESS            INQUIRY Command is executed successfully.
    341   @retval Others                 INQUIRY Command is not executed successfully.
    342 
    343 **/
    344 EFI_STATUS
    345 UsbBootInquiry (
    346   IN USB_MASS_DEVICE            *UsbMass
    347   )
    348 {
    349   USB_BOOT_INQUIRY_CMD        InquiryCmd;
    350   EFI_BLOCK_IO_MEDIA          *Media;
    351   EFI_STATUS                  Status;
    352 
    353   Media = &(UsbMass->BlockIoMedia);
    354 
    355   ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD));
    356   ZeroMem (&UsbMass->InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));
    357 
    358   InquiryCmd.OpCode   = USB_BOOT_INQUIRY_OPCODE;
    359   InquiryCmd.Lun      = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
    360   InquiryCmd.AllocLen = (UINT8) sizeof (USB_BOOT_INQUIRY_DATA);
    361 
    362   Status = UsbBootExecCmdWithRetry (
    363              UsbMass,
    364              &InquiryCmd,
    365              (UINT8) sizeof (USB_BOOT_INQUIRY_CMD),
    366              EfiUsbDataIn,
    367              &UsbMass->InquiryData,
    368              sizeof (USB_BOOT_INQUIRY_DATA),
    369              USB_BOOT_GENERAL_CMD_TIMEOUT
    370              );
    371   if (EFI_ERROR (Status)) {
    372     return Status;
    373   }
    374 
    375   //
    376   // Get information from PDT (Peripheral Device Type) field and Removable Medium Bit
    377   // from the inquiry data.
    378   //
    379   UsbMass->Pdt          = (UINT8) (USB_BOOT_PDT (UsbMass->InquiryData.Pdt));
    380   Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (UsbMass->InquiryData.Removable));
    381   //
    382   // Set block size to the default value of 512 Bytes, in case no media is present at first time.
    383   //
    384   Media->BlockSize      = 0x0200;
    385 
    386   return Status;
    387 }
    388 
    389 /**
    390   Execute READ CAPACITY 16 bytes command to request information regarding
    391   the capacity of the installed medium of the device.
    392 
    393   This function executes READ CAPACITY 16 bytes command to get the capacity
    394   of the USB mass storage media, including the presence, block size,
    395   and last block number.
    396 
    397   @param  UsbMass                The device to retireve disk gemotric.
    398 
    399   @retval EFI_SUCCESS            The disk geometry is successfully retrieved.
    400   @retval EFI_NOT_READY          The returned block size is zero.
    401   @retval Other                  READ CAPACITY 16 bytes command execution failed.
    402 
    403 **/
    404 EFI_STATUS
    405 UsbBootReadCapacity16 (
    406   IN USB_MASS_DEVICE            *UsbMass
    407   )
    408 {
    409   UINT8                         CapacityCmd[16];
    410   EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData;
    411   EFI_BLOCK_IO_MEDIA            *Media;
    412   EFI_STATUS                    Status;
    413   UINT32                        BlockSize;
    414 
    415   Media   = &UsbMass->BlockIoMedia;
    416 
    417   Media->MediaPresent = FALSE;
    418   Media->LastBlock    = 0;
    419   Media->BlockSize    = 0;
    420 
    421   ZeroMem (CapacityCmd, sizeof (CapacityCmd));
    422   ZeroMem (&CapacityData, sizeof (CapacityData));
    423 
    424   CapacityCmd[0]  = EFI_SCSI_OP_READ_CAPACITY16;
    425   CapacityCmd[1]  = 0x10;
    426   //
    427   // Partial medium indicator, set the bytes 2 ~ 9 of the Cdb as ZERO.
    428   //
    429   ZeroMem ((CapacityCmd + 2), 8);
    430 
    431   CapacityCmd[13] = sizeof (CapacityData);
    432 
    433   Status = UsbBootExecCmdWithRetry (
    434              UsbMass,
    435              CapacityCmd,
    436              (UINT8) sizeof (CapacityCmd),
    437              EfiUsbDataIn,
    438              &CapacityData,
    439              sizeof (CapacityData),
    440              USB_BOOT_GENERAL_CMD_TIMEOUT
    441              );
    442   if (EFI_ERROR (Status)) {
    443     return Status;
    444   }
    445 
    446   //
    447   // Get the information on media presence, block size, and last block number
    448   // from READ CAPACITY data.
    449   //
    450   Media->MediaPresent = TRUE;
    451   Media->LastBlock    = SwapBytes64 (ReadUnaligned64 ((CONST UINT64 *) &(CapacityData.LastLba7)));
    452 
    453   BlockSize           = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) &(CapacityData.BlockSize3)));
    454 
    455   Media->LowestAlignedLba = (CapacityData.LowestAlignLogic2 << 8) |
    456                              CapacityData.LowestAlignLogic1;
    457   Media->LogicalBlocksPerPhysicalBlock  = (1 << CapacityData.LogicPerPhysical);
    458   if (BlockSize == 0) {
    459     //
    460     //  Get sense data
    461     //
    462     return UsbBootRequestSense (UsbMass);
    463   } else {
    464     Media->BlockSize = BlockSize;
    465   }
    466 
    467   return Status;
    468 }
    469 
    470 
    471 /**
    472   Execute READ CAPACITY command to request information regarding
    473   the capacity of the installed medium of the device.
    474 
    475   This function executes READ CAPACITY command to get the capacity
    476   of the USB mass storage media, including the presence, block size,
    477   and last block number.
    478 
    479   @param  UsbMass                The device to retireve disk gemotric.
    480 
    481   @retval EFI_SUCCESS            The disk geometry is successfully retrieved.
    482   @retval EFI_NOT_READY          The returned block size is zero.
    483   @retval Other                  READ CAPACITY command execution failed.
    484 
    485 **/
    486 EFI_STATUS
    487 UsbBootReadCapacity (
    488   IN USB_MASS_DEVICE          *UsbMass
    489   )
    490 {
    491   USB_BOOT_READ_CAPACITY_CMD  CapacityCmd;
    492   USB_BOOT_READ_CAPACITY_DATA CapacityData;
    493   EFI_BLOCK_IO_MEDIA          *Media;
    494   EFI_STATUS                  Status;
    495   UINT32                      BlockSize;
    496 
    497   Media   = &UsbMass->BlockIoMedia;
    498 
    499   ZeroMem (&CapacityCmd, sizeof (USB_BOOT_READ_CAPACITY_CMD));
    500   ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA));
    501 
    502   CapacityCmd.OpCode = USB_BOOT_READ_CAPACITY_OPCODE;
    503   CapacityCmd.Lun    = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
    504 
    505   Status = UsbBootExecCmdWithRetry (
    506              UsbMass,
    507              &CapacityCmd,
    508              (UINT8) sizeof (USB_BOOT_READ_CAPACITY_CMD),
    509              EfiUsbDataIn,
    510              &CapacityData,
    511              sizeof (USB_BOOT_READ_CAPACITY_DATA),
    512              USB_BOOT_GENERAL_CMD_TIMEOUT
    513              );
    514   if (EFI_ERROR (Status)) {
    515     return Status;
    516   }
    517 
    518   //
    519   // Get the information on media presence, block size, and last block number
    520   // from READ CAPACITY data.
    521   //
    522   Media->MediaPresent = TRUE;
    523   Media->LastBlock    = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.LastLba));
    524 
    525   BlockSize           = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.BlockLen));
    526   if (BlockSize == 0) {
    527     //
    528     //  Get sense data
    529     //
    530     return UsbBootRequestSense (UsbMass);
    531   } else {
    532     Media->BlockSize = BlockSize;
    533   }
    534 
    535   if (Media->LastBlock == 0xFFFFFFFF) {
    536     Status = UsbBootReadCapacity16 (UsbMass);
    537     if (!EFI_ERROR (Status)) {
    538       UsbMass->Cdb16Byte = TRUE;
    539     }
    540   }
    541 
    542   return Status;
    543 }
    544 
    545 /**
    546   Retrieves SCSI mode sense information via MODE SENSE(6) command.
    547 
    548   @param  UsbMass                The device whose sense data is requested.
    549 
    550   @retval EFI_SUCCESS            SCSI mode sense information retrieved successfully.
    551   @retval Other                  Command execution failed.
    552 
    553 **/
    554 EFI_STATUS
    555 UsbScsiModeSense (
    556   IN USB_MASS_DEVICE          *UsbMass
    557   )
    558 {
    559   EFI_STATUS                       Status;
    560   USB_SCSI_MODE_SENSE6_CMD         ModeSenseCmd;
    561   USB_SCSI_MODE_SENSE6_PARA_HEADER ModeParaHeader;
    562   EFI_BLOCK_IO_MEDIA               *Media;
    563 
    564   Media   = &UsbMass->BlockIoMedia;
    565 
    566   ZeroMem (&ModeSenseCmd, sizeof (USB_SCSI_MODE_SENSE6_CMD));
    567   ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER));
    568 
    569   //
    570   // MODE SENSE(6) command is defined in Section 8.2.10 of SCSI-2 Spec
    571   //
    572   ModeSenseCmd.OpCode         = USB_SCSI_MODE_SENSE6_OPCODE;
    573   ModeSenseCmd.Lun            = (UINT8) USB_BOOT_LUN (UsbMass->Lun);
    574   ModeSenseCmd.PageCode       = 0x3F;
    575   ModeSenseCmd.AllocateLen    = (UINT8) sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER);
    576 
    577   Status = UsbBootExecCmdWithRetry (
    578              UsbMass,
    579              &ModeSenseCmd,
    580              (UINT8) sizeof (USB_SCSI_MODE_SENSE6_CMD),
    581              EfiUsbDataIn,
    582              &ModeParaHeader,
    583              sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER),
    584              USB_BOOT_GENERAL_CMD_TIMEOUT
    585              );
    586 
    587   //
    588   // Format of device-specific parameter byte of the mode parameter header is defined in
    589   // Section 8.2.10 of SCSI-2 Spec.
    590   // BIT7 of this byte is indicates whether the medium is write protected.
    591   //
    592   if (!EFI_ERROR (Status)) {
    593     Media->ReadOnly = (BOOLEAN) ((ModeParaHeader.DevicePara & BIT7) != 0);
    594   }
    595 
    596   return Status;
    597 }
    598 
    599 
    600 /**
    601   Get the parameters for the USB mass storage media.
    602 
    603   This function get the parameters for the USB mass storage media,
    604   It is used both to initialize the media during the Start() phase
    605   of Driver Binding Protocol and to re-initialize it when the media is
    606   changed. Althought the RemoveableMedia is unlikely to change,
    607   it is also included here.
    608 
    609   @param  UsbMass                The device to retrieve disk gemotric.
    610 
    611   @retval EFI_SUCCESS            The disk gemotric is successfully retrieved.
    612   @retval Other                  Failed to get the parameters.
    613 
    614 **/
    615 EFI_STATUS
    616 UsbBootGetParams (
    617   IN USB_MASS_DEVICE          *UsbMass
    618   )
    619 {
    620   EFI_BLOCK_IO_MEDIA          *Media;
    621   EFI_STATUS                  Status;
    622 
    623   Media  = &(UsbMass->BlockIoMedia);
    624 
    625   Status = UsbBootInquiry (UsbMass);
    626   if (EFI_ERROR (Status)) {
    627     DEBUG ((EFI_D_ERROR, "UsbBootGetParams: UsbBootInquiry (%r)\n", Status));
    628     return Status;
    629   }
    630 
    631   //
    632   // According to USB Mass Storage Specification for Bootability, only following
    633   // 4 Peripheral Device Types are in spec.
    634   //
    635   if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
    636        (UsbMass->Pdt != USB_PDT_CDROM) &&
    637        (UsbMass->Pdt != USB_PDT_OPTICAL) &&
    638        (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
    639     DEBUG ((EFI_D_ERROR, "UsbBootGetParams: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
    640     return EFI_UNSUPPORTED;
    641   }
    642 
    643   //
    644   // Don't use the Removable bit in inquiry data to test whether the media
    645   // is removable because many flash disks wrongly set this bit.
    646   //
    647   if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {
    648     //
    649     // CD-Rom device and Non-CD optical device
    650     //
    651     UsbMass->OpticalStorage = TRUE;
    652     //
    653     // Default value 2048 Bytes, in case no media present at first time
    654     //
    655     Media->BlockSize        = 0x0800;
    656   }
    657 
    658   Status = UsbBootDetectMedia (UsbMass);
    659 
    660   return Status;
    661 }
    662 
    663 
    664 /**
    665   Detect whether the removable media is present and whether it has changed.
    666 
    667   @param  UsbMass                The device to check.
    668 
    669   @retval EFI_SUCCESS            The media status is successfully checked.
    670   @retval Other                  Failed to detect media.
    671 
    672 **/
    673 EFI_STATUS
    674 UsbBootDetectMedia (
    675   IN  USB_MASS_DEVICE       *UsbMass
    676   )
    677 {
    678   EFI_BLOCK_IO_MEDIA        OldMedia;
    679   EFI_BLOCK_IO_MEDIA        *Media;
    680   UINT8                     CmdSet;
    681   EFI_TPL                   OldTpl;
    682   EFI_STATUS                Status;
    683 
    684   Media    = &UsbMass->BlockIoMedia;
    685 
    686   CopyMem (&OldMedia, &(UsbMass->BlockIoMedia), sizeof (EFI_BLOCK_IO_MEDIA));
    687 
    688   CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;
    689 
    690   Status = UsbBootIsUnitReady (UsbMass);
    691   if (EFI_ERROR (Status) && (Status != EFI_MEDIA_CHANGED)) {
    692     goto ON_ERROR;
    693   }
    694 
    695   if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {
    696     //
    697     // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E,
    698     // according to Section 4 of USB Mass Storage Specification for Bootability.
    699     // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI
    700     // could get the information of Write Protected.
    701     // Since not all device support this command, skip if fail.
    702     //
    703     UsbScsiModeSense (UsbMass);
    704   }
    705 
    706   Status = UsbBootReadCapacity (UsbMass);
    707   if (EFI_ERROR (Status)) {
    708     DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status));
    709     goto ON_ERROR;
    710   }
    711 
    712   return EFI_SUCCESS;
    713 
    714 ON_ERROR:
    715   //
    716   // Detect whether it is necessary to reinstall the Block I/O Protocol.
    717   //
    718   // MediaId may change in RequestSense for MediaChanged
    719   // MediaPresent may change in RequestSense for NoMedia
    720   // MediaReadOnly may change in RequestSense for WriteProtected or MediaChanged
    721   // MediaPresent/BlockSize/LastBlock may change in ReadCapacity
    722   //
    723   if ((Media->MediaId != OldMedia.MediaId) ||
    724       (Media->MediaPresent != OldMedia.MediaPresent) ||
    725       (Media->ReadOnly != OldMedia.ReadOnly) ||
    726       (Media->BlockSize != OldMedia.BlockSize) ||
    727       (Media->LastBlock != OldMedia.LastBlock)) {
    728 
    729     //
    730     // This function is called by Block I/O Protocol APIs, which run at TPL_NOTIFY.
    731     // Here we temporarily restore TPL to TPL_CALLBACK to invoke ReinstallProtocolInterface().
    732     //
    733     OldTpl = EfiGetCurrentTpl ();
    734     gBS->RestoreTPL (TPL_CALLBACK);
    735 
    736     gBS->ReinstallProtocolInterface (
    737            UsbMass->Controller,
    738            &gEfiBlockIoProtocolGuid,
    739            &UsbMass->BlockIo,
    740            &UsbMass->BlockIo
    741            );
    742 
    743     ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK);
    744     gBS->RaiseTPL (OldTpl);
    745 
    746     //
    747     // Update MediaId after reinstalling Block I/O Protocol.
    748     //
    749     if (Media->MediaPresent != OldMedia.MediaPresent) {
    750       if (Media->MediaPresent) {
    751         Media->MediaId = 1;
    752       } else {
    753         Media->MediaId = 0;
    754       }
    755     }
    756 
    757     if ((Media->ReadOnly != OldMedia.ReadOnly) ||
    758         (Media->BlockSize != OldMedia.BlockSize) ||
    759         (Media->LastBlock != OldMedia.LastBlock)) {
    760       Media->MediaId++;
    761     }
    762   }
    763 
    764   return Status;
    765 }
    766 
    767 
    768 /**
    769   Read some blocks from the device.
    770 
    771   @param  UsbMass                The USB mass storage device to read from
    772   @param  Lba                    The start block number
    773   @param  TotalBlock             Total block number to read
    774   @param  Buffer                 The buffer to read to
    775 
    776   @retval EFI_SUCCESS            Data are read into the buffer
    777   @retval Others                 Failed to read all the data
    778 
    779 **/
    780 EFI_STATUS
    781 UsbBootReadBlocks (
    782   IN  USB_MASS_DEVICE       *UsbMass,
    783   IN  UINT32                Lba,
    784   IN  UINTN                 TotalBlock,
    785   OUT UINT8                 *Buffer
    786   )
    787 {
    788   USB_BOOT_READ10_CMD       ReadCmd;
    789   EFI_STATUS                Status;
    790   UINT16                    Count;
    791   UINT32                    BlockSize;
    792   UINT32                    ByteSize;
    793   UINT32                    Timeout;
    794 
    795   BlockSize = UsbMass->BlockIoMedia.BlockSize;
    796   Status    = EFI_SUCCESS;
    797 
    798   while (TotalBlock > 0) {
    799     //
    800     // Split the total blocks into smaller pieces to ease the pressure
    801     // on the device. We must split the total block because the READ10
    802     // command only has 16 bit transfer length (in the unit of block).
    803     //
    804     Count     = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);
    805     ByteSize  = (UINT32)Count * BlockSize;
    806 
    807     //
    808     // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
    809     //
    810     Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
    811 
    812     //
    813     // Fill in the command then execute
    814     //
    815     ZeroMem (&ReadCmd, sizeof (USB_BOOT_READ10_CMD));
    816 
    817     ReadCmd.OpCode  = USB_BOOT_READ10_OPCODE;
    818     ReadCmd.Lun     = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
    819     WriteUnaligned32 ((UINT32 *) ReadCmd.Lba, SwapBytes32 (Lba));
    820     WriteUnaligned16 ((UINT16 *) ReadCmd.TransferLen, SwapBytes16 (Count));
    821 
    822     Status = UsbBootExecCmdWithRetry (
    823                UsbMass,
    824                &ReadCmd,
    825                (UINT8) sizeof (USB_BOOT_READ10_CMD),
    826                EfiUsbDataIn,
    827                Buffer,
    828                ByteSize,
    829                Timeout
    830                );
    831     if (EFI_ERROR (Status)) {
    832       return Status;
    833     }
    834     DEBUG ((EFI_D_BLKIO, "UsbBootReadBlocks: LBA (0x%x), Blk (0x%x)\n", Lba, Count));
    835     Lba        += Count;
    836     Buffer     += Count * BlockSize;
    837     TotalBlock -= Count;
    838   }
    839 
    840   return Status;
    841 }
    842 
    843 
    844 /**
    845   Write some blocks to the device.
    846 
    847   @param  UsbMass                The USB mass storage device to write to
    848   @param  Lba                    The start block number
    849   @param  TotalBlock             Total block number to write
    850   @param  Buffer                 Pointer to the source buffer for the data.
    851 
    852   @retval EFI_SUCCESS            Data are written into the buffer
    853   @retval Others                 Failed to write all the data
    854 
    855 **/
    856 EFI_STATUS
    857 UsbBootWriteBlocks (
    858   IN  USB_MASS_DEVICE         *UsbMass,
    859   IN  UINT32                  Lba,
    860   IN  UINTN                   TotalBlock,
    861   IN  UINT8                   *Buffer
    862   )
    863 {
    864   USB_BOOT_WRITE10_CMD  WriteCmd;
    865   EFI_STATUS            Status;
    866   UINT16                Count;
    867   UINT32                BlockSize;
    868   UINT32                ByteSize;
    869   UINT32                Timeout;
    870 
    871   BlockSize = UsbMass->BlockIoMedia.BlockSize;
    872   Status    = EFI_SUCCESS;
    873 
    874   while (TotalBlock > 0) {
    875     //
    876     // Split the total blocks into smaller pieces to ease the pressure
    877     // on the device. We must split the total block because the WRITE10
    878     // command only has 16 bit transfer length (in the unit of block).
    879     //
    880     Count     = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);
    881     ByteSize  = (UINT32)Count * BlockSize;
    882 
    883     //
    884     // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
    885     //
    886     Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
    887 
    888     //
    889     // Fill in the write10 command block
    890     //
    891     ZeroMem (&WriteCmd, sizeof (USB_BOOT_WRITE10_CMD));
    892 
    893     WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE;
    894     WriteCmd.Lun    = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
    895     WriteUnaligned32 ((UINT32 *) WriteCmd.Lba, SwapBytes32 (Lba));
    896     WriteUnaligned16 ((UINT16 *) WriteCmd.TransferLen, SwapBytes16 (Count));
    897 
    898     Status = UsbBootExecCmdWithRetry (
    899                UsbMass,
    900                &WriteCmd,
    901                (UINT8) sizeof (USB_BOOT_WRITE10_CMD),
    902                EfiUsbDataOut,
    903                Buffer,
    904                ByteSize,
    905                Timeout
    906                );
    907     if (EFI_ERROR (Status)) {
    908       return Status;
    909     }
    910     DEBUG ((EFI_D_BLKIO, "UsbBootWriteBlocks: LBA (0x%x), Blk (0x%x)\n", Lba, Count));
    911 
    912     Lba        += Count;
    913     Buffer     += Count * BlockSize;
    914     TotalBlock -= Count;
    915   }
    916 
    917   return Status;
    918 }
    919 
    920 /**
    921   Read some blocks from the device by SCSI 16 byte cmd.
    922 
    923   @param  UsbMass                The USB mass storage device to read from
    924   @param  Lba                    The start block number
    925   @param  TotalBlock             Total block number to read
    926   @param  Buffer                 The buffer to read to
    927 
    928   @retval EFI_SUCCESS            Data are read into the buffer
    929   @retval Others                 Failed to read all the data
    930 
    931 **/
    932 EFI_STATUS
    933 UsbBootReadBlocks16 (
    934   IN  USB_MASS_DEVICE       *UsbMass,
    935   IN  UINT64                Lba,
    936   IN  UINTN                 TotalBlock,
    937   OUT UINT8                 *Buffer
    938   )
    939 {
    940   UINT8                     ReadCmd[16];
    941   EFI_STATUS                Status;
    942   UINT16                    Count;
    943   UINT32                    BlockSize;
    944   UINT32                    ByteSize;
    945   UINT32                    Timeout;
    946 
    947   BlockSize = UsbMass->BlockIoMedia.BlockSize;
    948   Status    = EFI_SUCCESS;
    949 
    950   while (TotalBlock > 0) {
    951     //
    952     // Split the total blocks into smaller pieces.
    953     //
    954     Count     = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);
    955     ByteSize  = (UINT32)Count * BlockSize;
    956 
    957     //
    958     // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
    959     //
    960     Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
    961 
    962     //
    963     // Fill in the command then execute
    964     //
    965     ZeroMem (ReadCmd, sizeof (ReadCmd));
    966 
    967     ReadCmd[0]  = EFI_SCSI_OP_READ16;
    968     ReadCmd[1]  = (UINT8) ((USB_BOOT_LUN (UsbMass->Lun) & 0xE0));
    969     WriteUnaligned64 ((UINT64 *) &ReadCmd[2], SwapBytes64 (Lba));
    970     WriteUnaligned32 ((UINT32 *) &ReadCmd[10], SwapBytes32 (Count));
    971 
    972     Status = UsbBootExecCmdWithRetry (
    973                UsbMass,
    974                ReadCmd,
    975                (UINT8) sizeof (ReadCmd),
    976                EfiUsbDataIn,
    977                Buffer,
    978                ByteSize,
    979                Timeout
    980                );
    981     if (EFI_ERROR (Status)) {
    982       return Status;
    983     }
    984     DEBUG ((EFI_D_BLKIO, "UsbBootReadBlocks16: LBA (0x%lx), Blk (0x%x)\n", Lba, Count));
    985     Lba        += Count;
    986     Buffer     += Count * BlockSize;
    987     TotalBlock -= Count;
    988   }
    989 
    990   return Status;
    991 }
    992 
    993 
    994 /**
    995   Write some blocks to the device by SCSI 16 byte cmd.
    996 
    997   @param  UsbMass                The USB mass storage device to write to
    998   @param  Lba                    The start block number
    999   @param  TotalBlock             Total block number to write
   1000   @param  Buffer                 Pointer to the source buffer for the data.
   1001 
   1002   @retval EFI_SUCCESS            Data are written into the buffer
   1003   @retval Others                 Failed to write all the data
   1004 
   1005 **/
   1006 EFI_STATUS
   1007 UsbBootWriteBlocks16 (
   1008   IN  USB_MASS_DEVICE         *UsbMass,
   1009   IN  UINT64                  Lba,
   1010   IN  UINTN                   TotalBlock,
   1011   IN  UINT8                   *Buffer
   1012   )
   1013 {
   1014   UINT8                 WriteCmd[16];
   1015   EFI_STATUS            Status;
   1016   UINT16                Count;
   1017   UINT32                BlockSize;
   1018   UINT32                ByteSize;
   1019   UINT32                Timeout;
   1020 
   1021   BlockSize = UsbMass->BlockIoMedia.BlockSize;
   1022   Status    = EFI_SUCCESS;
   1023 
   1024   while (TotalBlock > 0) {
   1025     //
   1026     // Split the total blocks into smaller pieces.
   1027     //
   1028     Count     = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);
   1029     ByteSize  = (UINT32)Count * BlockSize;
   1030 
   1031     //
   1032     // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
   1033     //
   1034     Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
   1035 
   1036     //
   1037     // Fill in the write16 command block
   1038     //
   1039     ZeroMem (WriteCmd, sizeof (WriteCmd));
   1040 
   1041     WriteCmd[0]  = EFI_SCSI_OP_WRITE16;
   1042     WriteCmd[1]  = (UINT8) ((USB_BOOT_LUN (UsbMass->Lun) & 0xE0));
   1043     WriteUnaligned64 ((UINT64 *) &WriteCmd[2], SwapBytes64 (Lba));
   1044     WriteUnaligned32 ((UINT32 *) &WriteCmd[10], SwapBytes32 (Count));
   1045 
   1046     Status = UsbBootExecCmdWithRetry (
   1047                UsbMass,
   1048                WriteCmd,
   1049                (UINT8) sizeof (WriteCmd),
   1050                EfiUsbDataOut,
   1051                Buffer,
   1052                ByteSize,
   1053                Timeout
   1054                );
   1055     if (EFI_ERROR (Status)) {
   1056       return Status;
   1057     }
   1058     DEBUG ((EFI_D_BLKIO, "UsbBootWriteBlocks: LBA (0x%lx), Blk (0x%x)\n", Lba, Count));
   1059     Lba        += Count;
   1060     Buffer     += Count * BlockSize;
   1061     TotalBlock -= Count;
   1062   }
   1063 
   1064   return Status;
   1065 }
   1066 
   1067 /**
   1068   Use the USB clear feature control transfer to clear the endpoint stall condition.
   1069 
   1070   @param  UsbIo                  The USB I/O Protocol instance
   1071   @param  EndpointAddr           The endpoint to clear stall for
   1072 
   1073   @retval EFI_SUCCESS            The endpoint stall condition is cleared.
   1074   @retval Others                 Failed to clear the endpoint stall condition.
   1075 
   1076 **/
   1077 EFI_STATUS
   1078 UsbClearEndpointStall (
   1079   IN EFI_USB_IO_PROTOCOL    *UsbIo,
   1080   IN UINT8                  EndpointAddr
   1081   )
   1082 {
   1083   EFI_USB_DEVICE_REQUEST    Request;
   1084   EFI_STATUS                Status;
   1085   UINT32                    CmdResult;
   1086   UINT32                    Timeout;
   1087 
   1088   Request.RequestType = 0x02;
   1089   Request.Request     = USB_REQ_CLEAR_FEATURE;
   1090   Request.Value       = USB_FEATURE_ENDPOINT_HALT;
   1091   Request.Index       = EndpointAddr;
   1092   Request.Length      = 0;
   1093   Timeout             = USB_BOOT_GENERAL_CMD_TIMEOUT / USB_MASS_1_MILLISECOND;
   1094 
   1095   Status = UsbIo->UsbControlTransfer (
   1096                     UsbIo,
   1097                     &Request,
   1098                     EfiUsbNoData,
   1099                     Timeout,
   1100                     NULL,
   1101                     0,
   1102                     &CmdResult
   1103                     );
   1104 
   1105   return Status;
   1106 }
   1107