Home | History | Annotate | Download | only in ScsiDiskDxe
      1 /** @file
      2   SCSI disk driver that layers on every SCSI IO protocol in the system.
      3 
      4 Copyright (c) 2006 - 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 
     16 #include "ScsiDisk.h"
     17 
     18 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {
     19   ScsiDiskDriverBindingSupported,
     20   ScsiDiskDriverBindingStart,
     21   ScsiDiskDriverBindingStop,
     22   0xa,
     23   NULL,
     24   NULL
     25 };
     26 
     27 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = {
     28   EFI_DISK_INFO_SCSI_INTERFACE_GUID,
     29   ScsiDiskInfoInquiry,
     30   ScsiDiskInfoIdentify,
     31   ScsiDiskInfoSenseData,
     32   ScsiDiskInfoWhichIde
     33 };
     34 
     35 /**
     36   Allocates an aligned buffer for SCSI disk.
     37 
     38   This function allocates an aligned buffer for the SCSI disk to perform
     39   SCSI IO operations. The alignment requirement is from SCSI IO interface.
     40 
     41   @param  ScsiDiskDevice    The SCSI disk involved for the operation.
     42   @param  BufferSize        The request buffer size.
     43 
     44   @return A pointer to the aligned buffer or NULL if the allocation fails.
     45 
     46 **/
     47 VOID *
     48 AllocateAlignedBuffer (
     49   IN SCSI_DISK_DEV            *ScsiDiskDevice,
     50   IN UINTN                    BufferSize
     51   )
     52 {
     53   return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiDiskDevice->ScsiIo->IoAlign);
     54 }
     55 
     56 /**
     57   Frees an aligned buffer for SCSI disk.
     58 
     59   This function frees an aligned buffer for the SCSI disk to perform
     60   SCSI IO operations.
     61 
     62   @param  Buffer            The aligned buffer to be freed.
     63   @param  BufferSize        The request buffer size.
     64 
     65 **/
     66 VOID
     67 FreeAlignedBuffer (
     68   IN VOID                     *Buffer,
     69   IN UINTN                    BufferSize
     70   )
     71 {
     72   if (Buffer != NULL) {
     73     FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
     74   }
     75 }
     76 
     77 /**
     78   The user Entry Point for module ScsiDisk.
     79 
     80   The user code starts with this function.
     81 
     82   @param  ImageHandle    The firmware allocated handle for the EFI image.
     83   @param  SystemTable    A pointer to the EFI System Table.
     84 
     85   @retval EFI_SUCCESS       The entry point is executed successfully.
     86   @retval other             Some error occurs when executing this entry point.
     87 
     88 **/
     89 EFI_STATUS
     90 EFIAPI
     91 InitializeScsiDisk(
     92   IN EFI_HANDLE           ImageHandle,
     93   IN EFI_SYSTEM_TABLE     *SystemTable
     94   )
     95 {
     96   EFI_STATUS              Status;
     97 
     98   //
     99   // Install driver model protocol(s).
    100   //
    101   Status = EfiLibInstallDriverBindingComponentName2 (
    102              ImageHandle,
    103              SystemTable,
    104              &gScsiDiskDriverBinding,
    105              ImageHandle,
    106              &gScsiDiskComponentName,
    107              &gScsiDiskComponentName2
    108              );
    109   ASSERT_EFI_ERROR (Status);
    110 
    111 
    112   return Status;
    113 }
    114 
    115 /**
    116   Test to see if this driver supports ControllerHandle.
    117 
    118   This service is called by the EFI boot service ConnectController(). In order
    119   to make drivers as small as possible, there are a few calling restrictions for
    120   this service. ConnectController() must follow these calling restrictions.
    121   If any other agent wishes to call Supported() it must also follow these
    122   calling restrictions.
    123 
    124   @param  This                Protocol instance pointer.
    125   @param  ControllerHandle    Handle of device to test
    126   @param  RemainingDevicePath Optional parameter use to pick a specific child
    127                               device to start.
    128 
    129   @retval EFI_SUCCESS         This driver supports this device
    130   @retval EFI_ALREADY_STARTED This driver is already running on this device
    131   @retval other               This driver does not support this device
    132 
    133 **/
    134 EFI_STATUS
    135 EFIAPI
    136 ScsiDiskDriverBindingSupported (
    137   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    138   IN EFI_HANDLE                   Controller,
    139   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL
    140   )
    141 {
    142   EFI_STATUS            Status;
    143   EFI_SCSI_IO_PROTOCOL  *ScsiIo;
    144   UINT8                 DeviceType;
    145 
    146   Status = gBS->OpenProtocol (
    147                   Controller,
    148                   &gEfiScsiIoProtocolGuid,
    149                   (VOID **) &ScsiIo,
    150                   This->DriverBindingHandle,
    151                   Controller,
    152                   EFI_OPEN_PROTOCOL_BY_DRIVER
    153                   );
    154   if (EFI_ERROR (Status)) {
    155     return Status;
    156   }
    157 
    158   Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);
    159   if (!EFI_ERROR (Status)) {
    160     if ((DeviceType == EFI_SCSI_TYPE_DISK) || (DeviceType == EFI_SCSI_TYPE_CDROM)) {
    161       Status = EFI_SUCCESS;
    162     } else {
    163       Status = EFI_UNSUPPORTED;
    164     }
    165   }
    166 
    167   gBS->CloseProtocol (
    168          Controller,
    169          &gEfiScsiIoProtocolGuid,
    170          This->DriverBindingHandle,
    171          Controller
    172          );
    173   return Status;
    174 }
    175 
    176 
    177 /**
    178   Start this driver on ControllerHandle.
    179 
    180   This service is called by the EFI boot service ConnectController(). In order
    181   to make drivers as small as possible, there are a few calling restrictions for
    182   this service. ConnectController() must follow these calling restrictions. If
    183   any other agent wishes to call Start() it must also follow these calling
    184   restrictions.
    185 
    186   @param  This                 Protocol instance pointer.
    187   @param  ControllerHandle     Handle of device to bind driver to
    188   @param  RemainingDevicePath  Optional parameter use to pick a specific child
    189                                device to start.
    190 
    191   @retval EFI_SUCCESS          This driver is added to ControllerHandle
    192   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
    193   @retval other                This driver does not support this device
    194 
    195 **/
    196 EFI_STATUS
    197 EFIAPI
    198 ScsiDiskDriverBindingStart (
    199   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    200   IN EFI_HANDLE                   Controller,
    201   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL
    202   )
    203 {
    204   EFI_STATUS            Status;
    205   EFI_SCSI_IO_PROTOCOL  *ScsiIo;
    206   SCSI_DISK_DEV         *ScsiDiskDevice;
    207   BOOLEAN               Temp;
    208   UINT8                 Index;
    209   UINT8                 MaxRetry;
    210   BOOLEAN               NeedRetry;
    211   BOOLEAN               MustReadCapacity;
    212 
    213   MustReadCapacity = TRUE;
    214 
    215   ScsiDiskDevice = (SCSI_DISK_DEV *) AllocateZeroPool (sizeof (SCSI_DISK_DEV));
    216   if (ScsiDiskDevice == NULL) {
    217     return EFI_OUT_OF_RESOURCES;
    218   }
    219 
    220   Status = gBS->OpenProtocol (
    221                   Controller,
    222                   &gEfiScsiIoProtocolGuid,
    223                   (VOID **) &ScsiIo,
    224                   This->DriverBindingHandle,
    225                   Controller,
    226                   EFI_OPEN_PROTOCOL_BY_DRIVER
    227                   );
    228   if (EFI_ERROR (Status)) {
    229     FreePool (ScsiDiskDevice);
    230     return Status;
    231   }
    232 
    233   ScsiDiskDevice->Signature            = SCSI_DISK_DEV_SIGNATURE;
    234   ScsiDiskDevice->ScsiIo               = ScsiIo;
    235   ScsiDiskDevice->BlkIo.Revision       = EFI_BLOCK_IO_PROTOCOL_REVISION3;
    236   ScsiDiskDevice->BlkIo.Media          = &ScsiDiskDevice->BlkIoMedia;
    237   ScsiDiskDevice->BlkIo.Media->IoAlign = ScsiIo->IoAlign;
    238   ScsiDiskDevice->BlkIo.Reset          = ScsiDiskReset;
    239   ScsiDiskDevice->BlkIo.ReadBlocks     = ScsiDiskReadBlocks;
    240   ScsiDiskDevice->BlkIo.WriteBlocks    = ScsiDiskWriteBlocks;
    241   ScsiDiskDevice->BlkIo.FlushBlocks    = ScsiDiskFlushBlocks;
    242   ScsiDiskDevice->BlkIo2.Media         = &ScsiDiskDevice->BlkIoMedia;
    243   ScsiDiskDevice->BlkIo2.Reset         = ScsiDiskResetEx;
    244   ScsiDiskDevice->BlkIo2.ReadBlocksEx  = ScsiDiskReadBlocksEx;
    245   ScsiDiskDevice->BlkIo2.WriteBlocksEx = ScsiDiskWriteBlocksEx;
    246   ScsiDiskDevice->BlkIo2.FlushBlocksEx = ScsiDiskFlushBlocksEx;
    247   ScsiDiskDevice->Handle               = Controller;
    248   InitializeListHead (&ScsiDiskDevice->BlkIo2Queue);
    249 
    250   ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));
    251   switch (ScsiDiskDevice->DeviceType) {
    252   case EFI_SCSI_TYPE_DISK:
    253     ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;
    254     MustReadCapacity = TRUE;
    255     break;
    256 
    257   case EFI_SCSI_TYPE_CDROM:
    258     ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;
    259     ScsiDiskDevice->BlkIo.Media->ReadOnly  = TRUE;
    260     MustReadCapacity = FALSE;
    261     break;
    262   }
    263   //
    264   // The Sense Data Array's initial size is 6
    265   //
    266   ScsiDiskDevice->SenseDataNumber = 6;
    267   ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *) AllocateZeroPool (
    268                                  sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber
    269                                  );
    270   if (ScsiDiskDevice->SenseData == NULL) {
    271     gBS->CloseProtocol (
    272           Controller,
    273           &gEfiScsiIoProtocolGuid,
    274           This->DriverBindingHandle,
    275           Controller
    276           );
    277     FreePool (ScsiDiskDevice);
    278     return EFI_OUT_OF_RESOURCES;
    279   }
    280 
    281   //
    282   // Retrieve device information
    283   //
    284   MaxRetry = 2;
    285   for (Index = 0; Index < MaxRetry; Index++) {
    286     Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);
    287     if (!EFI_ERROR (Status)) {
    288       break;
    289     }
    290 
    291     if (!NeedRetry) {
    292       FreePool (ScsiDiskDevice->SenseData);
    293       gBS->CloseProtocol (
    294              Controller,
    295              &gEfiScsiIoProtocolGuid,
    296              This->DriverBindingHandle,
    297              Controller
    298              );
    299       FreePool (ScsiDiskDevice);
    300       return EFI_DEVICE_ERROR;
    301     }
    302   }
    303   //
    304   // The second parameter "TRUE" means must
    305   // retrieve media capacity
    306   //
    307   Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);
    308   if (!EFI_ERROR (Status)) {
    309     //
    310     // Determine if Block IO & Block IO2 should be produced on this controller
    311     // handle
    312     //
    313     if (DetermineInstallBlockIo(Controller)) {
    314       InitializeInstallDiskInfo(ScsiDiskDevice, Controller);
    315       Status = gBS->InstallMultipleProtocolInterfaces (
    316                       &Controller,
    317                       &gEfiBlockIoProtocolGuid,
    318                       &ScsiDiskDevice->BlkIo,
    319                       &gEfiBlockIo2ProtocolGuid,
    320                       &ScsiDiskDevice->BlkIo2,
    321                       &gEfiDiskInfoProtocolGuid,
    322                       &ScsiDiskDevice->DiskInfo,
    323                       NULL
    324                       );
    325       if (!EFI_ERROR(Status)) {
    326         ScsiDiskDevice->ControllerNameTable = NULL;
    327         AddUnicodeString2 (
    328           "eng",
    329           gScsiDiskComponentName.SupportedLanguages,
    330           &ScsiDiskDevice->ControllerNameTable,
    331           L"SCSI Disk Device",
    332           TRUE
    333           );
    334         AddUnicodeString2 (
    335           "en",
    336           gScsiDiskComponentName2.SupportedLanguages,
    337           &ScsiDiskDevice->ControllerNameTable,
    338           L"SCSI Disk Device",
    339           FALSE
    340           );
    341         return EFI_SUCCESS;
    342       }
    343     }
    344   }
    345 
    346   gBS->FreePool (ScsiDiskDevice->SenseData);
    347   gBS->FreePool (ScsiDiskDevice);
    348   gBS->CloseProtocol (
    349          Controller,
    350          &gEfiScsiIoProtocolGuid,
    351          This->DriverBindingHandle,
    352          Controller
    353          );
    354   return Status;
    355 
    356 }
    357 
    358 
    359 /**
    360   Stop this driver on ControllerHandle.
    361 
    362   This service is called by the EFI boot service DisconnectController().
    363   In order to make drivers as small as possible, there are a few calling
    364   restrictions for this service. DisconnectController() must follow these
    365   calling restrictions. If any other agent wishes to call Stop() it must
    366   also follow these calling restrictions.
    367 
    368   @param  This              Protocol instance pointer.
    369   @param  ControllerHandle  Handle of device to stop driver on
    370   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
    371                             children is zero stop the entire bus driver.
    372   @param  ChildHandleBuffer List of Child Handles to Stop.
    373 
    374   @retval EFI_SUCCESS       This driver is removed ControllerHandle
    375   @retval other             This driver was not removed from this device
    376 
    377 **/
    378 EFI_STATUS
    379 EFIAPI
    380 ScsiDiskDriverBindingStop (
    381   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
    382   IN  EFI_HANDLE                      Controller,
    383   IN  UINTN                           NumberOfChildren,
    384   IN  EFI_HANDLE                      *ChildHandleBuffer   OPTIONAL
    385   )
    386 {
    387   EFI_BLOCK_IO_PROTOCOL *BlkIo;
    388   SCSI_DISK_DEV         *ScsiDiskDevice;
    389   EFI_STATUS            Status;
    390 
    391   Status = gBS->OpenProtocol (
    392                   Controller,
    393                   &gEfiBlockIoProtocolGuid,
    394                   (VOID **) &BlkIo,
    395                   This->DriverBindingHandle,
    396                   Controller,
    397                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    398                   );
    399   if (EFI_ERROR (Status)) {
    400     return Status;
    401   }
    402 
    403   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlkIo);
    404 
    405   //
    406   // Wait for the BlockIo2 requests queue to become empty
    407   //
    408   while (!IsListEmpty (&ScsiDiskDevice->BlkIo2Queue));
    409 
    410   Status = gBS->UninstallMultipleProtocolInterfaces (
    411                   Controller,
    412                   &gEfiBlockIoProtocolGuid,
    413                   &ScsiDiskDevice->BlkIo,
    414                   &gEfiBlockIo2ProtocolGuid,
    415                   &ScsiDiskDevice->BlkIo2,
    416                   &gEfiDiskInfoProtocolGuid,
    417                   &ScsiDiskDevice->DiskInfo,
    418                   NULL
    419                   );
    420   if (!EFI_ERROR (Status)) {
    421     gBS->CloseProtocol (
    422            Controller,
    423            &gEfiScsiIoProtocolGuid,
    424            This->DriverBindingHandle,
    425            Controller
    426            );
    427 
    428     ReleaseScsiDiskDeviceResources (ScsiDiskDevice);
    429 
    430     return EFI_SUCCESS;
    431   }
    432   //
    433   // errors met
    434   //
    435   return Status;
    436 }
    437 
    438 /**
    439   Reset SCSI Disk.
    440 
    441 
    442   @param  This                 The pointer of EFI_BLOCK_IO_PROTOCOL
    443   @param  ExtendedVerification The flag about if extend verificate
    444 
    445   @retval EFI_SUCCESS          The device was reset.
    446   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
    447                                not be reset.
    448   @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
    449 
    450 **/
    451 EFI_STATUS
    452 EFIAPI
    453 ScsiDiskReset (
    454   IN  EFI_BLOCK_IO_PROTOCOL   *This,
    455   IN  BOOLEAN                 ExtendedVerification
    456   )
    457 {
    458   EFI_TPL       OldTpl;
    459   SCSI_DISK_DEV *ScsiDiskDevice;
    460   EFI_STATUS    Status;
    461 
    462   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    463 
    464   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_BLKIO (This);
    465 
    466   Status          = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
    467 
    468   if (EFI_ERROR (Status)) {
    469     Status = EFI_DEVICE_ERROR;
    470     goto Done;
    471   }
    472 
    473   if (!ExtendedVerification) {
    474     goto Done;
    475   }
    476 
    477   Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
    478 
    479   if (EFI_ERROR (Status)) {
    480     Status = EFI_DEVICE_ERROR;
    481     goto Done;
    482   }
    483 
    484 Done:
    485   gBS->RestoreTPL (OldTpl);
    486   return Status;
    487 }
    488 
    489 /**
    490   The function is to Read Block from SCSI Disk.
    491 
    492   @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL.
    493   @param  MediaId    The Id of Media detected
    494   @param  Lba        The logic block address
    495   @param  BufferSize The size of Buffer
    496   @param  Buffer     The buffer to fill the read out data
    497 
    498   @retval EFI_SUCCESS           Successfully to read out block.
    499   @retval EFI_DEVICE_ERROR      Fail to detect media.
    500   @retval EFI_NO_MEDIA          Media is not present.
    501   @retval EFI_MEDIA_CHANGED     Media has changed.
    502   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    503   @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
    504 
    505 **/
    506 EFI_STATUS
    507 EFIAPI
    508 ScsiDiskReadBlocks (
    509   IN  EFI_BLOCK_IO_PROTOCOL   *This,
    510   IN  UINT32                  MediaId,
    511   IN  EFI_LBA                 Lba,
    512   IN  UINTN                   BufferSize,
    513   OUT VOID                    *Buffer
    514   )
    515 {
    516   SCSI_DISK_DEV       *ScsiDiskDevice;
    517   EFI_BLOCK_IO_MEDIA  *Media;
    518   EFI_STATUS          Status;
    519   UINTN               BlockSize;
    520   UINTN               NumberOfBlocks;
    521   BOOLEAN             MediaChange;
    522   EFI_TPL             OldTpl;
    523 
    524   MediaChange    = FALSE;
    525   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
    526   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
    527 
    528   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
    529 
    530     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
    531     if (EFI_ERROR (Status)) {
    532       Status = EFI_DEVICE_ERROR;
    533       goto Done;
    534     }
    535 
    536     if (MediaChange) {
    537       gBS->ReinstallProtocolInterface (
    538             ScsiDiskDevice->Handle,
    539             &gEfiBlockIoProtocolGuid,
    540             &ScsiDiskDevice->BlkIo,
    541             &ScsiDiskDevice->BlkIo
    542             );
    543       gBS->ReinstallProtocolInterface (
    544              ScsiDiskDevice->Handle,
    545              &gEfiBlockIo2ProtocolGuid,
    546              &ScsiDiskDevice->BlkIo2,
    547              &ScsiDiskDevice->BlkIo2
    548              );
    549       Status = EFI_MEDIA_CHANGED;
    550       goto Done;
    551     }
    552   }
    553   //
    554   // Get the intrinsic block size
    555   //
    556   Media           = ScsiDiskDevice->BlkIo.Media;
    557   BlockSize       = Media->BlockSize;
    558 
    559   NumberOfBlocks  = BufferSize / BlockSize;
    560 
    561   if (!(Media->MediaPresent)) {
    562     Status = EFI_NO_MEDIA;
    563     goto Done;
    564   }
    565 
    566   if (MediaId != Media->MediaId) {
    567     Status = EFI_MEDIA_CHANGED;
    568     goto Done;
    569   }
    570 
    571   if (Buffer == NULL) {
    572     Status = EFI_INVALID_PARAMETER;
    573     goto Done;
    574   }
    575 
    576   if (BufferSize == 0) {
    577     Status = EFI_SUCCESS;
    578     goto Done;
    579   }
    580 
    581   if (BufferSize % BlockSize != 0) {
    582     Status = EFI_BAD_BUFFER_SIZE;
    583     goto Done;
    584   }
    585 
    586   if (Lba > Media->LastBlock) {
    587     Status = EFI_INVALID_PARAMETER;
    588     goto Done;
    589   }
    590 
    591   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
    592     Status = EFI_INVALID_PARAMETER;
    593     goto Done;
    594   }
    595 
    596   if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
    597     Status = EFI_INVALID_PARAMETER;
    598     goto Done;
    599   }
    600 
    601   //
    602   // If all the parameters are valid, then perform read sectors command
    603   // to transfer data from device to host.
    604   //
    605   Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
    606 
    607 Done:
    608   gBS->RestoreTPL (OldTpl);
    609   return Status;
    610 }
    611 
    612 /**
    613   The function is to Write Block to SCSI Disk.
    614 
    615   @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL
    616   @param  MediaId    The Id of Media detected
    617   @param  Lba        The logic block address
    618   @param  BufferSize The size of Buffer
    619   @param  Buffer     The buffer to fill the read out data
    620 
    621   @retval EFI_SUCCESS           Successfully to read out block.
    622   @retval EFI_WRITE_PROTECTED   The device can not be written to.
    623   @retval EFI_DEVICE_ERROR      Fail to detect media.
    624   @retval EFI_NO_MEDIA          Media is not present.
    625   @retval EFI_MEDIA_CHNAGED     Media has changed.
    626   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    627   @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
    628 
    629 **/
    630 EFI_STATUS
    631 EFIAPI
    632 ScsiDiskWriteBlocks (
    633   IN  EFI_BLOCK_IO_PROTOCOL   *This,
    634   IN  UINT32                  MediaId,
    635   IN  EFI_LBA                 Lba,
    636   IN  UINTN                   BufferSize,
    637   IN  VOID                    *Buffer
    638   )
    639 {
    640   SCSI_DISK_DEV       *ScsiDiskDevice;
    641   EFI_BLOCK_IO_MEDIA  *Media;
    642   EFI_STATUS          Status;
    643   UINTN               BlockSize;
    644   UINTN               NumberOfBlocks;
    645   BOOLEAN             MediaChange;
    646   EFI_TPL             OldTpl;
    647 
    648   MediaChange    = FALSE;
    649   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
    650   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);
    651 
    652   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
    653 
    654     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
    655     if (EFI_ERROR (Status)) {
    656       Status = EFI_DEVICE_ERROR;
    657       goto Done;
    658     }
    659 
    660     if (MediaChange) {
    661       gBS->ReinstallProtocolInterface (
    662             ScsiDiskDevice->Handle,
    663             &gEfiBlockIoProtocolGuid,
    664             &ScsiDiskDevice->BlkIo,
    665             &ScsiDiskDevice->BlkIo
    666             );
    667       gBS->ReinstallProtocolInterface (
    668              ScsiDiskDevice->Handle,
    669              &gEfiBlockIo2ProtocolGuid,
    670              &ScsiDiskDevice->BlkIo2,
    671              &ScsiDiskDevice->BlkIo2
    672              );
    673       Status = EFI_MEDIA_CHANGED;
    674       goto Done;
    675     }
    676   }
    677   //
    678   // Get the intrinsic block size
    679   //
    680   Media           = ScsiDiskDevice->BlkIo.Media;
    681   BlockSize       = Media->BlockSize;
    682 
    683   NumberOfBlocks  = BufferSize / BlockSize;
    684 
    685   if (!(Media->MediaPresent)) {
    686     Status = EFI_NO_MEDIA;
    687     goto Done;
    688   }
    689 
    690   if (MediaId != Media->MediaId) {
    691     Status = EFI_MEDIA_CHANGED;
    692     goto Done;
    693   }
    694 
    695   if (Media->ReadOnly) {
    696     Status = EFI_WRITE_PROTECTED;
    697     goto Done;
    698   }
    699 
    700   if (BufferSize == 0) {
    701     Status = EFI_SUCCESS;
    702     goto Done;
    703   }
    704 
    705   if (Buffer == NULL) {
    706     Status = EFI_INVALID_PARAMETER;
    707     goto Done;
    708   }
    709 
    710   if (BufferSize % BlockSize != 0) {
    711     Status = EFI_BAD_BUFFER_SIZE;
    712     goto Done;
    713   }
    714 
    715   if (Lba > Media->LastBlock) {
    716     Status = EFI_INVALID_PARAMETER;
    717     goto Done;
    718   }
    719 
    720   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
    721     Status = EFI_INVALID_PARAMETER;
    722     goto Done;
    723   }
    724 
    725   if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
    726     Status = EFI_INVALID_PARAMETER;
    727     goto Done;
    728   }
    729   //
    730   // if all the parameters are valid, then perform read sectors command
    731   // to transfer data from device to host.
    732   //
    733   Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);
    734 
    735 Done:
    736   gBS->RestoreTPL (OldTpl);
    737   return Status;
    738 }
    739 
    740 /**
    741   Flush Block to Disk.
    742 
    743   EFI_SUCCESS is returned directly.
    744 
    745   @param  This              The pointer of EFI_BLOCK_IO_PROTOCOL
    746 
    747   @retval EFI_SUCCESS       All outstanding data was written to the device
    748 
    749 **/
    750 EFI_STATUS
    751 EFIAPI
    752 ScsiDiskFlushBlocks (
    753   IN  EFI_BLOCK_IO_PROTOCOL   *This
    754   )
    755 {
    756   //
    757   // return directly
    758   //
    759   return EFI_SUCCESS;
    760 }
    761 
    762 
    763 /**
    764   Reset SCSI Disk.
    765 
    766   @param  This                 The pointer of EFI_BLOCK_IO2_PROTOCOL.
    767   @param  ExtendedVerification The flag about if extend verificate.
    768 
    769   @retval EFI_SUCCESS          The device was reset.
    770   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
    771                                not be reset.
    772   @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
    773 
    774 **/
    775 EFI_STATUS
    776 EFIAPI
    777 ScsiDiskResetEx (
    778   IN  EFI_BLOCK_IO2_PROTOCOL  *This,
    779   IN  BOOLEAN                 ExtendedVerification
    780   )
    781 {
    782   EFI_TPL       OldTpl;
    783   SCSI_DISK_DEV *ScsiDiskDevice;
    784   EFI_STATUS    Status;
    785 
    786   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    787 
    788   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_BLKIO2 (This);
    789 
    790   Status          = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
    791 
    792   if (EFI_ERROR (Status)) {
    793     Status = EFI_DEVICE_ERROR;
    794     goto Done;
    795   }
    796 
    797   if (!ExtendedVerification) {
    798     goto Done;
    799   }
    800 
    801   Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
    802 
    803   if (EFI_ERROR (Status)) {
    804     Status = EFI_DEVICE_ERROR;
    805     goto Done;
    806   }
    807 
    808 Done:
    809   gBS->RestoreTPL (OldTpl);
    810   return Status;
    811 }
    812 
    813 /**
    814   The function is to Read Block from SCSI Disk.
    815 
    816   @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL.
    817   @param  MediaId    The Id of Media detected.
    818   @param  Lba        The logic block address.
    819   @param  Token      A pointer to the token associated with the transaction.
    820   @param  BufferSize The size of Buffer.
    821   @param  Buffer     The buffer to fill the read out data.
    822 
    823   @retval EFI_SUCCESS           The read request was queued if Token-> Event is
    824                                 not NULL. The data was read correctly from the
    825                                 device if theToken-> Event is NULL.
    826   @retval EFI_DEVICE_ERROR      The device reported an error while attempting
    827                                 to perform the read operation.
    828   @retval EFI_NO_MEDIA          There is no media in the device.
    829   @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
    830   @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of
    831                                 the intrinsic block size of the device.
    832   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
    833                                 valid, or the buffer is not on proper
    834                                 alignment.
    835   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
    836                                 lack of resources.
    837 
    838 **/
    839 EFI_STATUS
    840 EFIAPI
    841 ScsiDiskReadBlocksEx (
    842   IN     EFI_BLOCK_IO2_PROTOCOL   *This,
    843   IN     UINT32                   MediaId,
    844   IN     EFI_LBA                  Lba,
    845   IN OUT EFI_BLOCK_IO2_TOKEN      *Token,
    846   IN     UINTN                    BufferSize,
    847   OUT    VOID                     *Buffer
    848   )
    849 {
    850   SCSI_DISK_DEV       *ScsiDiskDevice;
    851   EFI_BLOCK_IO_MEDIA  *Media;
    852   EFI_STATUS          Status;
    853   UINTN               BlockSize;
    854   UINTN               NumberOfBlocks;
    855   BOOLEAN             MediaChange;
    856   EFI_TPL             OldTpl;
    857 
    858   MediaChange    = FALSE;
    859   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
    860   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
    861 
    862   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
    863 
    864     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
    865     if (EFI_ERROR (Status)) {
    866       Status = EFI_DEVICE_ERROR;
    867       goto Done;
    868     }
    869 
    870     if (MediaChange) {
    871       gBS->ReinstallProtocolInterface (
    872             ScsiDiskDevice->Handle,
    873             &gEfiBlockIoProtocolGuid,
    874             &ScsiDiskDevice->BlkIo,
    875             &ScsiDiskDevice->BlkIo
    876             );
    877       gBS->ReinstallProtocolInterface (
    878              ScsiDiskDevice->Handle,
    879              &gEfiBlockIo2ProtocolGuid,
    880              &ScsiDiskDevice->BlkIo2,
    881              &ScsiDiskDevice->BlkIo2
    882              );
    883       Status = EFI_MEDIA_CHANGED;
    884       goto Done;
    885     }
    886   }
    887   //
    888   // Get the intrinsic block size
    889   //
    890   Media           = ScsiDiskDevice->BlkIo2.Media;
    891   BlockSize       = Media->BlockSize;
    892 
    893   NumberOfBlocks  = BufferSize / BlockSize;
    894 
    895   if (!(Media->MediaPresent)) {
    896     Status = EFI_NO_MEDIA;
    897     goto Done;
    898   }
    899 
    900   if (MediaId != Media->MediaId) {
    901     Status = EFI_MEDIA_CHANGED;
    902     goto Done;
    903   }
    904 
    905   if (Buffer == NULL) {
    906     Status = EFI_INVALID_PARAMETER;
    907     goto Done;
    908   }
    909 
    910   if (BufferSize == 0) {
    911     if ((Token != NULL) && (Token->Event != NULL)) {
    912       Token->TransactionStatus = EFI_SUCCESS;
    913       gBS->SignalEvent (Token->Event);
    914     }
    915 
    916     Status = EFI_SUCCESS;
    917     goto Done;
    918   }
    919 
    920   if (BufferSize % BlockSize != 0) {
    921     Status = EFI_BAD_BUFFER_SIZE;
    922     goto Done;
    923   }
    924 
    925   if (Lba > Media->LastBlock) {
    926     Status = EFI_INVALID_PARAMETER;
    927     goto Done;
    928   }
    929 
    930   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
    931     Status = EFI_INVALID_PARAMETER;
    932     goto Done;
    933   }
    934 
    935   if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
    936     Status = EFI_INVALID_PARAMETER;
    937     goto Done;
    938   }
    939 
    940   //
    941   // If all the parameters are valid, then perform read sectors command
    942   // to transfer data from device to host.
    943   //
    944   if ((Token != NULL) && (Token->Event != NULL)) {
    945     Token->TransactionStatus = EFI_SUCCESS;
    946     Status = ScsiDiskAsyncReadSectors (
    947                ScsiDiskDevice,
    948                Buffer,
    949                Lba,
    950                NumberOfBlocks,
    951                Token
    952                );
    953   } else {
    954     Status = ScsiDiskReadSectors (
    955                ScsiDiskDevice,
    956                Buffer,
    957                Lba,
    958                NumberOfBlocks
    959                );
    960   }
    961 
    962 Done:
    963   gBS->RestoreTPL (OldTpl);
    964   return Status;
    965 }
    966 
    967 /**
    968   The function is to Write Block to SCSI Disk.
    969 
    970   @param  This       The pointer of EFI_BLOCK_IO_PROTOCOL.
    971   @param  MediaId    The Id of Media detected.
    972   @param  Lba        The logic block address.
    973   @param  Token      A pointer to the token associated with the transaction.
    974   @param  BufferSize The size of Buffer.
    975   @param  Buffer     The buffer to fill the read out data.
    976 
    977   @retval EFI_SUCCESS           The data were written correctly to the device.
    978   @retval EFI_WRITE_PROTECTED   The device cannot be written to.
    979   @retval EFI_NO_MEDIA          There is no media in the device.
    980   @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
    981   @retval EFI_DEVICE_ERROR      The device reported an error while attempting
    982                                 to perform the write operation.
    983   @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of
    984                                 the intrinsic block size of the device.
    985   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
    986                                 valid, or the buffer is not on proper
    987                                 alignment.
    988 
    989 **/
    990 EFI_STATUS
    991 EFIAPI
    992 ScsiDiskWriteBlocksEx (
    993   IN     EFI_BLOCK_IO2_PROTOCOL *This,
    994   IN     UINT32                 MediaId,
    995   IN     EFI_LBA                Lba,
    996   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
    997   IN     UINTN                  BufferSize,
    998   IN     VOID                   *Buffer
    999   )
   1000 {
   1001   SCSI_DISK_DEV       *ScsiDiskDevice;
   1002   EFI_BLOCK_IO_MEDIA  *Media;
   1003   EFI_STATUS          Status;
   1004   UINTN               BlockSize;
   1005   UINTN               NumberOfBlocks;
   1006   BOOLEAN             MediaChange;
   1007   EFI_TPL             OldTpl;
   1008 
   1009   MediaChange    = FALSE;
   1010   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
   1011   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
   1012 
   1013   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
   1014 
   1015     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
   1016     if (EFI_ERROR (Status)) {
   1017       Status = EFI_DEVICE_ERROR;
   1018       goto Done;
   1019     }
   1020 
   1021     if (MediaChange) {
   1022       gBS->ReinstallProtocolInterface (
   1023             ScsiDiskDevice->Handle,
   1024             &gEfiBlockIoProtocolGuid,
   1025             &ScsiDiskDevice->BlkIo,
   1026             &ScsiDiskDevice->BlkIo
   1027             );
   1028       gBS->ReinstallProtocolInterface (
   1029              ScsiDiskDevice->Handle,
   1030              &gEfiBlockIo2ProtocolGuid,
   1031              &ScsiDiskDevice->BlkIo2,
   1032              &ScsiDiskDevice->BlkIo2
   1033              );
   1034       Status = EFI_MEDIA_CHANGED;
   1035       goto Done;
   1036     }
   1037   }
   1038   //
   1039   // Get the intrinsic block size
   1040   //
   1041   Media           = ScsiDiskDevice->BlkIo2.Media;
   1042   BlockSize       = Media->BlockSize;
   1043 
   1044   NumberOfBlocks  = BufferSize / BlockSize;
   1045 
   1046   if (!(Media->MediaPresent)) {
   1047     Status = EFI_NO_MEDIA;
   1048     goto Done;
   1049   }
   1050 
   1051   if (MediaId != Media->MediaId) {
   1052     Status = EFI_MEDIA_CHANGED;
   1053     goto Done;
   1054   }
   1055 
   1056   if (Media->ReadOnly) {
   1057     Status = EFI_WRITE_PROTECTED;
   1058     goto Done;
   1059   }
   1060 
   1061   if (BufferSize == 0) {
   1062     if ((Token != NULL) && (Token->Event != NULL)) {
   1063       Token->TransactionStatus = EFI_SUCCESS;
   1064       gBS->SignalEvent (Token->Event);
   1065     }
   1066 
   1067     Status = EFI_SUCCESS;
   1068     goto Done;
   1069   }
   1070 
   1071   if (Buffer == NULL) {
   1072     Status = EFI_INVALID_PARAMETER;
   1073     goto Done;
   1074   }
   1075 
   1076   if (BufferSize % BlockSize != 0) {
   1077     Status = EFI_BAD_BUFFER_SIZE;
   1078     goto Done;
   1079   }
   1080 
   1081   if (Lba > Media->LastBlock) {
   1082     Status = EFI_INVALID_PARAMETER;
   1083     goto Done;
   1084   }
   1085 
   1086   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
   1087     Status = EFI_INVALID_PARAMETER;
   1088     goto Done;
   1089   }
   1090 
   1091   if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
   1092     Status = EFI_INVALID_PARAMETER;
   1093     goto Done;
   1094   }
   1095 
   1096   //
   1097   // if all the parameters are valid, then perform write sectors command
   1098   // to transfer data from device to host.
   1099   //
   1100   if ((Token != NULL) && (Token->Event != NULL)) {
   1101     Token->TransactionStatus = EFI_SUCCESS;
   1102     Status = ScsiDiskAsyncWriteSectors (
   1103                ScsiDiskDevice,
   1104                Buffer,
   1105                Lba,
   1106                NumberOfBlocks,
   1107                Token
   1108                );
   1109   } else {
   1110     Status = ScsiDiskWriteSectors (
   1111                ScsiDiskDevice,
   1112                Buffer,
   1113                Lba,
   1114                NumberOfBlocks
   1115                );
   1116   }
   1117 
   1118 Done:
   1119   gBS->RestoreTPL (OldTpl);
   1120   return Status;
   1121 }
   1122 
   1123 /**
   1124   Flush the Block Device.
   1125 
   1126   @param  This       Indicates a pointer to the calling context.
   1127   @param  Token      A pointer to the token associated with the transaction.
   1128 
   1129   @retval EFI_SUCCESS         All outstanding data was written to the device.
   1130   @retval EFI_DEVICE_ERROR    The device reported an error while attempting to
   1131                               write data.
   1132   @retval EFI_WRITE_PROTECTED The device cannot be written to.
   1133   @retval EFI_NO_MEDIA        There is no media in the device.
   1134   @retval EFI_MEDIA_CHANGED   The MediaId is not for the current media.
   1135 
   1136 **/
   1137 EFI_STATUS
   1138 EFIAPI
   1139 ScsiDiskFlushBlocksEx (
   1140   IN     EFI_BLOCK_IO2_PROTOCOL  *This,
   1141   IN OUT EFI_BLOCK_IO2_TOKEN     *Token
   1142   )
   1143 {
   1144   SCSI_DISK_DEV       *ScsiDiskDevice;
   1145   EFI_BLOCK_IO_MEDIA  *Media;
   1146   EFI_STATUS          Status;
   1147   BOOLEAN             MediaChange;
   1148   EFI_TPL             OldTpl;
   1149 
   1150   MediaChange    = FALSE;
   1151   OldTpl         = gBS->RaiseTPL (TPL_CALLBACK);
   1152   ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);
   1153 
   1154   if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {
   1155 
   1156     Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);
   1157     if (EFI_ERROR (Status)) {
   1158       Status = EFI_DEVICE_ERROR;
   1159       goto Done;
   1160     }
   1161 
   1162     if (MediaChange) {
   1163       gBS->ReinstallProtocolInterface (
   1164             ScsiDiskDevice->Handle,
   1165             &gEfiBlockIoProtocolGuid,
   1166             &ScsiDiskDevice->BlkIo,
   1167             &ScsiDiskDevice->BlkIo
   1168             );
   1169       gBS->ReinstallProtocolInterface (
   1170              ScsiDiskDevice->Handle,
   1171              &gEfiBlockIo2ProtocolGuid,
   1172              &ScsiDiskDevice->BlkIo2,
   1173              &ScsiDiskDevice->BlkIo2
   1174              );
   1175       Status = EFI_MEDIA_CHANGED;
   1176       goto Done;
   1177     }
   1178   }
   1179 
   1180   Media = ScsiDiskDevice->BlkIo2.Media;
   1181 
   1182   if (!(Media->MediaPresent)) {
   1183     Status = EFI_NO_MEDIA;
   1184     goto Done;
   1185   }
   1186 
   1187   if (Media->ReadOnly) {
   1188     Status = EFI_WRITE_PROTECTED;
   1189     goto Done;
   1190   }
   1191 
   1192   //
   1193   // Wait for the BlockIo2 requests queue to become empty
   1194   //
   1195   while (!IsListEmpty (&ScsiDiskDevice->BlkIo2Queue));
   1196 
   1197   Status = EFI_SUCCESS;
   1198 
   1199   //
   1200   // Signal caller event
   1201   //
   1202   if ((Token != NULL) && (Token->Event != NULL)) {
   1203     Token->TransactionStatus = EFI_SUCCESS;
   1204     gBS->SignalEvent (Token->Event);
   1205   }
   1206 
   1207 Done:
   1208   gBS->RestoreTPL (OldTpl);
   1209   return Status;
   1210 }
   1211 
   1212 
   1213 /**
   1214   Detect Device and read out capacity ,if error occurs, parse the sense key.
   1215 
   1216   @param  ScsiDiskDevice    The pointer of SCSI_DISK_DEV
   1217   @param  MustReadCapacity  The flag about reading device capacity
   1218   @param  MediaChange       The pointer of flag indicates if media has changed
   1219 
   1220   @retval EFI_DEVICE_ERROR  Indicates that error occurs
   1221   @retval EFI_SUCCESS       Successfully to detect media
   1222 
   1223 **/
   1224 EFI_STATUS
   1225 ScsiDiskDetectMedia (
   1226   IN   SCSI_DISK_DEV   *ScsiDiskDevice,
   1227   IN   BOOLEAN         MustReadCapacity,
   1228   OUT  BOOLEAN         *MediaChange
   1229   )
   1230 {
   1231   EFI_STATUS          Status;
   1232   EFI_SCSI_SENSE_DATA *SenseData;
   1233   UINTN               NumberOfSenseKeys;
   1234   BOOLEAN             NeedRetry;
   1235   BOOLEAN             NeedReadCapacity;
   1236   UINT8               Retry;
   1237   UINT8               MaxRetry;
   1238   EFI_BLOCK_IO_MEDIA  OldMedia;
   1239   UINTN               Action;
   1240   EFI_EVENT           TimeoutEvt;
   1241 
   1242   Status              = EFI_SUCCESS;
   1243   SenseData           = NULL;
   1244   NumberOfSenseKeys   = 0;
   1245   Retry               = 0;
   1246   MaxRetry            = 3;
   1247   Action              = ACTION_NO_ACTION;
   1248   NeedReadCapacity    = FALSE;
   1249   *MediaChange        = FALSE;
   1250   TimeoutEvt          = NULL;
   1251 
   1252   CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));
   1253 
   1254   Status = gBS->CreateEvent (
   1255                   EVT_TIMER,
   1256                   TPL_CALLBACK,
   1257                   NULL,
   1258                   NULL,
   1259                   &TimeoutEvt
   1260                   );
   1261   if (EFI_ERROR (Status)) {
   1262     return Status;
   1263   }
   1264 
   1265   Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(120));
   1266   if (EFI_ERROR (Status)) {
   1267     goto EXIT;
   1268   }
   1269 
   1270   //
   1271   // Sending Test_Unit cmd to poll device status.
   1272   // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
   1273   // We limit the upper boundary to 120 seconds.
   1274   //
   1275   while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
   1276     Status = ScsiDiskTestUnitReady (
   1277               ScsiDiskDevice,
   1278               &NeedRetry,
   1279               &SenseData,
   1280               &NumberOfSenseKeys
   1281               );
   1282     if (!EFI_ERROR (Status)) {
   1283       Status = DetectMediaParsingSenseKeys (
   1284                  ScsiDiskDevice,
   1285                  SenseData,
   1286                  NumberOfSenseKeys,
   1287                  &Action
   1288                  );
   1289       if (EFI_ERROR (Status)) {
   1290         goto EXIT;
   1291       } else if (Action == ACTION_RETRY_COMMAND_LATER) {
   1292         continue;
   1293       } else {
   1294         break;
   1295       }
   1296     } else {
   1297       Retry++;
   1298       if (!NeedRetry || (Retry >= MaxRetry)) {
   1299         goto EXIT;
   1300       }
   1301     }
   1302   }
   1303 
   1304   if (EFI_ERROR (Status)) {
   1305     goto EXIT;
   1306   }
   1307 
   1308   //
   1309   // ACTION_NO_ACTION: need not read capacity
   1310   // other action code: need read capacity
   1311   //
   1312   if (Action == ACTION_READ_CAPACITY) {
   1313     NeedReadCapacity = TRUE;
   1314   }
   1315 
   1316   //
   1317   // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
   1318   // retrieve capacity via Read Capacity command
   1319   //
   1320   if (NeedReadCapacity || MustReadCapacity) {
   1321     //
   1322     // retrieve media information
   1323     //
   1324     for (Retry = 0; Retry < MaxRetry; Retry++) {
   1325       Status = ScsiDiskReadCapacity (
   1326                  ScsiDiskDevice,
   1327                  &NeedRetry,
   1328                  &SenseData,
   1329                  &NumberOfSenseKeys
   1330                  );
   1331       if (!EFI_ERROR (Status)) {
   1332         //
   1333         // analyze sense key to action
   1334         //
   1335         Status = DetectMediaParsingSenseKeys (
   1336                    ScsiDiskDevice,
   1337                    SenseData,
   1338                    NumberOfSenseKeys,
   1339                    &Action
   1340                    );
   1341         if (EFI_ERROR (Status)) {
   1342           //
   1343           // if Status is error, it may indicate crisis error,
   1344           // so return without retry.
   1345           //
   1346           goto EXIT;
   1347         } else if (Action == ACTION_RETRY_COMMAND_LATER) {
   1348           Retry = 0;
   1349           continue;
   1350         } else {
   1351           break;
   1352         }
   1353       } else {
   1354         Retry++;
   1355         if (!NeedRetry || (Retry >= MaxRetry)) {
   1356           goto EXIT;
   1357         }
   1358       }
   1359     }
   1360 
   1361     if (EFI_ERROR (Status)) {
   1362       goto EXIT;
   1363     }
   1364   }
   1365 
   1366   if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {
   1367     //
   1368     // Media change information got from the device
   1369     //
   1370     *MediaChange = TRUE;
   1371   }
   1372 
   1373   if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {
   1374     *MediaChange = TRUE;
   1375     ScsiDiskDevice->BlkIo.Media->MediaId += 1;
   1376   }
   1377 
   1378   if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {
   1379     *MediaChange = TRUE;
   1380     ScsiDiskDevice->BlkIo.Media->MediaId += 1;
   1381   }
   1382 
   1383   if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {
   1384     *MediaChange = TRUE;
   1385     ScsiDiskDevice->BlkIo.Media->MediaId += 1;
   1386   }
   1387 
   1388   if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {
   1389     if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {
   1390       //
   1391       // when change from no media to media present, reset the MediaId to 1.
   1392       //
   1393       ScsiDiskDevice->BlkIo.Media->MediaId = 1;
   1394     } else {
   1395       //
   1396       // when no media, reset the MediaId to zero.
   1397       //
   1398       ScsiDiskDevice->BlkIo.Media->MediaId = 0;
   1399     }
   1400 
   1401     *MediaChange = TRUE;
   1402   }
   1403 
   1404 EXIT:
   1405   if (TimeoutEvt != NULL) {
   1406     gBS->CloseEvent (TimeoutEvt);
   1407   }
   1408   return Status;
   1409 }
   1410 
   1411 
   1412 /**
   1413   Send out Inquiry command to Device.
   1414 
   1415   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
   1416   @param  NeedRetry       Indicates if needs try again when error happens
   1417 
   1418   @retval  EFI_DEVICE_ERROR  Indicates that error occurs
   1419   @retval  EFI_SUCCESS       Successfully to detect media
   1420 
   1421 **/
   1422 EFI_STATUS
   1423 ScsiDiskInquiryDevice (
   1424   IN OUT  SCSI_DISK_DEV   *ScsiDiskDevice,
   1425      OUT  BOOLEAN         *NeedRetry
   1426   )
   1427 {
   1428   UINT32                                InquiryDataLength;
   1429   UINT8                                 SenseDataLength;
   1430   UINT8                                 HostAdapterStatus;
   1431   UINT8                                 TargetStatus;
   1432   EFI_SCSI_SENSE_DATA                   *SenseDataArray;
   1433   UINTN                                 NumberOfSenseKeys;
   1434   EFI_STATUS                            Status;
   1435   UINT8                                 MaxRetry;
   1436   UINT8                                 Index;
   1437   EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE *SupportedVpdPages;
   1438   EFI_SCSI_BLOCK_LIMITS_VPD_PAGE        *BlockLimits;
   1439   UINTN                                 PageLength;
   1440 
   1441   InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
   1442   SenseDataLength   = 0;
   1443 
   1444   Status = ScsiInquiryCommand (
   1445             ScsiDiskDevice->ScsiIo,
   1446             SCSI_DISK_TIMEOUT,
   1447             NULL,
   1448             &SenseDataLength,
   1449             &HostAdapterStatus,
   1450             &TargetStatus,
   1451             (VOID *) &(ScsiDiskDevice->InquiryData),
   1452             &InquiryDataLength,
   1453             FALSE
   1454             );
   1455     //
   1456     // no need to check HostAdapterStatus and TargetStatus
   1457     //
   1458   if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
   1459     ParseInquiryData (ScsiDiskDevice);
   1460 
   1461     if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {
   1462       //
   1463       // Check whether the device supports Block Limits VPD page (0xB0)
   1464       //
   1465       SupportedVpdPages = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
   1466       if (SupportedVpdPages == NULL) {
   1467         *NeedRetry = FALSE;
   1468         return EFI_DEVICE_ERROR;
   1469       }
   1470       ZeroMem (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
   1471       InquiryDataLength = sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE);
   1472       SenseDataLength   = 0;
   1473       Status = ScsiInquiryCommandEx (
   1474                  ScsiDiskDevice->ScsiIo,
   1475                  SCSI_DISK_TIMEOUT,
   1476                  NULL,
   1477                  &SenseDataLength,
   1478                  &HostAdapterStatus,
   1479                  &TargetStatus,
   1480                  (VOID *) SupportedVpdPages,
   1481                  &InquiryDataLength,
   1482                  TRUE,
   1483                  EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
   1484                  );
   1485       if (!EFI_ERROR (Status)) {
   1486         PageLength = (SupportedVpdPages->PageLength2 << 8)
   1487                    |  SupportedVpdPages->PageLength1;
   1488         for (Index = 0; Index < PageLength; Index++) {
   1489           if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {
   1490             break;
   1491           }
   1492         }
   1493 
   1494         //
   1495         // Query the Block Limits VPD page
   1496         //
   1497         if (Index < PageLength) {
   1498           BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
   1499           if (BlockLimits == NULL) {
   1500             FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
   1501             *NeedRetry = FALSE;
   1502             return EFI_DEVICE_ERROR;
   1503           }
   1504           ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
   1505           InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE);
   1506           SenseDataLength   = 0;
   1507           Status = ScsiInquiryCommandEx (
   1508                      ScsiDiskDevice->ScsiIo,
   1509                      SCSI_DISK_TIMEOUT,
   1510                      NULL,
   1511                      &SenseDataLength,
   1512                      &HostAdapterStatus,
   1513                      &TargetStatus,
   1514                      (VOID *) BlockLimits,
   1515                      &InquiryDataLength,
   1516                      TRUE,
   1517                      EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
   1518                      );
   1519           if (!EFI_ERROR (Status)) {
   1520             ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity =
   1521               (BlockLimits->OptimalTransferLengthGranularity2 << 8) |
   1522                BlockLimits->OptimalTransferLengthGranularity1;
   1523           }
   1524 
   1525           FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));
   1526         }
   1527       }
   1528 
   1529       FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));
   1530     }
   1531   }
   1532 
   1533   if (!EFI_ERROR (Status)) {
   1534     return EFI_SUCCESS;
   1535 
   1536   } else if (Status == EFI_NOT_READY) {
   1537     *NeedRetry = TRUE;
   1538     return EFI_DEVICE_ERROR;
   1539 
   1540   } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
   1541     *NeedRetry = FALSE;
   1542     return EFI_DEVICE_ERROR;
   1543   }
   1544   //
   1545   // go ahead to check HostAdapterStatus and TargetStatus
   1546   // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
   1547   //
   1548 
   1549   Status = CheckHostAdapterStatus (HostAdapterStatus);
   1550   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
   1551     *NeedRetry = TRUE;
   1552     return EFI_DEVICE_ERROR;
   1553   } else if (Status == EFI_DEVICE_ERROR) {
   1554       //
   1555       // reset the scsi channel
   1556       //
   1557     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
   1558     *NeedRetry = FALSE;
   1559     return EFI_DEVICE_ERROR;
   1560   }
   1561 
   1562   Status = CheckTargetStatus (TargetStatus);
   1563   if (Status == EFI_NOT_READY) {
   1564     //
   1565     // reset the scsi device
   1566     //
   1567     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
   1568     *NeedRetry = TRUE;
   1569     return EFI_DEVICE_ERROR;
   1570 
   1571   } else if (Status == EFI_DEVICE_ERROR) {
   1572     *NeedRetry = FALSE;
   1573     return EFI_DEVICE_ERROR;
   1574   }
   1575 
   1576   //
   1577   // if goes here, meant ScsiInquiryCommand() failed.
   1578   // if ScsiDiskRequestSenseKeys() succeeds at last,
   1579   // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
   1580   //
   1581   MaxRetry = 3;
   1582   for (Index = 0; Index < MaxRetry; Index++) {
   1583     Status = ScsiDiskRequestSenseKeys (
   1584               ScsiDiskDevice,
   1585               NeedRetry,
   1586               &SenseDataArray,
   1587               &NumberOfSenseKeys,
   1588               TRUE
   1589               );
   1590     if (!EFI_ERROR (Status)) {
   1591       *NeedRetry = TRUE;
   1592       return EFI_DEVICE_ERROR;
   1593     }
   1594 
   1595     if (!*NeedRetry) {
   1596       return EFI_DEVICE_ERROR;
   1597     }
   1598   }
   1599   //
   1600   // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
   1601   // set *NeedRetry = FALSE to avoid the outside caller try again.
   1602   //
   1603   *NeedRetry = FALSE;
   1604   return EFI_DEVICE_ERROR;
   1605 }
   1606 
   1607 /**
   1608   To test device.
   1609 
   1610   When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
   1611   When Test Unit Ready command encounters any error caused by host adapter or
   1612   target, return error without retrieving Sense Keys.
   1613 
   1614   @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV
   1615   @param  NeedRetry          The pointer of flag indicates try again
   1616   @param  SenseDataArray     The pointer of an array of sense data
   1617   @param  NumberOfSenseKeys  The pointer of the number of sense data array
   1618 
   1619   @retval EFI_DEVICE_ERROR   Indicates that error occurs
   1620   @retval EFI_SUCCESS        Successfully to test unit
   1621 
   1622 **/
   1623 EFI_STATUS
   1624 ScsiDiskTestUnitReady (
   1625   IN  SCSI_DISK_DEV         *ScsiDiskDevice,
   1626   OUT BOOLEAN               *NeedRetry,
   1627   OUT EFI_SCSI_SENSE_DATA   **SenseDataArray,
   1628   OUT UINTN                 *NumberOfSenseKeys
   1629   )
   1630 {
   1631   EFI_STATUS  Status;
   1632   UINT8       SenseDataLength;
   1633   UINT8       HostAdapterStatus;
   1634   UINT8       TargetStatus;
   1635   UINT8       Index;
   1636   UINT8       MaxRetry;
   1637 
   1638   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
   1639   *NumberOfSenseKeys  = 0;
   1640 
   1641   //
   1642   // Parameter 3 and 4: do not require sense data, retrieve it when needed.
   1643   //
   1644   Status = ScsiTestUnitReadyCommand (
   1645             ScsiDiskDevice->ScsiIo,
   1646             SCSI_DISK_TIMEOUT,
   1647             ScsiDiskDevice->SenseData,
   1648             &SenseDataLength,
   1649             &HostAdapterStatus,
   1650             &TargetStatus
   1651             );
   1652   //
   1653   // no need to check HostAdapterStatus and TargetStatus
   1654   //
   1655   if (Status == EFI_NOT_READY) {
   1656     *NeedRetry = TRUE;
   1657     return EFI_DEVICE_ERROR;
   1658 
   1659   } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
   1660     *NeedRetry = FALSE;
   1661     return EFI_DEVICE_ERROR;
   1662   }
   1663   //
   1664   // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
   1665   //
   1666 
   1667   Status = CheckHostAdapterStatus (HostAdapterStatus);
   1668   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
   1669     *NeedRetry = TRUE;
   1670     return EFI_DEVICE_ERROR;
   1671 
   1672   } else if (Status == EFI_DEVICE_ERROR) {
   1673     //
   1674     // reset the scsi channel
   1675     //
   1676     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
   1677     *NeedRetry = FALSE;
   1678     return EFI_DEVICE_ERROR;
   1679   }
   1680 
   1681   Status = CheckTargetStatus (TargetStatus);
   1682   if (Status == EFI_NOT_READY) {
   1683     //
   1684     // reset the scsi device
   1685     //
   1686     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
   1687     *NeedRetry = TRUE;
   1688     return EFI_DEVICE_ERROR;
   1689 
   1690   } else if (Status == EFI_DEVICE_ERROR) {
   1691     *NeedRetry = FALSE;
   1692     return EFI_DEVICE_ERROR;
   1693   }
   1694 
   1695   if (SenseDataLength != 0) {
   1696     *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA);
   1697     *SenseDataArray    = ScsiDiskDevice->SenseData;
   1698     return EFI_SUCCESS;
   1699   }
   1700 
   1701   MaxRetry = 3;
   1702   for (Index = 0; Index < MaxRetry; Index++) {
   1703     Status = ScsiDiskRequestSenseKeys (
   1704               ScsiDiskDevice,
   1705               NeedRetry,
   1706               SenseDataArray,
   1707               NumberOfSenseKeys,
   1708               FALSE
   1709               );
   1710     if (!EFI_ERROR (Status)) {
   1711       return EFI_SUCCESS;
   1712     }
   1713 
   1714     if (!*NeedRetry) {
   1715       return EFI_DEVICE_ERROR;
   1716     }
   1717   }
   1718   //
   1719   // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
   1720   // set *NeedRetry = FALSE to avoid the outside caller try again.
   1721   //
   1722   *NeedRetry = FALSE;
   1723   return EFI_DEVICE_ERROR;
   1724 }
   1725 
   1726 /**
   1727   Parsing Sense Keys which got from request sense command.
   1728 
   1729   @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV
   1730   @param  SenseData          The pointer of EFI_SCSI_SENSE_DATA
   1731   @param  NumberOfSenseKeys  The number of sense key
   1732   @param  Action             The pointer of action which indicates what is need to do next
   1733 
   1734   @retval EFI_DEVICE_ERROR   Indicates that error occurs
   1735   @retval EFI_SUCCESS        Successfully to complete the parsing
   1736 
   1737 **/
   1738 EFI_STATUS
   1739 DetectMediaParsingSenseKeys (
   1740   OUT  SCSI_DISK_DEV           *ScsiDiskDevice,
   1741   IN   EFI_SCSI_SENSE_DATA     *SenseData,
   1742   IN   UINTN                   NumberOfSenseKeys,
   1743   OUT  UINTN                   *Action
   1744   )
   1745 {
   1746   BOOLEAN RetryLater;
   1747 
   1748   //
   1749   // Default is to read capacity, unless..
   1750   //
   1751   *Action = ACTION_READ_CAPACITY;
   1752 
   1753   if (NumberOfSenseKeys == 0) {
   1754     if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
   1755       *Action = ACTION_NO_ACTION;
   1756     }
   1757     return EFI_SUCCESS;
   1758   }
   1759 
   1760   if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {
   1761     //
   1762     // No Sense Key returned from last submitted command
   1763     //
   1764     if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {
   1765       *Action = ACTION_NO_ACTION;
   1766     }
   1767     return EFI_SUCCESS;
   1768   }
   1769 
   1770   if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {
   1771     ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;
   1772     ScsiDiskDevice->BlkIo.Media->LastBlock    = 0;
   1773     *Action = ACTION_NO_ACTION;
   1774     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));
   1775     return EFI_SUCCESS;
   1776   }
   1777 
   1778   if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {
   1779     ScsiDiskDevice->BlkIo.Media->MediaId++;
   1780     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
   1781     return EFI_SUCCESS;
   1782   }
   1783 
   1784   if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {
   1785     *Action = ACTION_RETRY_COMMAND_LATER;
   1786     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
   1787     return EFI_SUCCESS;
   1788   }
   1789 
   1790   if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {
   1791     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));
   1792     *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
   1793     return EFI_DEVICE_ERROR;
   1794   }
   1795 
   1796   if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {
   1797     DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));
   1798     *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
   1799     return EFI_DEVICE_ERROR;
   1800   }
   1801 
   1802   if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {
   1803     if (RetryLater) {
   1804       *Action = ACTION_RETRY_COMMAND_LATER;
   1805       DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
   1806       return EFI_SUCCESS;
   1807     }
   1808     *Action = ACTION_NO_ACTION;
   1809     return EFI_DEVICE_ERROR;
   1810   }
   1811 
   1812   *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;
   1813   DEBUG ((EFI_D_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));
   1814   return EFI_SUCCESS;
   1815 }
   1816 
   1817 
   1818 /**
   1819   Send read capacity command to device and get the device parameter.
   1820 
   1821   @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV
   1822   @param  NeedRetry          The pointer of flag indicates if need a retry
   1823   @param  SenseDataArray     The pointer of an array of sense data
   1824   @param  NumberOfSenseKeys  The number of sense key
   1825 
   1826   @retval EFI_DEVICE_ERROR   Indicates that error occurs
   1827   @retval EFI_SUCCESS        Successfully to read capacity or sense data is received.
   1828 
   1829 **/
   1830 EFI_STATUS
   1831 ScsiDiskReadCapacity (
   1832   IN  OUT  SCSI_DISK_DEV           *ScsiDiskDevice,
   1833       OUT  BOOLEAN                 *NeedRetry,
   1834       OUT  EFI_SCSI_SENSE_DATA     **SenseDataArray,
   1835       OUT  UINTN                   *NumberOfSenseKeys
   1836   )
   1837 {
   1838   UINT8                         HostAdapterStatus;
   1839   UINT8                         TargetStatus;
   1840   EFI_STATUS                    CommandStatus;
   1841   EFI_STATUS                    Status;
   1842   UINT8                         Index;
   1843   UINT8                         MaxRetry;
   1844   UINT8                         SenseDataLength;
   1845   UINT32                        DataLength10;
   1846   UINT32                        DataLength16;
   1847   EFI_SCSI_DISK_CAPACITY_DATA   *CapacityData10;
   1848   EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;
   1849 
   1850   CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
   1851   if (CapacityData10 == NULL) {
   1852     *NeedRetry = FALSE;
   1853     return EFI_DEVICE_ERROR;
   1854   }
   1855   CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
   1856   if (CapacityData16 == NULL) {
   1857     FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
   1858     *NeedRetry = FALSE;
   1859     return EFI_DEVICE_ERROR;
   1860   }
   1861 
   1862   SenseDataLength       = 0;
   1863   DataLength10          = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);
   1864   DataLength16          = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);
   1865   ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
   1866   ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
   1867 
   1868   *NumberOfSenseKeys  = 0;
   1869   *NeedRetry          = FALSE;
   1870 
   1871   //
   1872   // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
   1873   // 16 byte command should be used to access large hard disk >2TB
   1874   //
   1875   CommandStatus = ScsiReadCapacityCommand (
   1876                     ScsiDiskDevice->ScsiIo,
   1877                     SCSI_DISK_TIMEOUT,
   1878                     NULL,
   1879                     &SenseDataLength,
   1880                     &HostAdapterStatus,
   1881                     &TargetStatus,
   1882                     (VOID *) CapacityData10,
   1883                     &DataLength10,
   1884                     FALSE
   1885                     );
   1886 
   1887   ScsiDiskDevice->Cdb16Byte = FALSE;
   1888   if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) &&
   1889       (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff)) {
   1890     //
   1891     // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
   1892     //
   1893     ScsiDiskDevice->Cdb16Byte = TRUE;
   1894     //
   1895     // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
   1896     // and LowestAlignedLba
   1897     //
   1898     CommandStatus = ScsiReadCapacity16Command (
   1899                       ScsiDiskDevice->ScsiIo,
   1900                       SCSI_DISK_TIMEOUT,
   1901                       NULL,
   1902                       &SenseDataLength,
   1903                       &HostAdapterStatus,
   1904                       &TargetStatus,
   1905                       (VOID *) CapacityData16,
   1906                       &DataLength16,
   1907                       FALSE
   1908                       );
   1909   }
   1910 
   1911     //
   1912     // no need to check HostAdapterStatus and TargetStatus
   1913     //
   1914    if (CommandStatus == EFI_SUCCESS) {
   1915      GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16);
   1916      FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
   1917      FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
   1918      return EFI_SUCCESS;
   1919    }
   1920 
   1921    FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));
   1922    FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));
   1923 
   1924    if (CommandStatus == EFI_NOT_READY) {
   1925      *NeedRetry = TRUE;
   1926      return EFI_DEVICE_ERROR;
   1927    } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {
   1928      *NeedRetry = FALSE;
   1929      return EFI_DEVICE_ERROR;
   1930    }
   1931 
   1932    //
   1933    // go ahead to check HostAdapterStatus and TargetStatus
   1934    // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
   1935    //
   1936 
   1937    Status = CheckHostAdapterStatus (HostAdapterStatus);
   1938    if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
   1939      *NeedRetry = TRUE;
   1940      return EFI_DEVICE_ERROR;
   1941 
   1942    } else if (Status == EFI_DEVICE_ERROR) {
   1943     //
   1944     // reset the scsi channel
   1945     //
   1946     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
   1947     *NeedRetry = FALSE;
   1948     return EFI_DEVICE_ERROR;
   1949   }
   1950 
   1951   Status = CheckTargetStatus (TargetStatus);
   1952   if (Status == EFI_NOT_READY) {
   1953     //
   1954     // reset the scsi device
   1955     //
   1956     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
   1957     *NeedRetry = TRUE;
   1958     return EFI_DEVICE_ERROR;
   1959 
   1960   } else if (Status == EFI_DEVICE_ERROR) {
   1961     *NeedRetry = FALSE;
   1962     return EFI_DEVICE_ERROR;
   1963   }
   1964 
   1965   //
   1966   // if goes here, meant ScsiReadCapacityCommand() failed.
   1967   // if ScsiDiskRequestSenseKeys() succeeds at last,
   1968   // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
   1969   //
   1970   MaxRetry = 3;
   1971   for (Index = 0; Index < MaxRetry; Index++) {
   1972 
   1973     Status = ScsiDiskRequestSenseKeys (
   1974               ScsiDiskDevice,
   1975               NeedRetry,
   1976               SenseDataArray,
   1977               NumberOfSenseKeys,
   1978               TRUE
   1979               );
   1980     if (!EFI_ERROR (Status)) {
   1981       return EFI_SUCCESS;
   1982     }
   1983 
   1984     if (!*NeedRetry) {
   1985       return EFI_DEVICE_ERROR;
   1986     }
   1987   }
   1988   //
   1989   // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
   1990   // set *NeedRetry = FALSE to avoid the outside caller try again.
   1991   //
   1992   *NeedRetry = FALSE;
   1993   return EFI_DEVICE_ERROR;
   1994 }
   1995 
   1996 /**
   1997   Check the HostAdapter status and re-interpret it in EFI_STATUS.
   1998 
   1999   @param  HostAdapterStatus  Host Adapter status
   2000 
   2001   @retval  EFI_SUCCESS       Host adapter is OK.
   2002   @retval  EFI_TIMEOUT       Timeout.
   2003   @retval  EFI_NOT_READY     Adapter NOT ready.
   2004   @retval  EFI_DEVICE_ERROR  Adapter device error.
   2005 
   2006 **/
   2007 EFI_STATUS
   2008 CheckHostAdapterStatus (
   2009   IN UINT8   HostAdapterStatus
   2010   )
   2011 {
   2012   switch (HostAdapterStatus) {
   2013   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:
   2014     return EFI_SUCCESS;
   2015 
   2016   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:
   2017   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:
   2018   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:
   2019     return EFI_TIMEOUT;
   2020 
   2021   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:
   2022   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:
   2023   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:
   2024   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:
   2025   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:
   2026     return EFI_NOT_READY;
   2027 
   2028   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:
   2029   case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:
   2030     return EFI_DEVICE_ERROR;
   2031 
   2032   default:
   2033     return EFI_SUCCESS;
   2034   }
   2035 }
   2036 
   2037 
   2038 /**
   2039   Check the target status and re-interpret it in EFI_STATUS.
   2040 
   2041   @param  TargetStatus  Target status
   2042 
   2043   @retval EFI_NOT_READY       Device is NOT ready.
   2044   @retval EFI_DEVICE_ERROR
   2045   @retval EFI_SUCCESS
   2046 
   2047 **/
   2048 EFI_STATUS
   2049 CheckTargetStatus (
   2050   IN  UINT8   TargetStatus
   2051   )
   2052 {
   2053   switch (TargetStatus) {
   2054   case EFI_EXT_SCSI_STATUS_TARGET_GOOD:
   2055   case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:
   2056   case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:
   2057     return EFI_SUCCESS;
   2058 
   2059   case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:
   2060   case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:
   2061   case EFI_EXT_SCSI_STATUS_TARGET_BUSY:
   2062   case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:
   2063     return EFI_NOT_READY;
   2064 
   2065   case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:
   2066     return EFI_DEVICE_ERROR;
   2067 
   2068   default:
   2069     return EFI_SUCCESS;
   2070   }
   2071 }
   2072 
   2073 
   2074 /**
   2075   Retrieve all sense keys from the device.
   2076 
   2077   When encountering error during the process, if retrieve sense keys before
   2078   error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
   2079   and NeedRetry set to FALSE; otherwize, return the proper return status.
   2080 
   2081   @param  ScsiDiskDevice     The pointer of SCSI_DISK_DEV
   2082   @param  NeedRetry          The pointer of flag indicates if need a retry
   2083   @param  SenseDataArray     The pointer of an array of sense data
   2084   @param  NumberOfSenseKeys  The number of sense key
   2085   @param  AskResetIfError    The flag indicates if need reset when error occurs
   2086 
   2087   @retval EFI_DEVICE_ERROR   Indicates that error occurs
   2088   @retval EFI_SUCCESS        Successfully to request sense key
   2089 
   2090 **/
   2091 EFI_STATUS
   2092 ScsiDiskRequestSenseKeys (
   2093   IN  OUT  SCSI_DISK_DEV           *ScsiDiskDevice,
   2094       OUT  BOOLEAN                 *NeedRetry,
   2095       OUT  EFI_SCSI_SENSE_DATA     **SenseDataArray,
   2096       OUT  UINTN                   *NumberOfSenseKeys,
   2097   IN       BOOLEAN                 AskResetIfError
   2098   )
   2099 {
   2100   EFI_SCSI_SENSE_DATA *PtrSenseData;
   2101   UINT8               SenseDataLength;
   2102   BOOLEAN             SenseReq;
   2103   EFI_STATUS          Status;
   2104   EFI_STATUS          FallStatus;
   2105   UINT8               HostAdapterStatus;
   2106   UINT8               TargetStatus;
   2107 
   2108   FallStatus      = EFI_SUCCESS;
   2109   SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA);
   2110 
   2111   ZeroMem (
   2112     ScsiDiskDevice->SenseData,
   2113     sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)
   2114     );
   2115 
   2116   *NumberOfSenseKeys  = 0;
   2117   *SenseDataArray     = ScsiDiskDevice->SenseData;
   2118   Status              = EFI_SUCCESS;
   2119   PtrSenseData        = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));
   2120   if (PtrSenseData == NULL) {
   2121     return EFI_DEVICE_ERROR;
   2122   }
   2123 
   2124   for (SenseReq = TRUE; SenseReq;) {
   2125     ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
   2126     Status = ScsiRequestSenseCommand (
   2127               ScsiDiskDevice->ScsiIo,
   2128               SCSI_DISK_TIMEOUT,
   2129               PtrSenseData,
   2130               &SenseDataLength,
   2131               &HostAdapterStatus,
   2132               &TargetStatus
   2133               );
   2134      if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {
   2135         FallStatus = EFI_SUCCESS;
   2136 
   2137      } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
   2138        *NeedRetry  = TRUE;
   2139        FallStatus  = EFI_DEVICE_ERROR;
   2140 
   2141      } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {
   2142        *NeedRetry  = FALSE;
   2143        FallStatus  = EFI_DEVICE_ERROR;
   2144 
   2145      } else if (Status == EFI_DEVICE_ERROR) {
   2146         if (AskResetIfError) {
   2147           ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
   2148         }
   2149 
   2150         FallStatus = EFI_DEVICE_ERROR;
   2151     }
   2152 
   2153     if (EFI_ERROR (FallStatus)) {
   2154       if (*NumberOfSenseKeys != 0) {
   2155         *NeedRetry = FALSE;
   2156         Status = EFI_SUCCESS;
   2157         goto EXIT;
   2158       } else {
   2159         Status = EFI_DEVICE_ERROR;
   2160         goto EXIT;
   2161       }
   2162     }
   2163 
   2164     CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);
   2165     (*NumberOfSenseKeys) += 1;
   2166 
   2167     //
   2168     // no more sense key or number of sense keys exceeds predefined,
   2169     // skip the loop.
   2170     //
   2171     if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||
   2172         (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {
   2173       SenseReq = FALSE;
   2174     }
   2175   }
   2176 
   2177 EXIT:
   2178   FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));
   2179   return Status;
   2180 }
   2181 
   2182 
   2183 /**
   2184   Get information from media read capacity command.
   2185 
   2186   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
   2187   @param  Capacity10      The pointer of EFI_SCSI_DISK_CAPACITY_DATA
   2188   @param  Capacity16      The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
   2189 
   2190 **/
   2191 VOID
   2192 GetMediaInfo (
   2193   IN OUT SCSI_DISK_DEV                  *ScsiDiskDevice,
   2194   IN     EFI_SCSI_DISK_CAPACITY_DATA    *Capacity10,
   2195   IN     EFI_SCSI_DISK_CAPACITY_DATA16  *Capacity16
   2196   )
   2197 {
   2198   UINT8       *Ptr;
   2199 
   2200   if (!ScsiDiskDevice->Cdb16Byte) {
   2201     ScsiDiskDevice->BlkIo.Media->LastBlock =  (Capacity10->LastLba3 << 24) |
   2202                                               (Capacity10->LastLba2 << 16) |
   2203                                               (Capacity10->LastLba1 << 8)  |
   2204                                                Capacity10->LastLba0;
   2205 
   2206     ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |
   2207                                              (Capacity10->BlockSize2 << 16) |
   2208                                              (Capacity10->BlockSize1 << 8)  |
   2209                                               Capacity10->BlockSize0;
   2210     ScsiDiskDevice->BlkIo.Media->LowestAlignedLba               = 0;
   2211     ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock  = 0;
   2212   } else {
   2213     Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;
   2214     *Ptr++ = Capacity16->LastLba0;
   2215     *Ptr++ = Capacity16->LastLba1;
   2216     *Ptr++ = Capacity16->LastLba2;
   2217     *Ptr++ = Capacity16->LastLba3;
   2218     *Ptr++ = Capacity16->LastLba4;
   2219     *Ptr++ = Capacity16->LastLba5;
   2220     *Ptr++ = Capacity16->LastLba6;
   2221     *Ptr   = Capacity16->LastLba7;
   2222 
   2223     ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |
   2224                                              (Capacity16->BlockSize2 << 16) |
   2225                                              (Capacity16->BlockSize1 << 8)  |
   2226                                               Capacity16->BlockSize0;
   2227 
   2228     ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) |
   2229                                                      Capacity16->LowestAlignLogic1;
   2230     ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock  = (1 << Capacity16->LogicPerPhysical);
   2231   }
   2232 
   2233   ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;
   2234 }
   2235 
   2236 /**
   2237   Parse Inquiry data.
   2238 
   2239   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
   2240 
   2241 **/
   2242 VOID
   2243 ParseInquiryData (
   2244   IN OUT SCSI_DISK_DEV   *ScsiDiskDevice
   2245   )
   2246 {
   2247   ScsiDiskDevice->FixedDevice               = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);
   2248   ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);
   2249 }
   2250 
   2251 /**
   2252   Read sector from SCSI Disk.
   2253 
   2254   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
   2255   @param  Buffer          The buffer to fill in the read out data
   2256   @param  Lba             Logic block address
   2257   @param  NumberOfBlocks  The number of blocks to read
   2258 
   2259   @retval EFI_DEVICE_ERROR  Indicates a device error.
   2260   @retval EFI_SUCCESS       Operation is successful.
   2261 
   2262 **/
   2263 EFI_STATUS
   2264 ScsiDiskReadSectors (
   2265   IN   SCSI_DISK_DEV     *ScsiDiskDevice,
   2266   OUT  VOID              *Buffer,
   2267   IN   EFI_LBA           Lba,
   2268   IN   UINTN             NumberOfBlocks
   2269   )
   2270 {
   2271   UINTN               BlocksRemaining;
   2272   UINT8               *PtrBuffer;
   2273   UINT32              BlockSize;
   2274   UINT32              ByteCount;
   2275   UINT32              MaxBlock;
   2276   UINT32              SectorCount;
   2277   UINT32              NextSectorCount;
   2278   UINT64              Timeout;
   2279   EFI_STATUS          Status;
   2280   UINT8               Index;
   2281   UINT8               MaxRetry;
   2282   BOOLEAN             NeedRetry;
   2283 
   2284   Status            = EFI_SUCCESS;
   2285 
   2286   BlocksRemaining   = NumberOfBlocks;
   2287   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;
   2288 
   2289   //
   2290   // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
   2291   //
   2292   if (!ScsiDiskDevice->Cdb16Byte) {
   2293     MaxBlock         = 0xFFFF;
   2294   } else {
   2295     MaxBlock         = 0xFFFFFFFF;
   2296   }
   2297 
   2298   PtrBuffer = Buffer;
   2299 
   2300   while (BlocksRemaining > 0) {
   2301 
   2302     if (BlocksRemaining <= MaxBlock) {
   2303       if (!ScsiDiskDevice->Cdb16Byte) {
   2304         SectorCount = (UINT16) BlocksRemaining;
   2305       } else {
   2306         SectorCount = (UINT32) BlocksRemaining;
   2307       }
   2308     } else {
   2309       SectorCount = MaxBlock;
   2310     }
   2311 
   2312     ByteCount = SectorCount * BlockSize;
   2313     //
   2314     // |------------------------|-----------------|------------------|-----------------|
   2315     // |   ATA Transfer Mode    |  Transfer Rate  |  SCSI Interface  |  Transfer Rate  |
   2316     // |------------------------|-----------------|------------------|-----------------|
   2317     // |       PIO Mode 0       |  3.3Mbytes/sec  |     SCSI-1       |    5Mbytes/sec  |
   2318     // |------------------------|-----------------|------------------|-----------------|
   2319     // |       PIO Mode 1       |  5.2Mbytes/sec  |    Fast SCSI     |   10Mbytes/sec  |
   2320     // |------------------------|-----------------|------------------|-----------------|
   2321     // |       PIO Mode 2       |  8.3Mbytes/sec  |  Fast-Wide SCSI  |   20Mbytes/sec  |
   2322     // |------------------------|-----------------|------------------|-----------------|
   2323     // |       PIO Mode 3       | 11.1Mbytes/sec  |    Ultra SCSI    |   20Mbytes/sec  |
   2324     // |------------------------|-----------------|------------------|-----------------|
   2325     // |       PIO Mode 4       | 16.6Mbytes/sec  |  Ultra Wide SCSI |   40Mbytes/sec  |
   2326     // |------------------------|-----------------|------------------|-----------------|
   2327     // | Single-word DMA Mode 0 |  2.1Mbytes/sec  |    Ultra2 SCSI   |   40Mbytes/sec  |
   2328     // |------------------------|-----------------|------------------|-----------------|
   2329     // | Single-word DMA Mode 1 |  4.2Mbytes/sec  | Ultra2 Wide SCSI |   80Mbytes/sec  |
   2330     // |------------------------|-----------------|------------------|-----------------|
   2331     // | Single-word DMA Mode 2 |  8.4Mbytes/sec  |    Ultra3 SCSI   |  160Mbytes/sec  |
   2332     // |------------------------|-----------------|------------------|-----------------|
   2333     // | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |  Ultra-320 SCSI  |  320Mbytes/sec  |
   2334     // |------------------------|-----------------|------------------|-----------------|
   2335     // | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |  Ultra-640 SCSI  |  640Mbytes/sec  |
   2336     // |------------------------|-----------------|------------------|-----------------|
   2337     //
   2338     // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
   2339     // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
   2340     // From the above table, we could know 2.1Mbytes per second is lowest one.
   2341     // The timout value is rounded up to nearest integar and here an additional 30s is added
   2342     // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
   2343     // commands in the Standby/Idle mode.
   2344     //
   2345     Timeout   = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
   2346 
   2347     MaxRetry  = 2;
   2348     for (Index = 0; Index < MaxRetry; Index++) {
   2349       if (!ScsiDiskDevice->Cdb16Byte) {
   2350         Status = ScsiDiskRead10 (
   2351                   ScsiDiskDevice,
   2352                   &NeedRetry,
   2353                   Timeout,
   2354                   PtrBuffer,
   2355                   &ByteCount,
   2356                   (UINT32) Lba,
   2357                   SectorCount
   2358                   );
   2359       } else {
   2360         Status = ScsiDiskRead16 (
   2361                   ScsiDiskDevice,
   2362                   &NeedRetry,
   2363                   Timeout,
   2364                   PtrBuffer,
   2365                   &ByteCount,
   2366                   Lba,
   2367                   SectorCount
   2368                   );
   2369       }
   2370       if (!EFI_ERROR (Status)) {
   2371         break;
   2372       }
   2373 
   2374       if (!NeedRetry) {
   2375         return EFI_DEVICE_ERROR;
   2376       }
   2377 
   2378       //
   2379       // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
   2380       // lowered ByteCount on output, we must make sure that we lower
   2381       // SectorCount accordingly. SectorCount will be encoded in the CDB, and
   2382       // it is invalid to request more sectors in the CDB than the entire
   2383       // transfer (ie. ByteCount) can carry.
   2384       //
   2385       // In addition, ByteCount is only expected to go down, or stay unchaged.
   2386       // Therefore we don't need to update Timeout: the original timeout should
   2387       // accommodate shorter transfers too.
   2388       //
   2389       NextSectorCount = ByteCount / BlockSize;
   2390       if (NextSectorCount < SectorCount) {
   2391         SectorCount = NextSectorCount;
   2392         //
   2393         // Account for any rounding down.
   2394         //
   2395         ByteCount = SectorCount * BlockSize;
   2396       }
   2397     }
   2398 
   2399     if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
   2400       return EFI_DEVICE_ERROR;
   2401     }
   2402 
   2403     //
   2404     // actual transferred sectors
   2405     //
   2406     SectorCount = ByteCount / BlockSize;
   2407 
   2408     Lba += SectorCount;
   2409     PtrBuffer = PtrBuffer + SectorCount * BlockSize;
   2410     BlocksRemaining -= SectorCount;
   2411   }
   2412 
   2413   return EFI_SUCCESS;
   2414 }
   2415 
   2416 /**
   2417   Write sector to SCSI Disk.
   2418 
   2419   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
   2420   @param  Buffer          The buffer of data to be written into SCSI Disk
   2421   @param  Lba             Logic block address
   2422   @param  NumberOfBlocks  The number of blocks to read
   2423 
   2424   @retval EFI_DEVICE_ERROR  Indicates a device error.
   2425   @retval EFI_SUCCESS       Operation is successful.
   2426 
   2427 **/
   2428 EFI_STATUS
   2429 ScsiDiskWriteSectors (
   2430   IN  SCSI_DISK_DEV     *ScsiDiskDevice,
   2431   IN  VOID              *Buffer,
   2432   IN  EFI_LBA           Lba,
   2433   IN  UINTN             NumberOfBlocks
   2434   )
   2435 {
   2436   UINTN               BlocksRemaining;
   2437   UINT8               *PtrBuffer;
   2438   UINT32              BlockSize;
   2439   UINT32              ByteCount;
   2440   UINT32              MaxBlock;
   2441   UINT32              SectorCount;
   2442   UINT32              NextSectorCount;
   2443   UINT64              Timeout;
   2444   EFI_STATUS          Status;
   2445   UINT8               Index;
   2446   UINT8               MaxRetry;
   2447   BOOLEAN             NeedRetry;
   2448 
   2449   Status            = EFI_SUCCESS;
   2450 
   2451   BlocksRemaining   = NumberOfBlocks;
   2452   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;
   2453 
   2454   //
   2455   // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
   2456   //
   2457   if (!ScsiDiskDevice->Cdb16Byte) {
   2458     MaxBlock         = 0xFFFF;
   2459   } else {
   2460     MaxBlock         = 0xFFFFFFFF;
   2461   }
   2462 
   2463   PtrBuffer = Buffer;
   2464 
   2465   while (BlocksRemaining > 0) {
   2466 
   2467     if (BlocksRemaining <= MaxBlock) {
   2468       if (!ScsiDiskDevice->Cdb16Byte) {
   2469         SectorCount = (UINT16) BlocksRemaining;
   2470       } else {
   2471         SectorCount = (UINT32) BlocksRemaining;
   2472       }
   2473     } else {
   2474       SectorCount = MaxBlock;
   2475     }
   2476 
   2477     ByteCount = SectorCount * BlockSize;
   2478     //
   2479     // |------------------------|-----------------|------------------|-----------------|
   2480     // |   ATA Transfer Mode    |  Transfer Rate  |  SCSI Interface  |  Transfer Rate  |
   2481     // |------------------------|-----------------|------------------|-----------------|
   2482     // |       PIO Mode 0       |  3.3Mbytes/sec  |     SCSI-1       |    5Mbytes/sec  |
   2483     // |------------------------|-----------------|------------------|-----------------|
   2484     // |       PIO Mode 1       |  5.2Mbytes/sec  |    Fast SCSI     |   10Mbytes/sec  |
   2485     // |------------------------|-----------------|------------------|-----------------|
   2486     // |       PIO Mode 2       |  8.3Mbytes/sec  |  Fast-Wide SCSI  |   20Mbytes/sec  |
   2487     // |------------------------|-----------------|------------------|-----------------|
   2488     // |       PIO Mode 3       | 11.1Mbytes/sec  |    Ultra SCSI    |   20Mbytes/sec  |
   2489     // |------------------------|-----------------|------------------|-----------------|
   2490     // |       PIO Mode 4       | 16.6Mbytes/sec  |  Ultra Wide SCSI |   40Mbytes/sec  |
   2491     // |------------------------|-----------------|------------------|-----------------|
   2492     // | Single-word DMA Mode 0 |  2.1Mbytes/sec  |    Ultra2 SCSI   |   40Mbytes/sec  |
   2493     // |------------------------|-----------------|------------------|-----------------|
   2494     // | Single-word DMA Mode 1 |  4.2Mbytes/sec  | Ultra2 Wide SCSI |   80Mbytes/sec  |
   2495     // |------------------------|-----------------|------------------|-----------------|
   2496     // | Single-word DMA Mode 2 |  8.4Mbytes/sec  |    Ultra3 SCSI   |  160Mbytes/sec  |
   2497     // |------------------------|-----------------|------------------|-----------------|
   2498     // | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |  Ultra-320 SCSI  |  320Mbytes/sec  |
   2499     // |------------------------|-----------------|------------------|-----------------|
   2500     // | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |  Ultra-640 SCSI  |  640Mbytes/sec  |
   2501     // |------------------------|-----------------|------------------|-----------------|
   2502     //
   2503     // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
   2504     // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
   2505     // From the above table, we could know 2.1Mbytes per second is lowest one.
   2506     // The timout value is rounded up to nearest integar and here an additional 30s is added
   2507     // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
   2508     // commands in the Standby/Idle mode.
   2509     //
   2510     Timeout   = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
   2511     MaxRetry  = 2;
   2512     for (Index = 0; Index < MaxRetry; Index++) {
   2513       if (!ScsiDiskDevice->Cdb16Byte) {
   2514         Status = ScsiDiskWrite10 (
   2515                   ScsiDiskDevice,
   2516                   &NeedRetry,
   2517                   Timeout,
   2518                   PtrBuffer,
   2519                   &ByteCount,
   2520                   (UINT32) Lba,
   2521                   SectorCount
   2522                   );
   2523       } else {
   2524         Status = ScsiDiskWrite16 (
   2525                   ScsiDiskDevice,
   2526                   &NeedRetry,
   2527                   Timeout,
   2528                   PtrBuffer,
   2529                   &ByteCount,
   2530                   Lba,
   2531                   SectorCount
   2532                   );
   2533         }
   2534       if (!EFI_ERROR (Status)) {
   2535         break;
   2536       }
   2537 
   2538       if (!NeedRetry) {
   2539         return EFI_DEVICE_ERROR;
   2540       }
   2541 
   2542       //
   2543       // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
   2544       // has lowered ByteCount on output, we must make sure that we lower
   2545       // SectorCount accordingly. SectorCount will be encoded in the CDB, and
   2546       // it is invalid to request more sectors in the CDB than the entire
   2547       // transfer (ie. ByteCount) can carry.
   2548       //
   2549       // In addition, ByteCount is only expected to go down, or stay unchaged.
   2550       // Therefore we don't need to update Timeout: the original timeout should
   2551       // accommodate shorter transfers too.
   2552       //
   2553       NextSectorCount = ByteCount / BlockSize;
   2554       if (NextSectorCount < SectorCount) {
   2555         SectorCount = NextSectorCount;
   2556         //
   2557         // Account for any rounding down.
   2558         //
   2559         ByteCount = SectorCount * BlockSize;
   2560       }
   2561     }
   2562 
   2563     if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
   2564       return EFI_DEVICE_ERROR;
   2565     }
   2566     //
   2567     // actual transferred sectors
   2568     //
   2569     SectorCount = ByteCount / BlockSize;
   2570 
   2571     Lba += SectorCount;
   2572     PtrBuffer = PtrBuffer + SectorCount * BlockSize;
   2573     BlocksRemaining -= SectorCount;
   2574   }
   2575 
   2576   return EFI_SUCCESS;
   2577 }
   2578 
   2579 /**
   2580   Asynchronously read sector from SCSI Disk.
   2581 
   2582   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV.
   2583   @param  Buffer          The buffer to fill in the read out data.
   2584   @param  Lba             Logic block address.
   2585   @param  NumberOfBlocks  The number of blocks to read.
   2586   @param  Token           A pointer to the token associated with the
   2587                           non-blocking read request.
   2588 
   2589   @retval EFI_INVALID_PARAMETER  Token is NULL or Token->Event is NULL.
   2590   @retval EFI_DEVICE_ERROR       Indicates a device error.
   2591   @retval EFI_SUCCESS            Operation is successful.
   2592 
   2593 **/
   2594 EFI_STATUS
   2595 ScsiDiskAsyncReadSectors (
   2596   IN   SCSI_DISK_DEV         *ScsiDiskDevice,
   2597   OUT  VOID                  *Buffer,
   2598   IN   EFI_LBA               Lba,
   2599   IN   UINTN                 NumberOfBlocks,
   2600   IN   EFI_BLOCK_IO2_TOKEN   *Token
   2601   )
   2602 {
   2603   UINTN                 BlocksRemaining;
   2604   UINT8                 *PtrBuffer;
   2605   UINT32                BlockSize;
   2606   UINT32                ByteCount;
   2607   UINT32                MaxBlock;
   2608   UINT32                SectorCount;
   2609   UINT64                Timeout;
   2610   SCSI_BLKIO2_REQUEST   *BlkIo2Req;
   2611   EFI_STATUS            Status;
   2612   EFI_TPL               OldTpl;
   2613 
   2614   if ((Token == NULL) || (Token->Event == NULL)) {
   2615     return EFI_INVALID_PARAMETER;
   2616   }
   2617 
   2618   BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
   2619   if (BlkIo2Req == NULL) {
   2620     return EFI_OUT_OF_RESOURCES;
   2621   }
   2622 
   2623   BlkIo2Req->Token  = Token;
   2624 
   2625   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   2626   InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link);
   2627   gBS->RestoreTPL (OldTpl);
   2628 
   2629   InitializeListHead (&BlkIo2Req->ScsiRWQueue);
   2630 
   2631   Status            = EFI_SUCCESS;
   2632 
   2633   BlocksRemaining   = NumberOfBlocks;
   2634   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;
   2635 
   2636   //
   2637   // Limit the data bytes that can be transferred by one Read(10) or Read(16)
   2638   // Command
   2639   //
   2640   if (!ScsiDiskDevice->Cdb16Byte) {
   2641     MaxBlock         = 0xFFFF;
   2642   } else {
   2643     MaxBlock         = 0xFFFFFFFF;
   2644   }
   2645 
   2646   PtrBuffer = Buffer;
   2647 
   2648   while (BlocksRemaining > 0) {
   2649 
   2650     if (BlocksRemaining <= MaxBlock) {
   2651       if (!ScsiDiskDevice->Cdb16Byte) {
   2652         SectorCount = (UINT16) BlocksRemaining;
   2653       } else {
   2654         SectorCount = (UINT32) BlocksRemaining;
   2655       }
   2656     } else {
   2657       SectorCount = MaxBlock;
   2658     }
   2659 
   2660     ByteCount = SectorCount * BlockSize;
   2661     //
   2662     // |------------------------|-----------------|------------------|-----------------|
   2663     // |   ATA Transfer Mode    |  Transfer Rate  |  SCSI Interface  |  Transfer Rate  |
   2664     // |------------------------|-----------------|------------------|-----------------|
   2665     // |       PIO Mode 0       |  3.3Mbytes/sec  |     SCSI-1       |    5Mbytes/sec  |
   2666     // |------------------------|-----------------|------------------|-----------------|
   2667     // |       PIO Mode 1       |  5.2Mbytes/sec  |    Fast SCSI     |   10Mbytes/sec  |
   2668     // |------------------------|-----------------|------------------|-----------------|
   2669     // |       PIO Mode 2       |  8.3Mbytes/sec  |  Fast-Wide SCSI  |   20Mbytes/sec  |
   2670     // |------------------------|-----------------|------------------|-----------------|
   2671     // |       PIO Mode 3       | 11.1Mbytes/sec  |    Ultra SCSI    |   20Mbytes/sec  |
   2672     // |------------------------|-----------------|------------------|-----------------|
   2673     // |       PIO Mode 4       | 16.6Mbytes/sec  |  Ultra Wide SCSI |   40Mbytes/sec  |
   2674     // |------------------------|-----------------|------------------|-----------------|
   2675     // | Single-word DMA Mode 0 |  2.1Mbytes/sec  |    Ultra2 SCSI   |   40Mbytes/sec  |
   2676     // |------------------------|-----------------|------------------|-----------------|
   2677     // | Single-word DMA Mode 1 |  4.2Mbytes/sec  | Ultra2 Wide SCSI |   80Mbytes/sec  |
   2678     // |------------------------|-----------------|------------------|-----------------|
   2679     // | Single-word DMA Mode 2 |  8.4Mbytes/sec  |    Ultra3 SCSI   |  160Mbytes/sec  |
   2680     // |------------------------|-----------------|------------------|-----------------|
   2681     // | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |  Ultra-320 SCSI  |  320Mbytes/sec  |
   2682     // |------------------------|-----------------|------------------|-----------------|
   2683     // | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |  Ultra-640 SCSI  |  640Mbytes/sec  |
   2684     // |------------------------|-----------------|------------------|-----------------|
   2685     //
   2686     // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
   2687     // we have to use the lowest transfer rate to calculate the possible
   2688     // maximum timeout value for each operation.
   2689     // From the above table, we could know 2.1Mbytes per second is lowest one.
   2690     // The timout value is rounded up to nearest integar and here an additional
   2691     // 30s is added to follow ATA spec in which it mentioned that the device
   2692     // may take up to 30s to respond commands in the Standby/Idle mode.
   2693     //
   2694     Timeout   = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
   2695 
   2696     if (!ScsiDiskDevice->Cdb16Byte) {
   2697       Status = ScsiDiskAsyncRead10 (
   2698                  ScsiDiskDevice,
   2699                  Timeout,
   2700                  0,
   2701                  PtrBuffer,
   2702                  ByteCount,
   2703                  (UINT32) Lba,
   2704                  SectorCount,
   2705                  BlkIo2Req,
   2706                  Token
   2707                  );
   2708     } else {
   2709       Status = ScsiDiskAsyncRead16 (
   2710                  ScsiDiskDevice,
   2711                  Timeout,
   2712                  0,
   2713                  PtrBuffer,
   2714                  ByteCount,
   2715                  Lba,
   2716                  SectorCount,
   2717                  BlkIo2Req,
   2718                  Token
   2719                  );
   2720     }
   2721     if (EFI_ERROR (Status)) {
   2722       //
   2723       // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
   2724       // length of a SCSI I/O command is too large.
   2725       // In this case, we retry sending the SCSI command with a data length
   2726       // half of its previous value.
   2727       //
   2728       if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
   2729         if ((MaxBlock > 1) && (SectorCount > 1)) {
   2730           MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
   2731           continue;
   2732         }
   2733       }
   2734 
   2735       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   2736       if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
   2737         //
   2738         // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
   2739         // SCSI sub-task running. Otherwise, it will be freed in the callback
   2740         // function ScsiDiskNotify().
   2741         //
   2742         RemoveEntryList (&BlkIo2Req->Link);
   2743         FreePool (BlkIo2Req);
   2744         BlkIo2Req = NULL;
   2745         gBS->RestoreTPL (OldTpl);
   2746 
   2747         //
   2748         // It is safe to return error status to the caller, since there is no
   2749         // previous SCSI sub-task executing.
   2750         //
   2751         Status = EFI_DEVICE_ERROR;
   2752         goto Done;
   2753       } else {
   2754         gBS->RestoreTPL (OldTpl);
   2755 
   2756         //
   2757         // There are previous SCSI commands still running, EFI_SUCCESS should
   2758         // be returned to make sure that the caller does not free resources
   2759         // still using by these SCSI commands.
   2760         //
   2761         Status = EFI_SUCCESS;
   2762         goto Done;
   2763       }
   2764     }
   2765 
   2766     //
   2767     // Sectors submitted for transfer
   2768     //
   2769     SectorCount = ByteCount / BlockSize;
   2770 
   2771     Lba += SectorCount;
   2772     PtrBuffer = PtrBuffer + SectorCount * BlockSize;
   2773     BlocksRemaining -= SectorCount;
   2774   }
   2775 
   2776   Status = EFI_SUCCESS;
   2777 
   2778 Done:
   2779   if (BlkIo2Req != NULL) {
   2780     BlkIo2Req->LastScsiRW = TRUE;
   2781 
   2782     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   2783     if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
   2784       RemoveEntryList (&BlkIo2Req->Link);
   2785       FreePool (BlkIo2Req);
   2786       BlkIo2Req = NULL;
   2787 
   2788       gBS->SignalEvent (Token->Event);
   2789     }
   2790     gBS->RestoreTPL (OldTpl);
   2791   }
   2792 
   2793   return Status;
   2794 }
   2795 
   2796 /**
   2797   Asynchronously write sector to SCSI Disk.
   2798 
   2799   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV.
   2800   @param  Buffer          The buffer of data to be written into SCSI Disk.
   2801   @param  Lba             Logic block address.
   2802   @param  NumberOfBlocks  The number of blocks to read.
   2803   @param  Token           A pointer to the token associated with the
   2804                           non-blocking read request.
   2805 
   2806   @retval EFI_INVALID_PARAMETER  Token is NULL or Token->Event is NULL
   2807   @retval EFI_DEVICE_ERROR  Indicates a device error.
   2808   @retval EFI_SUCCESS       Operation is successful.
   2809 
   2810 **/
   2811 EFI_STATUS
   2812 ScsiDiskAsyncWriteSectors (
   2813   IN  SCSI_DISK_DEV          *ScsiDiskDevice,
   2814   IN  VOID                   *Buffer,
   2815   IN  EFI_LBA                Lba,
   2816   IN  UINTN                  NumberOfBlocks,
   2817   IN  EFI_BLOCK_IO2_TOKEN    *Token
   2818   )
   2819 {
   2820   UINTN                 BlocksRemaining;
   2821   UINT8                 *PtrBuffer;
   2822   UINT32                BlockSize;
   2823   UINT32                ByteCount;
   2824   UINT32                MaxBlock;
   2825   UINT32                SectorCount;
   2826   UINT64                Timeout;
   2827   SCSI_BLKIO2_REQUEST   *BlkIo2Req;
   2828   EFI_STATUS            Status;
   2829   EFI_TPL               OldTpl;
   2830 
   2831   if ((Token == NULL) || (Token->Event == NULL)) {
   2832     return EFI_INVALID_PARAMETER;
   2833   }
   2834 
   2835   BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));
   2836   if (BlkIo2Req == NULL) {
   2837     return EFI_OUT_OF_RESOURCES;
   2838   }
   2839 
   2840   BlkIo2Req->Token  = Token;
   2841 
   2842   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   2843   InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link);
   2844   gBS->RestoreTPL (OldTpl);
   2845 
   2846   InitializeListHead (&BlkIo2Req->ScsiRWQueue);
   2847 
   2848   Status            = EFI_SUCCESS;
   2849 
   2850   BlocksRemaining   = NumberOfBlocks;
   2851   BlockSize         = ScsiDiskDevice->BlkIo.Media->BlockSize;
   2852 
   2853   //
   2854   // Limit the data bytes that can be transferred by one Read(10) or Read(16)
   2855   // Command
   2856   //
   2857   if (!ScsiDiskDevice->Cdb16Byte) {
   2858     MaxBlock         = 0xFFFF;
   2859   } else {
   2860     MaxBlock         = 0xFFFFFFFF;
   2861   }
   2862 
   2863   PtrBuffer = Buffer;
   2864 
   2865   while (BlocksRemaining > 0) {
   2866 
   2867     if (BlocksRemaining <= MaxBlock) {
   2868       if (!ScsiDiskDevice->Cdb16Byte) {
   2869         SectorCount = (UINT16) BlocksRemaining;
   2870       } else {
   2871         SectorCount = (UINT32) BlocksRemaining;
   2872       }
   2873     } else {
   2874       SectorCount = MaxBlock;
   2875     }
   2876 
   2877     ByteCount = SectorCount * BlockSize;
   2878     //
   2879     // |------------------------|-----------------|------------------|-----------------|
   2880     // |   ATA Transfer Mode    |  Transfer Rate  |  SCSI Interface  |  Transfer Rate  |
   2881     // |------------------------|-----------------|------------------|-----------------|
   2882     // |       PIO Mode 0       |  3.3Mbytes/sec  |     SCSI-1       |    5Mbytes/sec  |
   2883     // |------------------------|-----------------|------------------|-----------------|
   2884     // |       PIO Mode 1       |  5.2Mbytes/sec  |    Fast SCSI     |   10Mbytes/sec  |
   2885     // |------------------------|-----------------|------------------|-----------------|
   2886     // |       PIO Mode 2       |  8.3Mbytes/sec  |  Fast-Wide SCSI  |   20Mbytes/sec  |
   2887     // |------------------------|-----------------|------------------|-----------------|
   2888     // |       PIO Mode 3       | 11.1Mbytes/sec  |    Ultra SCSI    |   20Mbytes/sec  |
   2889     // |------------------------|-----------------|------------------|-----------------|
   2890     // |       PIO Mode 4       | 16.6Mbytes/sec  |  Ultra Wide SCSI |   40Mbytes/sec  |
   2891     // |------------------------|-----------------|------------------|-----------------|
   2892     // | Single-word DMA Mode 0 |  2.1Mbytes/sec  |    Ultra2 SCSI   |   40Mbytes/sec  |
   2893     // |------------------------|-----------------|------------------|-----------------|
   2894     // | Single-word DMA Mode 1 |  4.2Mbytes/sec  | Ultra2 Wide SCSI |   80Mbytes/sec  |
   2895     // |------------------------|-----------------|------------------|-----------------|
   2896     // | Single-word DMA Mode 2 |  8.4Mbytes/sec  |    Ultra3 SCSI   |  160Mbytes/sec  |
   2897     // |------------------------|-----------------|------------------|-----------------|
   2898     // | Multi-word DMA Mode 0  |  4.2Mbytes/sec  |  Ultra-320 SCSI  |  320Mbytes/sec  |
   2899     // |------------------------|-----------------|------------------|-----------------|
   2900     // | Multi-word DMA Mode 1  | 13.3Mbytes/sec  |  Ultra-640 SCSI  |  640Mbytes/sec  |
   2901     // |------------------------|-----------------|------------------|-----------------|
   2902     //
   2903     // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
   2904     // we have to use the lowest transfer rate to calculate the possible
   2905     // maximum timeout value for each operation.
   2906     // From the above table, we could know 2.1Mbytes per second is lowest one.
   2907     // The timout value is rounded up to nearest integar and here an additional
   2908     // 30s is added to follow ATA spec in which it mentioned that the device
   2909     // may take up to 30s to respond commands in the Standby/Idle mode.
   2910     //
   2911     Timeout   = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);
   2912 
   2913     if (!ScsiDiskDevice->Cdb16Byte) {
   2914       Status = ScsiDiskAsyncWrite10 (
   2915                  ScsiDiskDevice,
   2916                  Timeout,
   2917                  0,
   2918                  PtrBuffer,
   2919                  ByteCount,
   2920                  (UINT32) Lba,
   2921                  SectorCount,
   2922                  BlkIo2Req,
   2923                  Token
   2924                  );
   2925     } else {
   2926       Status = ScsiDiskAsyncWrite16 (
   2927                  ScsiDiskDevice,
   2928                  Timeout,
   2929                  0,
   2930                  PtrBuffer,
   2931                  ByteCount,
   2932                  Lba,
   2933                  SectorCount,
   2934                  BlkIo2Req,
   2935                  Token
   2936                  );
   2937     }
   2938     if (EFI_ERROR (Status)) {
   2939       //
   2940       // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
   2941       // length of a SCSI I/O command is too large.
   2942       // In this case, we retry sending the SCSI command with a data length
   2943       // half of its previous value.
   2944       //
   2945       if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
   2946         if ((MaxBlock > 1) && (SectorCount > 1)) {
   2947           MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
   2948           continue;
   2949         }
   2950       }
   2951 
   2952       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   2953       if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
   2954         //
   2955         // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
   2956         // SCSI sub-task running. Otherwise, it will be freed in the callback
   2957         // function ScsiDiskNotify().
   2958         //
   2959         RemoveEntryList (&BlkIo2Req->Link);
   2960         FreePool (BlkIo2Req);
   2961         BlkIo2Req = NULL;
   2962         gBS->RestoreTPL (OldTpl);
   2963 
   2964         //
   2965         // It is safe to return error status to the caller, since there is no
   2966         // previous SCSI sub-task executing.
   2967         //
   2968         Status = EFI_DEVICE_ERROR;
   2969         goto Done;
   2970       } else {
   2971         gBS->RestoreTPL (OldTpl);
   2972 
   2973         //
   2974         // There are previous SCSI commands still running, EFI_SUCCESS should
   2975         // be returned to make sure that the caller does not free resources
   2976         // still using by these SCSI commands.
   2977         //
   2978         Status = EFI_SUCCESS;
   2979         goto Done;
   2980       }
   2981     }
   2982 
   2983     //
   2984     // Sectors submitted for transfer
   2985     //
   2986     SectorCount = ByteCount / BlockSize;
   2987 
   2988     Lba += SectorCount;
   2989     PtrBuffer = PtrBuffer + SectorCount * BlockSize;
   2990     BlocksRemaining -= SectorCount;
   2991   }
   2992 
   2993   Status = EFI_SUCCESS;
   2994 
   2995 Done:
   2996   if (BlkIo2Req != NULL) {
   2997     BlkIo2Req->LastScsiRW = TRUE;
   2998 
   2999     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   3000     if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
   3001       RemoveEntryList (&BlkIo2Req->Link);
   3002       FreePool (BlkIo2Req);
   3003       BlkIo2Req = NULL;
   3004 
   3005       gBS->SignalEvent (Token->Event);
   3006     }
   3007     gBS->RestoreTPL (OldTpl);
   3008   }
   3009 
   3010   return Status;
   3011 }
   3012 
   3013 
   3014 /**
   3015   Submit Read(10) command.
   3016 
   3017   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice
   3018   @param  NeedRetry          The pointer of flag indicates if needs retry if error happens
   3019   @param  Timeout            The time to complete the command
   3020   @param  DataBuffer         The buffer to fill with the read out data
   3021   @param  DataLength         The length of buffer
   3022   @param  StartLba           The start logic block address
   3023   @param  SectorCount        The number of blocks to read
   3024 
   3025   @return  EFI_STATUS is returned by calling ScsiRead10Command().
   3026 **/
   3027 EFI_STATUS
   3028 ScsiDiskRead10 (
   3029   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
   3030      OUT BOOLEAN               *NeedRetry,
   3031   IN     UINT64                Timeout,
   3032      OUT UINT8                 *DataBuffer,
   3033   IN OUT UINT32                *DataLength,
   3034   IN     UINT32                StartLba,
   3035   IN     UINT32                SectorCount
   3036   )
   3037 {
   3038   UINT8       SenseDataLength;
   3039   EFI_STATUS  Status;
   3040   EFI_STATUS  ReturnStatus;
   3041   UINT8       HostAdapterStatus;
   3042   UINT8       TargetStatus;
   3043   UINTN       Action;
   3044 
   3045   //
   3046   // Implement a backoff algorithem to resolve some compatibility issues that
   3047   // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
   3048   // big data in a single operation.
   3049   // This algorithem will at first try to execute original request. If the request fails
   3050   // with media error sense data or else, it will reduce the transfer length to half and
   3051   // try again till the operation succeeds or fails with one sector transfer length.
   3052   //
   3053 BackOff:
   3054   *NeedRetry          = FALSE;
   3055   Action              = ACTION_NO_ACTION;
   3056   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
   3057   ReturnStatus = ScsiRead10Command (
   3058                    ScsiDiskDevice->ScsiIo,
   3059                    Timeout,
   3060                    ScsiDiskDevice->SenseData,
   3061                    &SenseDataLength,
   3062                    &HostAdapterStatus,
   3063                    &TargetStatus,
   3064                    DataBuffer,
   3065                    DataLength,
   3066                    StartLba,
   3067                    SectorCount
   3068                    );
   3069 
   3070   if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
   3071     *NeedRetry = TRUE;
   3072     return EFI_DEVICE_ERROR;
   3073   } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
   3074     *NeedRetry = FALSE;
   3075     return ReturnStatus;
   3076   }
   3077 
   3078   //
   3079   // go ahead to check HostAdapterStatus and TargetStatus
   3080   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
   3081   //
   3082   Status = CheckHostAdapterStatus (HostAdapterStatus);
   3083   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
   3084     *NeedRetry = TRUE;
   3085     return EFI_DEVICE_ERROR;
   3086   } else if (Status == EFI_DEVICE_ERROR) {
   3087     //
   3088     // reset the scsi channel
   3089     //
   3090     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
   3091     *NeedRetry = FALSE;
   3092     return EFI_DEVICE_ERROR;
   3093   }
   3094 
   3095   Status = CheckTargetStatus (TargetStatus);
   3096   if (Status == EFI_NOT_READY) {
   3097     //
   3098     // reset the scsi device
   3099     //
   3100     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
   3101     *NeedRetry = TRUE;
   3102     return EFI_DEVICE_ERROR;
   3103   } else if (Status == EFI_DEVICE_ERROR) {
   3104     *NeedRetry = FALSE;
   3105     return EFI_DEVICE_ERROR;
   3106   }
   3107 
   3108   if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
   3109     DEBUG ((EFI_D_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));
   3110     Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
   3111     if (Action == ACTION_RETRY_COMMAND_LATER) {
   3112       *NeedRetry = TRUE;
   3113       return EFI_DEVICE_ERROR;
   3114     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
   3115       if (SectorCount <= 1) {
   3116         //
   3117         // Jump out if the operation still fails with one sector transfer length.
   3118         //
   3119         *NeedRetry = FALSE;
   3120         return EFI_DEVICE_ERROR;
   3121       }
   3122       //
   3123       // Try again with half length if the sense data shows we need to retry.
   3124       //
   3125       SectorCount >>= 1;
   3126       *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
   3127       goto BackOff;
   3128     } else {
   3129       *NeedRetry = FALSE;
   3130       return EFI_DEVICE_ERROR;
   3131     }
   3132   }
   3133 
   3134   return ReturnStatus;
   3135 }
   3136 
   3137 
   3138 /**
   3139   Submit Write(10) Command.
   3140 
   3141   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice
   3142   @param  NeedRetry          The pointer of flag indicates if needs retry if error happens
   3143   @param  Timeout            The time to complete the command
   3144   @param  DataBuffer         The buffer to fill with the read out data
   3145   @param  DataLength         The length of buffer
   3146   @param  StartLba           The start logic block address
   3147   @param  SectorCount        The number of blocks to write
   3148 
   3149   @return  EFI_STATUS is returned by calling ScsiWrite10Command().
   3150 
   3151 **/
   3152 EFI_STATUS
   3153 ScsiDiskWrite10 (
   3154   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
   3155      OUT BOOLEAN               *NeedRetry,
   3156   IN     UINT64                Timeout,
   3157   IN     UINT8                 *DataBuffer,
   3158   IN OUT UINT32                *DataLength,
   3159   IN     UINT32                StartLba,
   3160   IN     UINT32                SectorCount
   3161   )
   3162 {
   3163   EFI_STATUS  Status;
   3164   EFI_STATUS  ReturnStatus;
   3165   UINT8       SenseDataLength;
   3166   UINT8       HostAdapterStatus;
   3167   UINT8       TargetStatus;
   3168   UINTN       Action;
   3169 
   3170   //
   3171   // Implement a backoff algorithem to resolve some compatibility issues that
   3172   // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
   3173   // big data in a single operation.
   3174   // This algorithem will at first try to execute original request. If the request fails
   3175   // with media error sense data or else, it will reduce the transfer length to half and
   3176   // try again till the operation succeeds or fails with one sector transfer length.
   3177   //
   3178 BackOff:
   3179   *NeedRetry          = FALSE;
   3180   Action              = ACTION_NO_ACTION;
   3181   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
   3182   ReturnStatus = ScsiWrite10Command (
   3183                    ScsiDiskDevice->ScsiIo,
   3184                    Timeout,
   3185                    ScsiDiskDevice->SenseData,
   3186                    &SenseDataLength,
   3187                    &HostAdapterStatus,
   3188                    &TargetStatus,
   3189                    DataBuffer,
   3190                    DataLength,
   3191                    StartLba,
   3192                    SectorCount
   3193                    );
   3194   if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
   3195     *NeedRetry = TRUE;
   3196     return EFI_DEVICE_ERROR;
   3197   } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
   3198     *NeedRetry = FALSE;
   3199     return ReturnStatus;
   3200   }
   3201 
   3202   //
   3203   // go ahead to check HostAdapterStatus and TargetStatus
   3204   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
   3205   //
   3206   Status = CheckHostAdapterStatus (HostAdapterStatus);
   3207   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
   3208     *NeedRetry = TRUE;
   3209     return EFI_DEVICE_ERROR;
   3210   } else if (Status == EFI_DEVICE_ERROR) {
   3211     //
   3212     // reset the scsi channel
   3213     //
   3214     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
   3215     *NeedRetry = FALSE;
   3216     return EFI_DEVICE_ERROR;
   3217   }
   3218 
   3219   Status = CheckTargetStatus (TargetStatus);
   3220   if (Status == EFI_NOT_READY) {
   3221     //
   3222     // reset the scsi device
   3223     //
   3224     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
   3225     *NeedRetry = TRUE;
   3226     return EFI_DEVICE_ERROR;
   3227   } else if (Status == EFI_DEVICE_ERROR) {
   3228     *NeedRetry = FALSE;
   3229     return EFI_DEVICE_ERROR;
   3230   }
   3231 
   3232   if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
   3233     DEBUG ((EFI_D_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));
   3234     Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
   3235     if (Action == ACTION_RETRY_COMMAND_LATER) {
   3236       *NeedRetry = TRUE;
   3237       return EFI_DEVICE_ERROR;
   3238     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
   3239       if (SectorCount <= 1) {
   3240         //
   3241         // Jump out if the operation still fails with one sector transfer length.
   3242         //
   3243         *NeedRetry = FALSE;
   3244         return EFI_DEVICE_ERROR;
   3245       }
   3246       //
   3247       // Try again with half length if the sense data shows we need to retry.
   3248       //
   3249       SectorCount >>= 1;
   3250       *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
   3251       goto BackOff;
   3252     } else {
   3253       *NeedRetry = FALSE;
   3254       return EFI_DEVICE_ERROR;
   3255     }
   3256   }
   3257 
   3258   return ReturnStatus;
   3259 }
   3260 
   3261 
   3262 /**
   3263   Submit Read(16) command.
   3264 
   3265   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice
   3266   @param  NeedRetry          The pointer of flag indicates if needs retry if error happens
   3267   @param  Timeout            The time to complete the command
   3268   @param  DataBuffer         The buffer to fill with the read out data
   3269   @param  DataLength         The length of buffer
   3270   @param  StartLba           The start logic block address
   3271   @param  SectorCount        The number of blocks to read
   3272 
   3273   @return  EFI_STATUS is returned by calling ScsiRead16Command().
   3274 **/
   3275 EFI_STATUS
   3276 ScsiDiskRead16 (
   3277   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
   3278      OUT BOOLEAN               *NeedRetry,
   3279   IN     UINT64                Timeout,
   3280      OUT UINT8                 *DataBuffer,
   3281   IN OUT UINT32                *DataLength,
   3282   IN     UINT64                StartLba,
   3283   IN     UINT32                SectorCount
   3284   )
   3285 {
   3286   UINT8       SenseDataLength;
   3287   EFI_STATUS  Status;
   3288   EFI_STATUS  ReturnStatus;
   3289   UINT8       HostAdapterStatus;
   3290   UINT8       TargetStatus;
   3291   UINTN       Action;
   3292 
   3293   //
   3294   // Implement a backoff algorithem to resolve some compatibility issues that
   3295   // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
   3296   // big data in a single operation.
   3297   // This algorithem will at first try to execute original request. If the request fails
   3298   // with media error sense data or else, it will reduce the transfer length to half and
   3299   // try again till the operation succeeds or fails with one sector transfer length.
   3300   //
   3301 BackOff:
   3302   *NeedRetry          = FALSE;
   3303   Action              = ACTION_NO_ACTION;
   3304   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
   3305   ReturnStatus = ScsiRead16Command (
   3306                    ScsiDiskDevice->ScsiIo,
   3307                    Timeout,
   3308                    ScsiDiskDevice->SenseData,
   3309                    &SenseDataLength,
   3310                    &HostAdapterStatus,
   3311                    &TargetStatus,
   3312                    DataBuffer,
   3313                    DataLength,
   3314                    StartLba,
   3315                    SectorCount
   3316                    );
   3317   if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
   3318     *NeedRetry = TRUE;
   3319     return EFI_DEVICE_ERROR;
   3320   } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
   3321     *NeedRetry = FALSE;
   3322     return ReturnStatus;
   3323   }
   3324 
   3325   //
   3326   // go ahead to check HostAdapterStatus and TargetStatus
   3327   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
   3328   //
   3329   Status = CheckHostAdapterStatus (HostAdapterStatus);
   3330   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
   3331     *NeedRetry = TRUE;
   3332     return EFI_DEVICE_ERROR;
   3333   } else if (Status == EFI_DEVICE_ERROR) {
   3334     //
   3335     // reset the scsi channel
   3336     //
   3337     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
   3338     *NeedRetry = FALSE;
   3339     return EFI_DEVICE_ERROR;
   3340   }
   3341 
   3342   Status = CheckTargetStatus (TargetStatus);
   3343   if (Status == EFI_NOT_READY) {
   3344     //
   3345     // reset the scsi device
   3346     //
   3347     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
   3348     *NeedRetry = TRUE;
   3349     return EFI_DEVICE_ERROR;
   3350   } else if (Status == EFI_DEVICE_ERROR) {
   3351     *NeedRetry = FALSE;
   3352     return EFI_DEVICE_ERROR;
   3353   }
   3354 
   3355   if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
   3356     DEBUG ((EFI_D_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));
   3357     Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
   3358     if (Action == ACTION_RETRY_COMMAND_LATER) {
   3359       *NeedRetry = TRUE;
   3360       return EFI_DEVICE_ERROR;
   3361     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
   3362       if (SectorCount <= 1) {
   3363         //
   3364         // Jump out if the operation still fails with one sector transfer length.
   3365         //
   3366         *NeedRetry = FALSE;
   3367         return EFI_DEVICE_ERROR;
   3368       }
   3369       //
   3370       // Try again with half length if the sense data shows we need to retry.
   3371       //
   3372       SectorCount >>= 1;
   3373       *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
   3374       goto BackOff;
   3375     } else {
   3376       *NeedRetry = FALSE;
   3377       return EFI_DEVICE_ERROR;
   3378     }
   3379   }
   3380 
   3381   return ReturnStatus;
   3382 }
   3383 
   3384 
   3385 /**
   3386   Submit Write(16) Command.
   3387 
   3388   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice
   3389   @param  NeedRetry          The pointer of flag indicates if needs retry if error happens
   3390   @param  Timeout            The time to complete the command
   3391   @param  DataBuffer         The buffer to fill with the read out data
   3392   @param  DataLength         The length of buffer
   3393   @param  StartLba           The start logic block address
   3394   @param  SectorCount        The number of blocks to write
   3395 
   3396   @return  EFI_STATUS is returned by calling ScsiWrite16Command().
   3397 
   3398 **/
   3399 EFI_STATUS
   3400 ScsiDiskWrite16 (
   3401   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
   3402      OUT BOOLEAN               *NeedRetry,
   3403   IN     UINT64                Timeout,
   3404   IN     UINT8                 *DataBuffer,
   3405   IN OUT UINT32                *DataLength,
   3406   IN     UINT64                StartLba,
   3407   IN     UINT32                SectorCount
   3408   )
   3409 {
   3410   EFI_STATUS  Status;
   3411   EFI_STATUS  ReturnStatus;
   3412   UINT8       SenseDataLength;
   3413   UINT8       HostAdapterStatus;
   3414   UINT8       TargetStatus;
   3415   UINTN       Action;
   3416 
   3417   //
   3418   // Implement a backoff algorithem to resolve some compatibility issues that
   3419   // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
   3420   // big data in a single operation.
   3421   // This algorithem will at first try to execute original request. If the request fails
   3422   // with media error sense data or else, it will reduce the transfer length to half and
   3423   // try again till the operation succeeds or fails with one sector transfer length.
   3424   //
   3425 BackOff:
   3426   *NeedRetry          = FALSE;
   3427   Action              = ACTION_NO_ACTION;
   3428   SenseDataLength     = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));
   3429   ReturnStatus = ScsiWrite16Command (
   3430                    ScsiDiskDevice->ScsiIo,
   3431                    Timeout,
   3432                    ScsiDiskDevice->SenseData,
   3433                    &SenseDataLength,
   3434                    &HostAdapterStatus,
   3435                    &TargetStatus,
   3436                    DataBuffer,
   3437                    DataLength,
   3438                    StartLba,
   3439                    SectorCount
   3440                    );
   3441   if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) {
   3442     *NeedRetry = TRUE;
   3443     return EFI_DEVICE_ERROR;
   3444   } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {
   3445     *NeedRetry = FALSE;
   3446     return ReturnStatus;
   3447   }
   3448 
   3449   //
   3450   // go ahead to check HostAdapterStatus and TargetStatus
   3451   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
   3452   //
   3453   Status = CheckHostAdapterStatus (HostAdapterStatus);
   3454   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
   3455     *NeedRetry = TRUE;
   3456     return EFI_DEVICE_ERROR;
   3457   } else if (Status == EFI_DEVICE_ERROR) {
   3458     //
   3459     // reset the scsi channel
   3460     //
   3461     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
   3462     *NeedRetry = FALSE;
   3463     return EFI_DEVICE_ERROR;
   3464   }
   3465 
   3466   Status = CheckTargetStatus (TargetStatus);
   3467   if (Status == EFI_NOT_READY) {
   3468     //
   3469     // reset the scsi device
   3470     //
   3471     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
   3472     *NeedRetry = TRUE;
   3473     return EFI_DEVICE_ERROR;
   3474   } else if (Status == EFI_DEVICE_ERROR) {
   3475     *NeedRetry = FALSE;
   3476     return EFI_DEVICE_ERROR;
   3477   }
   3478 
   3479   if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {
   3480     DEBUG ((EFI_D_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));
   3481     Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);
   3482     if (Action == ACTION_RETRY_COMMAND_LATER) {
   3483       *NeedRetry = TRUE;
   3484       return EFI_DEVICE_ERROR;
   3485     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
   3486       if (SectorCount <= 1) {
   3487         //
   3488         // Jump out if the operation still fails with one sector transfer length.
   3489         //
   3490         *NeedRetry = FALSE;
   3491         return EFI_DEVICE_ERROR;
   3492       }
   3493       //
   3494       // Try again with half length if the sense data shows we need to retry.
   3495       //
   3496       SectorCount >>= 1;
   3497       *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
   3498       goto BackOff;
   3499     } else {
   3500       *NeedRetry = FALSE;
   3501       return EFI_DEVICE_ERROR;
   3502     }
   3503   }
   3504 
   3505   return ReturnStatus;
   3506 }
   3507 
   3508 
   3509 /**
   3510   Internal helper notify function in which determine whether retry of a SCSI
   3511   Read/Write command is needed and signal the event passed from Block I/O(2) if
   3512   the SCSI I/O operation completes.
   3513 
   3514   @param  Event    The instance of EFI_EVENT.
   3515   @param  Context  The parameter passed in.
   3516 
   3517 **/
   3518 VOID
   3519 EFIAPI
   3520 ScsiDiskNotify (
   3521   IN  EFI_EVENT  Event,
   3522   IN  VOID       *Context
   3523   )
   3524 {
   3525   EFI_STATUS                       Status;
   3526   SCSI_ASYNC_RW_REQUEST            *Request;
   3527   SCSI_DISK_DEV                    *ScsiDiskDevice;
   3528   EFI_BLOCK_IO2_TOKEN              *Token;
   3529   UINTN                            Action;
   3530   UINT32                           OldDataLength;
   3531   UINT32                           OldSectorCount;
   3532   UINT8                            MaxRetry;
   3533 
   3534   gBS->CloseEvent (Event);
   3535 
   3536   Request         = (SCSI_ASYNC_RW_REQUEST *) Context;
   3537   ScsiDiskDevice  = Request->ScsiDiskDevice;
   3538   Token           = Request->BlkIo2Req->Token;
   3539   OldDataLength   = Request->DataLength;
   3540   OldSectorCount  = Request->SectorCount;
   3541   MaxRetry        = 2;
   3542 
   3543   //
   3544   // If previous sub-tasks already fails, no need to process this sub-task.
   3545   //
   3546   if (Token->TransactionStatus != EFI_SUCCESS) {
   3547     goto Exit;
   3548   }
   3549 
   3550   //
   3551   // Check HostAdapterStatus and TargetStatus
   3552   // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
   3553   //
   3554   Status = CheckHostAdapterStatus (Request->HostAdapterStatus);
   3555   if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {
   3556     if (++Request->TimesRetry > MaxRetry) {
   3557       Token->TransactionStatus = EFI_DEVICE_ERROR;
   3558       goto Exit;
   3559     } else {
   3560       goto Retry;
   3561     }
   3562   } else if (Status == EFI_DEVICE_ERROR) {
   3563     //
   3564     // reset the scsi channel
   3565     //
   3566     ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);
   3567     Token->TransactionStatus = EFI_DEVICE_ERROR;
   3568     goto Exit;
   3569   }
   3570 
   3571   Status = CheckTargetStatus (Request->TargetStatus);
   3572   if (Status == EFI_NOT_READY) {
   3573     //
   3574     // reset the scsi device
   3575     //
   3576     ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);
   3577     if (++Request->TimesRetry > MaxRetry) {
   3578       Token->TransactionStatus = EFI_DEVICE_ERROR;
   3579       goto Exit;
   3580     } else {
   3581       goto Retry;
   3582     }
   3583   } else if (Status == EFI_DEVICE_ERROR) {
   3584     Token->TransactionStatus = EFI_DEVICE_ERROR;
   3585     goto Exit;
   3586   }
   3587 
   3588   if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
   3589     DEBUG ((EFI_D_ERROR, "ScsiDiskNotify: Check Condition happened!\n"));
   3590 
   3591     Status = DetectMediaParsingSenseKeys (
   3592                ScsiDiskDevice,
   3593                Request->SenseData,
   3594                Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA),
   3595                &Action
   3596                );
   3597     if (Action == ACTION_RETRY_COMMAND_LATER) {
   3598       if (++Request->TimesRetry > MaxRetry) {
   3599         Token->TransactionStatus = EFI_DEVICE_ERROR;
   3600         goto Exit;
   3601       } else {
   3602         goto Retry;
   3603       }
   3604     } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {
   3605       if (Request->SectorCount <= 1) {
   3606         //
   3607         // Jump out if the operation still fails with one sector transfer
   3608         // length.
   3609         //
   3610         Token->TransactionStatus = EFI_DEVICE_ERROR;
   3611         goto Exit;
   3612       }
   3613       //
   3614       // Try again with two half length request if the sense data shows we need
   3615       // to retry.
   3616       //
   3617       Request->SectorCount >>= 1;
   3618       Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;
   3619       Request->TimesRetry  = 0;
   3620 
   3621       goto Retry;
   3622     } else {
   3623       Token->TransactionStatus = EFI_DEVICE_ERROR;
   3624       goto Exit;
   3625     }
   3626   }
   3627 
   3628   //
   3629   // This sub-task succeeds, no need to retry.
   3630   //
   3631   goto Exit;
   3632 
   3633 Retry:
   3634   if (Request->InBuffer != NULL) {
   3635     //
   3636     // SCSI read command
   3637     //
   3638     if (!ScsiDiskDevice->Cdb16Byte) {
   3639       Status = ScsiDiskAsyncRead10 (
   3640                  ScsiDiskDevice,
   3641                  Request->Timeout,
   3642                  Request->TimesRetry,
   3643                  Request->InBuffer,
   3644                  Request->DataLength,
   3645                  (UINT32) Request->StartLba,
   3646                  Request->SectorCount,
   3647                  Request->BlkIo2Req,
   3648                  Token
   3649                  );
   3650     } else {
   3651       Status = ScsiDiskAsyncRead16 (
   3652                  ScsiDiskDevice,
   3653                  Request->Timeout,
   3654                  Request->TimesRetry,
   3655                  Request->InBuffer,
   3656                  Request->DataLength,
   3657                  Request->StartLba,
   3658                  Request->SectorCount,
   3659                  Request->BlkIo2Req,
   3660                  Token
   3661                  );
   3662     }
   3663 
   3664     if (EFI_ERROR (Status)) {
   3665       Token->TransactionStatus = EFI_DEVICE_ERROR;
   3666       goto Exit;
   3667     } else if (OldSectorCount != Request->SectorCount) {
   3668       //
   3669       // Original sub-task will be split into two new sub-tasks with smaller
   3670       // DataLength
   3671       //
   3672       if (!ScsiDiskDevice->Cdb16Byte) {
   3673         Status = ScsiDiskAsyncRead10 (
   3674                    ScsiDiskDevice,
   3675                    Request->Timeout,
   3676                    0,
   3677                    Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
   3678                    OldDataLength - Request->DataLength,
   3679                    (UINT32) Request->StartLba + Request->SectorCount,
   3680                    OldSectorCount - Request->SectorCount,
   3681                    Request->BlkIo2Req,
   3682                    Token
   3683                    );
   3684       } else {
   3685         Status = ScsiDiskAsyncRead16 (
   3686                    ScsiDiskDevice,
   3687                    Request->Timeout,
   3688                    0,
   3689                    Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
   3690                    OldDataLength - Request->DataLength,
   3691                    Request->StartLba + Request->SectorCount,
   3692                    OldSectorCount - Request->SectorCount,
   3693                    Request->BlkIo2Req,
   3694                    Token
   3695                    );
   3696       }
   3697       if (EFI_ERROR (Status)) {
   3698         Token->TransactionStatus = EFI_DEVICE_ERROR;
   3699         goto Exit;
   3700       }
   3701     }
   3702   } else {
   3703     //
   3704     // SCSI write command
   3705     //
   3706     if (!ScsiDiskDevice->Cdb16Byte) {
   3707       Status = ScsiDiskAsyncWrite10 (
   3708                  ScsiDiskDevice,
   3709                  Request->Timeout,
   3710                  Request->TimesRetry,
   3711                  Request->OutBuffer,
   3712                  Request->DataLength,
   3713                  (UINT32) Request->StartLba,
   3714                  Request->SectorCount,
   3715                  Request->BlkIo2Req,
   3716                  Token
   3717                  );
   3718     } else {
   3719       Status = ScsiDiskAsyncWrite16 (
   3720                  ScsiDiskDevice,
   3721                  Request->Timeout,
   3722                  Request->TimesRetry,
   3723                  Request->OutBuffer,
   3724                  Request->DataLength,
   3725                  Request->StartLba,
   3726                  Request->SectorCount,
   3727                  Request->BlkIo2Req,
   3728                  Token
   3729                  );
   3730     }
   3731 
   3732     if (EFI_ERROR (Status)) {
   3733       Token->TransactionStatus = EFI_DEVICE_ERROR;
   3734       goto Exit;
   3735     } else if (OldSectorCount != Request->SectorCount) {
   3736       //
   3737       // Original sub-task will be split into two new sub-tasks with smaller
   3738       // DataLength
   3739       //
   3740       if (!ScsiDiskDevice->Cdb16Byte) {
   3741         Status = ScsiDiskAsyncWrite10 (
   3742                    ScsiDiskDevice,
   3743                    Request->Timeout,
   3744                    0,
   3745                    Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
   3746                    OldDataLength - Request->DataLength,
   3747                    (UINT32) Request->StartLba + Request->SectorCount,
   3748                    OldSectorCount - Request->SectorCount,
   3749                    Request->BlkIo2Req,
   3750                    Token
   3751                    );
   3752       } else {
   3753         Status = ScsiDiskAsyncWrite16 (
   3754                    ScsiDiskDevice,
   3755                    Request->Timeout,
   3756                    0,
   3757                    Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,
   3758                    OldDataLength - Request->DataLength,
   3759                    Request->StartLba + Request->SectorCount,
   3760                    OldSectorCount - Request->SectorCount,
   3761                    Request->BlkIo2Req,
   3762                    Token
   3763                    );
   3764       }
   3765       if (EFI_ERROR (Status)) {
   3766         Token->TransactionStatus = EFI_DEVICE_ERROR;
   3767         goto Exit;
   3768       }
   3769     }
   3770   }
   3771 
   3772 Exit:
   3773   RemoveEntryList (&Request->Link);
   3774   if ((IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) &&
   3775       (Request->BlkIo2Req->LastScsiRW)) {
   3776     //
   3777     // The last SCSI R/W command of a BlockIo2 request completes
   3778     //
   3779     RemoveEntryList (&Request->BlkIo2Req->Link);
   3780     FreePool (Request->BlkIo2Req);  // Should be freed only once
   3781     gBS->SignalEvent (Token->Event);
   3782   }
   3783 
   3784   FreePool (Request->SenseData);
   3785   FreePool (Request);
   3786 }
   3787 
   3788 
   3789 /**
   3790   Submit Async Read(10) command.
   3791 
   3792   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.
   3793   @param  Timeout            The time to complete the command.
   3794   @param  TimesRetry         The number of times the command has been retried.
   3795   @param  DataBuffer         The buffer to fill with the read out data.
   3796   @param  DataLength         The length of buffer.
   3797   @param  StartLba           The start logic block address.
   3798   @param  SectorCount        The number of blocks to read.
   3799   @param  BlkIo2Req          The upstream BlockIo2 request.
   3800   @param  Token              The pointer to the token associated with the
   3801                              non-blocking read request.
   3802 
   3803   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
   3804                                 lack of resources.
   3805   @return others                Status returned by calling
   3806                                 ScsiRead10CommandEx().
   3807 
   3808 **/
   3809 EFI_STATUS
   3810 ScsiDiskAsyncRead10 (
   3811   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
   3812   IN     UINT64                Timeout,
   3813   IN     UINT8                 TimesRetry,
   3814      OUT UINT8                 *DataBuffer,
   3815   IN     UINT32                DataLength,
   3816   IN     UINT32                StartLba,
   3817   IN     UINT32                SectorCount,
   3818   IN OUT SCSI_BLKIO2_REQUEST   *BlkIo2Req,
   3819   IN     EFI_BLOCK_IO2_TOKEN   *Token
   3820   )
   3821 {
   3822   EFI_STATUS                   Status;
   3823   SCSI_ASYNC_RW_REQUEST        *Request;
   3824   EFI_EVENT                    AsyncIoEvent;
   3825   EFI_TPL                      OldTpl;
   3826 
   3827   AsyncIoEvent = NULL;
   3828 
   3829   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
   3830   if (Request == NULL) {
   3831     return EFI_OUT_OF_RESOURCES;
   3832   }
   3833 
   3834   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   3835   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
   3836   gBS->RestoreTPL (OldTpl);
   3837 
   3838   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
   3839   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);
   3840   if (Request->SenseData == NULL) {
   3841     Status = EFI_OUT_OF_RESOURCES;
   3842     goto ErrorExit;
   3843   }
   3844 
   3845   Request->ScsiDiskDevice  = ScsiDiskDevice;
   3846   Request->Timeout         = Timeout;
   3847   Request->TimesRetry      = TimesRetry;
   3848   Request->InBuffer        = DataBuffer;
   3849   Request->DataLength      = DataLength;
   3850   Request->StartLba        = StartLba;
   3851   Request->SectorCount     = SectorCount;
   3852   Request->BlkIo2Req       = BlkIo2Req;
   3853 
   3854   //
   3855   // Create Event
   3856   //
   3857   Status = gBS->CreateEvent (
   3858                   EVT_NOTIFY_SIGNAL,
   3859                   TPL_NOTIFY,
   3860                   ScsiDiskNotify,
   3861                   Request,
   3862                   &AsyncIoEvent
   3863                   );
   3864   if (EFI_ERROR(Status)) {
   3865     goto ErrorExit;
   3866   }
   3867 
   3868   Status = ScsiRead10CommandEx (
   3869              ScsiDiskDevice->ScsiIo,
   3870              Request->Timeout,
   3871              Request->SenseData,
   3872              &Request->SenseDataLength,
   3873              &Request->HostAdapterStatus,
   3874              &Request->TargetStatus,
   3875              Request->InBuffer,
   3876              &Request->DataLength,
   3877              (UINT32) Request->StartLba,
   3878              Request->SectorCount,
   3879              AsyncIoEvent
   3880              );
   3881   if (EFI_ERROR(Status)) {
   3882     goto ErrorExit;
   3883   }
   3884 
   3885   return EFI_SUCCESS;
   3886 
   3887 ErrorExit:
   3888   if (AsyncIoEvent != NULL) {
   3889     gBS->CloseEvent (AsyncIoEvent);
   3890   }
   3891 
   3892   if (Request != NULL) {
   3893     if (Request->SenseData != NULL) {
   3894       FreePool (Request->SenseData);
   3895     }
   3896 
   3897     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   3898     RemoveEntryList (&Request->Link);
   3899     gBS->RestoreTPL (OldTpl);
   3900 
   3901     FreePool (Request);
   3902   }
   3903 
   3904   return Status;
   3905 }
   3906 
   3907 
   3908 /**
   3909   Submit Async Write(10) command.
   3910 
   3911   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.
   3912   @param  Timeout            The time to complete the command.
   3913   @param  TimesRetry         The number of times the command has been retried.
   3914   @param  DataBuffer         The buffer contains the data to write.
   3915   @param  DataLength         The length of buffer.
   3916   @param  StartLba           The start logic block address.
   3917   @param  SectorCount        The number of blocks to write.
   3918   @param  BlkIo2Req          The upstream BlockIo2 request.
   3919   @param  Token              The pointer to the token associated with the
   3920                              non-blocking read request.
   3921 
   3922   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
   3923                                 lack of resources.
   3924   @return others                Status returned by calling
   3925                                 ScsiWrite10CommandEx().
   3926 
   3927 **/
   3928 EFI_STATUS
   3929 ScsiDiskAsyncWrite10 (
   3930   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
   3931   IN     UINT64                Timeout,
   3932   IN     UINT8                 TimesRetry,
   3933   IN     UINT8                 *DataBuffer,
   3934   IN     UINT32                DataLength,
   3935   IN     UINT32                StartLba,
   3936   IN     UINT32                SectorCount,
   3937   IN OUT SCSI_BLKIO2_REQUEST   *BlkIo2Req,
   3938   IN     EFI_BLOCK_IO2_TOKEN   *Token
   3939   )
   3940 {
   3941   EFI_STATUS                   Status;
   3942   SCSI_ASYNC_RW_REQUEST        *Request;
   3943   EFI_EVENT                    AsyncIoEvent;
   3944   EFI_TPL                      OldTpl;
   3945 
   3946   AsyncIoEvent = NULL;
   3947 
   3948   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
   3949   if (Request == NULL) {
   3950     return EFI_OUT_OF_RESOURCES;
   3951   }
   3952 
   3953   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   3954   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
   3955   gBS->RestoreTPL (OldTpl);
   3956 
   3957   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
   3958   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);
   3959   if (Request->SenseData == NULL) {
   3960     Status = EFI_OUT_OF_RESOURCES;
   3961     goto ErrorExit;
   3962   }
   3963 
   3964   Request->ScsiDiskDevice  = ScsiDiskDevice;
   3965   Request->Timeout         = Timeout;
   3966   Request->TimesRetry      = TimesRetry;
   3967   Request->OutBuffer       = DataBuffer;
   3968   Request->DataLength      = DataLength;
   3969   Request->StartLba        = StartLba;
   3970   Request->SectorCount     = SectorCount;
   3971   Request->BlkIo2Req       = BlkIo2Req;
   3972 
   3973   //
   3974   // Create Event
   3975   //
   3976   Status = gBS->CreateEvent (
   3977                   EVT_NOTIFY_SIGNAL,
   3978                   TPL_NOTIFY,
   3979                   ScsiDiskNotify,
   3980                   Request,
   3981                   &AsyncIoEvent
   3982                   );
   3983   if (EFI_ERROR(Status)) {
   3984     goto ErrorExit;
   3985   }
   3986 
   3987   Status = ScsiWrite10CommandEx (
   3988              ScsiDiskDevice->ScsiIo,
   3989              Request->Timeout,
   3990              Request->SenseData,
   3991              &Request->SenseDataLength,
   3992              &Request->HostAdapterStatus,
   3993              &Request->TargetStatus,
   3994              Request->OutBuffer,
   3995              &Request->DataLength,
   3996              (UINT32) Request->StartLba,
   3997              Request->SectorCount,
   3998              AsyncIoEvent
   3999              );
   4000   if (EFI_ERROR(Status)) {
   4001     goto ErrorExit;
   4002   }
   4003 
   4004   return EFI_SUCCESS;
   4005 
   4006 ErrorExit:
   4007   if (AsyncIoEvent != NULL) {
   4008     gBS->CloseEvent (AsyncIoEvent);
   4009   }
   4010 
   4011   if (Request != NULL) {
   4012     if (Request->SenseData != NULL) {
   4013       FreePool (Request->SenseData);
   4014     }
   4015 
   4016     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   4017     RemoveEntryList (&Request->Link);
   4018     gBS->RestoreTPL (OldTpl);
   4019 
   4020     FreePool (Request);
   4021   }
   4022 
   4023   return Status;
   4024 }
   4025 
   4026 
   4027 /**
   4028   Submit Async Read(16) command.
   4029 
   4030   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.
   4031   @param  Timeout            The time to complete the command.
   4032   @param  TimesRetry         The number of times the command has been retried.
   4033   @param  DataBuffer         The buffer to fill with the read out data.
   4034   @param  DataLength         The length of buffer.
   4035   @param  StartLba           The start logic block address.
   4036   @param  SectorCount        The number of blocks to read.
   4037   @param  BlkIo2Req          The upstream BlockIo2 request.
   4038   @param  Token              The pointer to the token associated with the
   4039                              non-blocking read request.
   4040 
   4041   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
   4042                                 lack of resources.
   4043   @return others                Status returned by calling
   4044                                 ScsiRead16CommandEx().
   4045 
   4046 **/
   4047 EFI_STATUS
   4048 ScsiDiskAsyncRead16 (
   4049   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
   4050   IN     UINT64                Timeout,
   4051   IN     UINT8                 TimesRetry,
   4052      OUT UINT8                 *DataBuffer,
   4053   IN     UINT32                DataLength,
   4054   IN     UINT64                StartLba,
   4055   IN     UINT32                SectorCount,
   4056   IN OUT SCSI_BLKIO2_REQUEST   *BlkIo2Req,
   4057   IN     EFI_BLOCK_IO2_TOKEN   *Token
   4058   )
   4059 {
   4060   EFI_STATUS                   Status;
   4061   SCSI_ASYNC_RW_REQUEST        *Request;
   4062   EFI_EVENT                    AsyncIoEvent;
   4063   EFI_TPL                      OldTpl;
   4064 
   4065   AsyncIoEvent = NULL;
   4066 
   4067   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
   4068   if (Request == NULL) {
   4069     return EFI_OUT_OF_RESOURCES;
   4070   }
   4071 
   4072   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   4073   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
   4074   gBS->RestoreTPL (OldTpl);
   4075 
   4076   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
   4077   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);
   4078   if (Request->SenseData == NULL) {
   4079     Status = EFI_OUT_OF_RESOURCES;
   4080     goto ErrorExit;
   4081   }
   4082 
   4083   Request->ScsiDiskDevice  = ScsiDiskDevice;
   4084   Request->Timeout         = Timeout;
   4085   Request->TimesRetry      = TimesRetry;
   4086   Request->InBuffer        = DataBuffer;
   4087   Request->DataLength      = DataLength;
   4088   Request->StartLba        = StartLba;
   4089   Request->SectorCount     = SectorCount;
   4090   Request->BlkIo2Req       = BlkIo2Req;
   4091 
   4092   //
   4093   // Create Event
   4094   //
   4095   Status = gBS->CreateEvent (
   4096                   EVT_NOTIFY_SIGNAL,
   4097                   TPL_NOTIFY,
   4098                   ScsiDiskNotify,
   4099                   Request,
   4100                   &AsyncIoEvent
   4101                   );
   4102   if (EFI_ERROR(Status)) {
   4103     goto ErrorExit;
   4104   }
   4105 
   4106   Status = ScsiRead16CommandEx (
   4107              ScsiDiskDevice->ScsiIo,
   4108              Request->Timeout,
   4109              Request->SenseData,
   4110              &Request->SenseDataLength,
   4111              &Request->HostAdapterStatus,
   4112              &Request->TargetStatus,
   4113              Request->InBuffer,
   4114              &Request->DataLength,
   4115              Request->StartLba,
   4116              Request->SectorCount,
   4117              AsyncIoEvent
   4118              );
   4119   if (EFI_ERROR(Status)) {
   4120     goto ErrorExit;
   4121   }
   4122 
   4123   return EFI_SUCCESS;
   4124 
   4125 ErrorExit:
   4126   if (AsyncIoEvent != NULL) {
   4127     gBS->CloseEvent (AsyncIoEvent);
   4128   }
   4129 
   4130   if (Request != NULL) {
   4131     if (Request->SenseData != NULL) {
   4132       FreePool (Request->SenseData);
   4133     }
   4134 
   4135     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   4136     RemoveEntryList (&Request->Link);
   4137     gBS->RestoreTPL (OldTpl);
   4138 
   4139     FreePool (Request);
   4140   }
   4141 
   4142   return Status;
   4143 }
   4144 
   4145 
   4146 /**
   4147   Submit Async Write(16) command.
   4148 
   4149   @param  ScsiDiskDevice     The pointer of ScsiDiskDevice.
   4150   @param  Timeout            The time to complete the command.
   4151   @param  TimesRetry         The number of times the command has been retried.
   4152   @param  DataBuffer         The buffer contains the data to write.
   4153   @param  DataLength         The length of buffer.
   4154   @param  StartLba           The start logic block address.
   4155   @param  SectorCount        The number of blocks to write.
   4156   @param  BlkIo2Req          The upstream BlockIo2 request.
   4157   @param  Token              The pointer to the token associated with the
   4158                              non-blocking read request.
   4159 
   4160   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
   4161                                 lack of resources.
   4162   @return others                Status returned by calling
   4163                                 ScsiWrite16CommandEx().
   4164 
   4165 **/
   4166 EFI_STATUS
   4167 ScsiDiskAsyncWrite16 (
   4168   IN     SCSI_DISK_DEV         *ScsiDiskDevice,
   4169   IN     UINT64                Timeout,
   4170   IN     UINT8                 TimesRetry,
   4171   IN     UINT8                 *DataBuffer,
   4172   IN     UINT32                DataLength,
   4173   IN     UINT64                StartLba,
   4174   IN     UINT32                SectorCount,
   4175   IN OUT SCSI_BLKIO2_REQUEST   *BlkIo2Req,
   4176   IN     EFI_BLOCK_IO2_TOKEN   *Token
   4177   )
   4178 {
   4179   EFI_STATUS                   Status;
   4180   SCSI_ASYNC_RW_REQUEST        *Request;
   4181   EFI_EVENT                    AsyncIoEvent;
   4182   EFI_TPL                      OldTpl;
   4183 
   4184   AsyncIoEvent = NULL;
   4185 
   4186   Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));
   4187   if (Request == NULL) {
   4188     return EFI_OUT_OF_RESOURCES;
   4189   }
   4190 
   4191   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   4192   InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);
   4193   gBS->RestoreTPL (OldTpl);
   4194 
   4195   Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));
   4196   Request->SenseData       = AllocateZeroPool (Request->SenseDataLength);
   4197   if (Request->SenseData == NULL) {
   4198     Status = EFI_OUT_OF_RESOURCES;
   4199     goto ErrorExit;
   4200   }
   4201 
   4202   Request->ScsiDiskDevice  = ScsiDiskDevice;
   4203   Request->Timeout         = Timeout;
   4204   Request->TimesRetry      = TimesRetry;
   4205   Request->OutBuffer       = DataBuffer;
   4206   Request->DataLength      = DataLength;
   4207   Request->StartLba        = StartLba;
   4208   Request->SectorCount     = SectorCount;
   4209   Request->BlkIo2Req       = BlkIo2Req;
   4210 
   4211   //
   4212   // Create Event
   4213   //
   4214   Status = gBS->CreateEvent (
   4215                   EVT_NOTIFY_SIGNAL,
   4216                   TPL_NOTIFY,
   4217                   ScsiDiskNotify,
   4218                   Request,
   4219                   &AsyncIoEvent
   4220                   );
   4221   if (EFI_ERROR(Status)) {
   4222     goto ErrorExit;
   4223   }
   4224 
   4225   Status = ScsiWrite16CommandEx (
   4226              ScsiDiskDevice->ScsiIo,
   4227              Request->Timeout,
   4228              Request->SenseData,
   4229              &Request->SenseDataLength,
   4230              &Request->HostAdapterStatus,
   4231              &Request->TargetStatus,
   4232              Request->OutBuffer,
   4233              &Request->DataLength,
   4234              Request->StartLba,
   4235              Request->SectorCount,
   4236              AsyncIoEvent
   4237              );
   4238   if (EFI_ERROR(Status)) {
   4239     goto ErrorExit;
   4240   }
   4241 
   4242   return EFI_SUCCESS;
   4243 
   4244 ErrorExit:
   4245   if (AsyncIoEvent != NULL) {
   4246     gBS->CloseEvent (AsyncIoEvent);
   4247   }
   4248 
   4249   if (Request != NULL) {
   4250     if (Request->SenseData != NULL) {
   4251       FreePool (Request->SenseData);
   4252     }
   4253 
   4254     OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
   4255     RemoveEntryList (&Request->Link);
   4256     gBS->RestoreTPL (OldTpl);
   4257 
   4258     FreePool (Request);
   4259   }
   4260 
   4261   return Status;
   4262 }
   4263 
   4264 
   4265 /**
   4266   Check sense key to find if media presents.
   4267 
   4268   @param  SenseData   The pointer of EFI_SCSI_SENSE_DATA
   4269   @param  SenseCounts The number of sense key
   4270 
   4271   @retval TRUE    NOT any media
   4272   @retval FALSE   Media presents
   4273 **/
   4274 BOOLEAN
   4275 ScsiDiskIsNoMedia (
   4276   IN  EFI_SCSI_SENSE_DATA   *SenseData,
   4277   IN  UINTN                 SenseCounts
   4278   )
   4279 {
   4280   EFI_SCSI_SENSE_DATA *SensePtr;
   4281   UINTN               Index;
   4282   BOOLEAN             IsNoMedia;
   4283 
   4284   IsNoMedia = FALSE;
   4285   SensePtr  = SenseData;
   4286 
   4287   for (Index = 0; Index < SenseCounts; Index++) {
   4288     //
   4289     // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
   4290     // Additional Sense Code is ASC_NO_MEDIA (0x3A)
   4291     //
   4292     if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&
   4293         (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {
   4294       IsNoMedia = TRUE;
   4295     }
   4296     SensePtr++;
   4297   }
   4298 
   4299   return IsNoMedia;
   4300 }
   4301 
   4302 
   4303 /**
   4304   Parse sense key.
   4305 
   4306   @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA
   4307   @param  SenseCounts  The number of sense key
   4308 
   4309   @retval TRUE   Error
   4310   @retval FALSE  NOT error
   4311 
   4312 **/
   4313 BOOLEAN
   4314 ScsiDiskIsMediaError (
   4315   IN  EFI_SCSI_SENSE_DATA   *SenseData,
   4316   IN  UINTN                 SenseCounts
   4317   )
   4318 {
   4319   EFI_SCSI_SENSE_DATA *SensePtr;
   4320   UINTN               Index;
   4321   BOOLEAN             IsError;
   4322 
   4323   IsError   = FALSE;
   4324   SensePtr  = SenseData;
   4325 
   4326   for (Index = 0; Index < SenseCounts; Index++) {
   4327 
   4328     switch (SensePtr->Sense_Key) {
   4329 
   4330     case EFI_SCSI_SK_MEDIUM_ERROR:
   4331       //
   4332       // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
   4333       //
   4334       switch (SensePtr->Addnl_Sense_Code) {
   4335 
   4336       //
   4337       // fall through
   4338       //
   4339       case EFI_SCSI_ASC_MEDIA_ERR1:
   4340 
   4341       //
   4342       // fall through
   4343       //
   4344       case EFI_SCSI_ASC_MEDIA_ERR2:
   4345 
   4346       //
   4347       // fall through
   4348       //
   4349       case EFI_SCSI_ASC_MEDIA_ERR3:
   4350       case EFI_SCSI_ASC_MEDIA_ERR4:
   4351         IsError = TRUE;
   4352         break;
   4353 
   4354       default:
   4355         break;
   4356       }
   4357 
   4358       break;
   4359 
   4360     case EFI_SCSI_SK_NOT_READY:
   4361       //
   4362       // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
   4363       //
   4364       switch (SensePtr->Addnl_Sense_Code) {
   4365       //
   4366       // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
   4367       //
   4368       case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:
   4369         IsError = TRUE;
   4370         break;
   4371 
   4372       default:
   4373         break;
   4374       }
   4375       break;
   4376 
   4377     default:
   4378       break;
   4379     }
   4380 
   4381     SensePtr++;
   4382   }
   4383 
   4384   return IsError;
   4385 }
   4386 
   4387 
   4388 /**
   4389   Check sense key to find if hardware error happens.
   4390 
   4391   @param  SenseData     The pointer of EFI_SCSI_SENSE_DATA
   4392   @param  SenseCounts   The number of sense key
   4393 
   4394   @retval TRUE  Hardware error exits.
   4395   @retval FALSE NO error.
   4396 
   4397 **/
   4398 BOOLEAN
   4399 ScsiDiskIsHardwareError (
   4400   IN  EFI_SCSI_SENSE_DATA   *SenseData,
   4401   IN  UINTN                 SenseCounts
   4402   )
   4403 {
   4404   EFI_SCSI_SENSE_DATA *SensePtr;
   4405   UINTN               Index;
   4406   BOOLEAN             IsError;
   4407 
   4408   IsError   = FALSE;
   4409   SensePtr  = SenseData;
   4410 
   4411   for (Index = 0; Index < SenseCounts; Index++) {
   4412 
   4413     //
   4414     // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
   4415     //
   4416     if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {
   4417       IsError = TRUE;
   4418     }
   4419 
   4420     SensePtr++;
   4421   }
   4422 
   4423   return IsError;
   4424 }
   4425 
   4426 
   4427 /**
   4428   Check sense key to find if media has changed.
   4429 
   4430   @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA
   4431   @param  SenseCounts  The number of sense key
   4432 
   4433   @retval TRUE   Media is changed.
   4434   @retval FALSE  Media is NOT changed.
   4435 **/
   4436 BOOLEAN
   4437 ScsiDiskIsMediaChange (
   4438   IN  EFI_SCSI_SENSE_DATA   *SenseData,
   4439   IN  UINTN                 SenseCounts
   4440   )
   4441 {
   4442   EFI_SCSI_SENSE_DATA *SensePtr;
   4443   UINTN               Index;
   4444   BOOLEAN             IsMediaChanged;
   4445 
   4446   IsMediaChanged  = FALSE;
   4447   SensePtr        = SenseData;
   4448 
   4449   for (Index = 0; Index < SenseCounts; Index++) {
   4450     //
   4451     // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
   4452     // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
   4453     //
   4454     if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
   4455         (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {
   4456       IsMediaChanged = TRUE;
   4457     }
   4458 
   4459     SensePtr++;
   4460   }
   4461 
   4462   return IsMediaChanged;
   4463 }
   4464 
   4465 /**
   4466   Check sense key to find if reset happens.
   4467 
   4468   @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA
   4469   @param  SenseCounts  The number of sense key
   4470 
   4471   @retval TRUE  It is reset before.
   4472   @retval FALSE It is NOT reset before.
   4473 
   4474 **/
   4475 BOOLEAN
   4476 ScsiDiskIsResetBefore (
   4477   IN  EFI_SCSI_SENSE_DATA   *SenseData,
   4478   IN  UINTN                 SenseCounts
   4479   )
   4480 {
   4481   EFI_SCSI_SENSE_DATA *SensePtr;
   4482   UINTN               Index;
   4483   BOOLEAN             IsResetBefore;
   4484 
   4485   IsResetBefore = FALSE;
   4486   SensePtr      = SenseData;
   4487 
   4488   for (Index = 0; Index < SenseCounts; Index++) {
   4489 
   4490     //
   4491     // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
   4492     // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
   4493     //
   4494     if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&
   4495         (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {
   4496       IsResetBefore = TRUE;
   4497     }
   4498 
   4499     SensePtr++;
   4500   }
   4501 
   4502   return IsResetBefore;
   4503 }
   4504 
   4505 /**
   4506   Check sense key to find if the drive is ready.
   4507 
   4508   @param  SenseData    The pointer of EFI_SCSI_SENSE_DATA
   4509   @param  SenseCounts  The number of sense key
   4510   @param  RetryLater   The flag means if need a retry
   4511 
   4512   @retval TRUE  Drive is ready.
   4513   @retval FALSE Drive is NOT ready.
   4514 
   4515 **/
   4516 BOOLEAN
   4517 ScsiDiskIsDriveReady (
   4518   IN  EFI_SCSI_SENSE_DATA   *SenseData,
   4519   IN  UINTN                 SenseCounts,
   4520   OUT BOOLEAN               *RetryLater
   4521   )
   4522 {
   4523   EFI_SCSI_SENSE_DATA *SensePtr;
   4524   UINTN               Index;
   4525   BOOLEAN             IsReady;
   4526 
   4527   IsReady     = TRUE;
   4528   *RetryLater = FALSE;
   4529   SensePtr    = SenseData;
   4530 
   4531   for (Index = 0; Index < SenseCounts; Index++) {
   4532 
   4533     switch (SensePtr->Sense_Key) {
   4534 
   4535     case EFI_SCSI_SK_NOT_READY:
   4536       //
   4537       // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
   4538       //
   4539       switch (SensePtr->Addnl_Sense_Code) {
   4540       case EFI_SCSI_ASC_NOT_READY:
   4541         //
   4542         // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
   4543         //
   4544         switch (SensePtr->Addnl_Sense_Code_Qualifier) {
   4545         case EFI_SCSI_ASCQ_IN_PROGRESS:
   4546           //
   4547           // Additional Sense Code Qualifier is
   4548           // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
   4549           //
   4550           IsReady     = FALSE;
   4551           *RetryLater = TRUE;
   4552           break;
   4553 
   4554         default:
   4555           IsReady     = FALSE;
   4556           *RetryLater = FALSE;
   4557           break;
   4558         }
   4559         break;
   4560 
   4561       default:
   4562         break;
   4563       }
   4564       break;
   4565 
   4566     default:
   4567       break;
   4568     }
   4569 
   4570     SensePtr++;
   4571   }
   4572 
   4573   return IsReady;
   4574 }
   4575 
   4576 /**
   4577   Check sense key to find if it has sense key.
   4578 
   4579   @param  SenseData   - The pointer of EFI_SCSI_SENSE_DATA
   4580   @param  SenseCounts - The number of sense key
   4581 
   4582   @retval TRUE  It has sense key.
   4583   @retval FALSE It has NOT any sense key.
   4584 
   4585 **/
   4586 BOOLEAN
   4587 ScsiDiskHaveSenseKey (
   4588   IN  EFI_SCSI_SENSE_DATA   *SenseData,
   4589   IN  UINTN                 SenseCounts
   4590   )
   4591 {
   4592   EFI_SCSI_SENSE_DATA *SensePtr;
   4593   UINTN               Index;
   4594   BOOLEAN             HaveSenseKey;
   4595 
   4596   if (SenseCounts == 0) {
   4597     HaveSenseKey = FALSE;
   4598   } else {
   4599     HaveSenseKey = TRUE;
   4600   }
   4601 
   4602   SensePtr = SenseData;
   4603 
   4604   for (Index = 0; Index < SenseCounts; Index++) {
   4605 
   4606     //
   4607     // Sense Key is SK_NO_SENSE (0x0)
   4608     //
   4609     if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&
   4610         (Index == 0)) {
   4611       HaveSenseKey = FALSE;
   4612     }
   4613 
   4614     SensePtr++;
   4615   }
   4616 
   4617   return HaveSenseKey;
   4618 }
   4619 
   4620 /**
   4621   Release resource about disk device.
   4622 
   4623   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
   4624 
   4625 **/
   4626 VOID
   4627 ReleaseScsiDiskDeviceResources (
   4628   IN  SCSI_DISK_DEV   *ScsiDiskDevice
   4629   )
   4630 {
   4631   if (ScsiDiskDevice == NULL) {
   4632     return ;
   4633   }
   4634 
   4635   if (ScsiDiskDevice->SenseData != NULL) {
   4636     FreePool (ScsiDiskDevice->SenseData);
   4637     ScsiDiskDevice->SenseData = NULL;
   4638   }
   4639 
   4640   if (ScsiDiskDevice->ControllerNameTable != NULL) {
   4641     FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);
   4642     ScsiDiskDevice->ControllerNameTable = NULL;
   4643   }
   4644 
   4645   FreePool (ScsiDiskDevice);
   4646 
   4647   ScsiDiskDevice = NULL;
   4648 }
   4649 
   4650 /**
   4651   Determine if Block Io & Block Io2 should be produced.
   4652 
   4653 
   4654   @param  ChildHandle  Child Handle to retrieve Parent information.
   4655 
   4656   @retval  TRUE    Should produce Block Io & Block Io2.
   4657   @retval  FALSE   Should not produce Block Io & Block Io2.
   4658 
   4659 **/
   4660 BOOLEAN
   4661 DetermineInstallBlockIo (
   4662   IN  EFI_HANDLE      ChildHandle
   4663   )
   4664 {
   4665   EFI_SCSI_PASS_THRU_PROTOCOL           *ScsiPassThru;
   4666   EFI_EXT_SCSI_PASS_THRU_PROTOCOL       *ExtScsiPassThru;
   4667 
   4668   //
   4669   // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
   4670   // check its attribute, logic or physical.
   4671   //
   4672   ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);
   4673   if (ExtScsiPassThru != NULL) {
   4674     if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
   4675       return TRUE;
   4676     }
   4677   }
   4678 
   4679   //
   4680   // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
   4681   // check its attribute, logic or physical.
   4682   //
   4683   ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);
   4684   if (ScsiPassThru != NULL) {
   4685     if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {
   4686       return TRUE;
   4687     }
   4688   }
   4689 
   4690   return FALSE;
   4691 }
   4692 
   4693 /**
   4694   Search protocol database and check to see if the protocol
   4695   specified by ProtocolGuid is present on a ControllerHandle and opened by
   4696   ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
   4697   If the ControllerHandle is found, then the protocol specified by ProtocolGuid
   4698   will be opened on it.
   4699 
   4700 
   4701   @param  ProtocolGuid   ProtocolGuid pointer.
   4702   @param  ChildHandle    Child Handle to retrieve Parent information.
   4703 
   4704 **/
   4705 VOID *
   4706 EFIAPI
   4707 GetParentProtocol (
   4708   IN  EFI_GUID                          *ProtocolGuid,
   4709   IN  EFI_HANDLE                        ChildHandle
   4710   )
   4711 {
   4712   UINTN                                 Index;
   4713   UINTN                                 HandleCount;
   4714   VOID                                  *Interface;
   4715   EFI_STATUS                            Status;
   4716   EFI_HANDLE                            *HandleBuffer;
   4717 
   4718   //
   4719   // Retrieve the list of all handles from the handle database
   4720   //
   4721   Status = gBS->LocateHandleBuffer (
   4722                   ByProtocol,
   4723                   ProtocolGuid,
   4724                   NULL,
   4725                   &HandleCount,
   4726                   &HandleBuffer
   4727                   );
   4728 
   4729   if (EFI_ERROR (Status)) {
   4730     return NULL;
   4731   }
   4732 
   4733   //
   4734   // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
   4735   //
   4736   for (Index = 0; Index < HandleCount; Index++) {
   4737     Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);
   4738     if (!EFI_ERROR (Status)) {
   4739       Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);
   4740       if (!EFI_ERROR (Status)) {
   4741         gBS->FreePool (HandleBuffer);
   4742         return Interface;
   4743       }
   4744     }
   4745   }
   4746 
   4747   gBS->FreePool (HandleBuffer);
   4748   return NULL;
   4749 }
   4750 
   4751 /**
   4752   Provides inquiry information for the controller type.
   4753 
   4754   This function is used by the IDE bus driver to get inquiry data.  Data format
   4755   of Identify data is defined by the Interface GUID.
   4756 
   4757   @param[in]      This              Pointer to the EFI_DISK_INFO_PROTOCOL instance.
   4758   @param[in, out] InquiryData       Pointer to a buffer for the inquiry data.
   4759   @param[in, out] InquiryDataSize   Pointer to the value for the inquiry data size.
   4760 
   4761   @retval EFI_SUCCESS            The command was accepted without any errors.
   4762   @retval EFI_NOT_FOUND          Device does not support this data class
   4763   @retval EFI_DEVICE_ERROR       Error reading InquiryData from device
   4764   @retval EFI_BUFFER_TOO_SMALL   InquiryDataSize not big enough
   4765 
   4766 **/
   4767 EFI_STATUS
   4768 EFIAPI
   4769 ScsiDiskInfoInquiry (
   4770   IN     EFI_DISK_INFO_PROTOCOL   *This,
   4771   IN OUT VOID                     *InquiryData,
   4772   IN OUT UINT32                   *InquiryDataSize
   4773   )
   4774 {
   4775   EFI_STATUS      Status;
   4776   SCSI_DISK_DEV   *ScsiDiskDevice;
   4777 
   4778   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_DISKINFO (This);
   4779 
   4780   Status = EFI_BUFFER_TOO_SMALL;
   4781   if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {
   4782     Status = EFI_SUCCESS;
   4783     CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));
   4784   }
   4785   *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);
   4786   return Status;
   4787 }
   4788 
   4789 
   4790 /**
   4791   Provides identify information for the controller type.
   4792 
   4793   This function is used by the IDE bus driver to get identify data.  Data format
   4794   of Identify data is defined by the Interface GUID.
   4795 
   4796   @param[in]      This              Pointer to the EFI_DISK_INFO_PROTOCOL
   4797                                     instance.
   4798   @param[in, out] IdentifyData      Pointer to a buffer for the identify data.
   4799   @param[in, out] IdentifyDataSize  Pointer to the value for the identify data
   4800                                     size.
   4801 
   4802   @retval EFI_SUCCESS            The command was accepted without any errors.
   4803   @retval EFI_NOT_FOUND          Device does not support this data class
   4804   @retval EFI_DEVICE_ERROR       Error reading IdentifyData from device
   4805   @retval EFI_BUFFER_TOO_SMALL   IdentifyDataSize not big enough
   4806 
   4807 **/
   4808 EFI_STATUS
   4809 EFIAPI
   4810 ScsiDiskInfoIdentify (
   4811   IN     EFI_DISK_INFO_PROTOCOL   *This,
   4812   IN OUT VOID                     *IdentifyData,
   4813   IN OUT UINT32                   *IdentifyDataSize
   4814   )
   4815 {
   4816   EFI_STATUS      Status;
   4817   SCSI_DISK_DEV   *ScsiDiskDevice;
   4818 
   4819   if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
   4820     //
   4821     // Physical SCSI bus does not support this data class.
   4822     //
   4823     return EFI_NOT_FOUND;
   4824   }
   4825 
   4826   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_DISKINFO (This);
   4827 
   4828   Status = EFI_BUFFER_TOO_SMALL;
   4829   if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {
   4830     Status = EFI_SUCCESS;
   4831     CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));
   4832   }
   4833   *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);
   4834   return Status;
   4835 }
   4836 
   4837 /**
   4838   Provides sense data information for the controller type.
   4839 
   4840   This function is used by the IDE bus driver to get sense data.
   4841   Data format of Sense data is defined by the Interface GUID.
   4842 
   4843   @param[in]      This              Pointer to the EFI_DISK_INFO_PROTOCOL instance.
   4844   @param[in, out] SenseData         Pointer to the SenseData.
   4845   @param[in, out] SenseDataSize     Size of SenseData in bytes.
   4846   @param[out]     SenseDataNumber   Pointer to the value for the sense data size.
   4847 
   4848   @retval EFI_SUCCESS            The command was accepted without any errors.
   4849   @retval EFI_NOT_FOUND          Device does not support this data class.
   4850   @retval EFI_DEVICE_ERROR       Error reading SenseData from device.
   4851   @retval EFI_BUFFER_TOO_SMALL   SenseDataSize not big enough.
   4852 
   4853 **/
   4854 EFI_STATUS
   4855 EFIAPI
   4856 ScsiDiskInfoSenseData (
   4857   IN     EFI_DISK_INFO_PROTOCOL   *This,
   4858   IN OUT VOID                     *SenseData,
   4859   IN OUT UINT32                   *SenseDataSize,
   4860   OUT    UINT8                    *SenseDataNumber
   4861   )
   4862 {
   4863   return EFI_NOT_FOUND;
   4864 }
   4865 
   4866 
   4867 /**
   4868   This function is used by the IDE bus driver to get controller information.
   4869 
   4870   @param[in]  This         Pointer to the EFI_DISK_INFO_PROTOCOL instance.
   4871   @param[out] IdeChannel   Pointer to the Ide Channel number.  Primary or secondary.
   4872   @param[out] IdeDevice    Pointer to the Ide Device number.  Master or slave.
   4873 
   4874   @retval EFI_SUCCESS       IdeChannel and IdeDevice are valid.
   4875   @retval EFI_UNSUPPORTED   This is not an IDE device.
   4876 
   4877 **/
   4878 EFI_STATUS
   4879 EFIAPI
   4880 ScsiDiskInfoWhichIde (
   4881   IN  EFI_DISK_INFO_PROTOCOL   *This,
   4882   OUT UINT32                   *IdeChannel,
   4883   OUT UINT32                   *IdeDevice
   4884   )
   4885 {
   4886   SCSI_DISK_DEV   *ScsiDiskDevice;
   4887 
   4888   if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {
   4889     //
   4890     // This is not an IDE physical device.
   4891     //
   4892     return EFI_UNSUPPORTED;
   4893   }
   4894 
   4895   ScsiDiskDevice  = SCSI_DISK_DEV_FROM_DISKINFO (This);
   4896   *IdeChannel     = ScsiDiskDevice->Channel;
   4897   *IdeDevice      = ScsiDiskDevice->Device;
   4898 
   4899   return EFI_SUCCESS;
   4900 }
   4901 
   4902 
   4903 /**
   4904   Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
   4905 
   4906   This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
   4907   implement Identify() interface for DiskInfo protocol. The ATA command is sent
   4908   via SCSI Request Packet.
   4909 
   4910   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV
   4911 
   4912   @retval EFI_SUCCESS     The ATAPI device identify data were retrieved successfully.
   4913   @retval others          Some error occurred during the identification that ATAPI device.
   4914 
   4915 **/
   4916 EFI_STATUS
   4917 AtapiIdentifyDevice (
   4918   IN OUT SCSI_DISK_DEV   *ScsiDiskDevice
   4919   )
   4920 {
   4921   EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
   4922   UINT8                           Cdb[6];
   4923 
   4924   //
   4925   // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
   4926   //
   4927   ZeroMem (&CommandPacket, sizeof (CommandPacket));
   4928   ZeroMem (Cdb, sizeof (Cdb));
   4929 
   4930   Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;
   4931   CommandPacket.Timeout = SCSI_DISK_TIMEOUT;
   4932   CommandPacket.Cdb = Cdb;
   4933   CommandPacket.CdbLength = (UINT8) sizeof (Cdb);
   4934   CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;
   4935   CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);
   4936 
   4937   return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);
   4938 }
   4939 
   4940 
   4941 /**
   4942   Initialize the installation of DiskInfo protocol.
   4943 
   4944   This function prepares for the installation of DiskInfo protocol on the child handle.
   4945   By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
   4946   detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
   4947   to be IDE/AHCI interface GUID.
   4948 
   4949   @param  ScsiDiskDevice  The pointer of SCSI_DISK_DEV.
   4950   @param  ChildHandle     Child handle to install DiskInfo protocol.
   4951 
   4952 **/
   4953 VOID
   4954 InitializeInstallDiskInfo (
   4955   IN  SCSI_DISK_DEV   *ScsiDiskDevice,
   4956   IN  EFI_HANDLE      ChildHandle
   4957   )
   4958 {
   4959   EFI_STATUS                Status;
   4960   EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode;
   4961   EFI_DEVICE_PATH_PROTOCOL  *ChildDevicePathNode;
   4962   ATAPI_DEVICE_PATH         *AtapiDevicePath;
   4963   SATA_DEVICE_PATH          *SataDevicePath;
   4964   UINTN                     IdentifyRetry;
   4965 
   4966   Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePathNode);
   4967   //
   4968   // Device Path protocol must be installed on the device handle.
   4969   //
   4970   ASSERT_EFI_ERROR (Status);
   4971   //
   4972   // Copy the DiskInfo protocol template.
   4973   //
   4974   CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));
   4975 
   4976   while (!IsDevicePathEnd (DevicePathNode)) {
   4977     ChildDevicePathNode = NextDevicePathNode (DevicePathNode);
   4978     if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
   4979         (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
   4980         (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
   4981        ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||
   4982         (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP))) {
   4983 
   4984       IdentifyRetry = 3;
   4985       do {
   4986         //
   4987         // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
   4988         // with IDE/AHCI interface GUID.
   4989         //
   4990         Status = AtapiIdentifyDevice (ScsiDiskDevice);
   4991         if (!EFI_ERROR (Status)) {
   4992           if (DevicePathSubType(ChildDevicePathNode) == MSG_ATAPI_DP) {
   4993             //
   4994             // We find the valid ATAPI device path
   4995             //
   4996             AtapiDevicePath = (ATAPI_DEVICE_PATH *) ChildDevicePathNode;
   4997             ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;
   4998             ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;
   4999             //
   5000             // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
   5001             //
   5002             CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);
   5003           } else {
   5004             //
   5005             // We find the valid SATA device path
   5006             //
   5007             SataDevicePath = (SATA_DEVICE_PATH *) ChildDevicePathNode;
   5008             ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;
   5009             ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;
   5010             //
   5011             // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
   5012             //
   5013             CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);
   5014           }
   5015           return;
   5016         }
   5017       } while (--IdentifyRetry > 0);
   5018     } else if ((DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&
   5019        (DevicePathSubType (ChildDevicePathNode) == MSG_UFS_DP)) {
   5020       CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoUfsInterfaceGuid);
   5021       break;
   5022     }
   5023     DevicePathNode = ChildDevicePathNode;
   5024   }
   5025 
   5026   return;
   5027 }
   5028