Home | History | Annotate | Download | only in ScsiBusDxe
      1 /** @file
      2   SCSI Bus driver that layers on every SCSI Pass Thru and
      3   Extended SCSI Pass Thru protocol in the system.
      4 
      5 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 
     17 #include "ScsiBus.h"
     18 
     19 
     20 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = {
     21   SCSIBusDriverBindingSupported,
     22   SCSIBusDriverBindingStart,
     23   SCSIBusDriverBindingStop,
     24   0xa,
     25   NULL,
     26   NULL
     27 };
     28 
     29 VOID  *mWorkingBuffer;
     30 
     31 /**
     32   Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
     33 
     34   @param  Packet         The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
     35   @param  CommandPacket  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
     36 
     37 **/
     38 EFI_STATUS
     39 EFIAPI
     40 ScsiioToPassThruPacket (
     41   IN      EFI_SCSI_IO_SCSI_REQUEST_PACKET         *Packet,
     42   OUT     EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *CommandPacket
     43   );
     44 
     45 /**
     46   Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
     47 
     48   @param  ScsiPacket  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
     49   @param  Packet      The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
     50 
     51 **/
     52 EFI_STATUS
     53 EFIAPI
     54 PassThruToScsiioPacket (
     55   IN     EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *ScsiPacket,
     56   OUT    EFI_SCSI_IO_SCSI_REQUEST_PACKET         *Packet
     57   );
     58 
     59 /**
     60   Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
     61   SCSI IO Packet.
     62 
     63   @param  Event    The instance of EFI_EVENT.
     64   @param  Context  The parameter passed in.
     65 
     66 **/
     67 VOID
     68 EFIAPI
     69 NotifyFunction (
     70   IN  EFI_EVENT  Event,
     71   IN  VOID       *Context
     72   );
     73 
     74 /**
     75   Allocates an aligned buffer for SCSI device.
     76 
     77   This function allocates an aligned buffer for the SCSI device to perform
     78   SCSI pass through operations. The alignment requirement is from SCSI pass
     79   through interface.
     80 
     81   @param  ScsiIoDevice      The SCSI child device involved for the operation.
     82   @param  BufferSize        The request buffer size.
     83 
     84   @return A pointer to the aligned buffer or NULL if the allocation fails.
     85 
     86 **/
     87 VOID *
     88 AllocateAlignedBuffer (
     89   IN SCSI_IO_DEV              *ScsiIoDevice,
     90   IN UINTN                    BufferSize
     91   )
     92 {
     93   return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiIoDevice->ScsiIo.IoAlign);
     94 }
     95 
     96 /**
     97   Frees an aligned buffer for SCSI device.
     98 
     99   This function frees an aligned buffer for the SCSI device to perform
    100   SCSI pass through operations.
    101 
    102   @param  Buffer            The aligned buffer to be freed.
    103   @param  BufferSize        The request buffer size.
    104 
    105 **/
    106 VOID
    107 FreeAlignedBuffer (
    108   IN VOID                     *Buffer,
    109   IN UINTN                    BufferSize
    110   )
    111 {
    112   if (Buffer != NULL) {
    113     FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
    114   }
    115 }
    116 
    117 /**
    118   The user Entry Point for module ScsiBus. The user code starts with this function.
    119 
    120   @param  ImageHandle    The firmware allocated handle for the EFI image.
    121   @param  SystemTable    A pointer to the EFI System Table.
    122 
    123   @retval EFI_SUCCESS    The entry point is executed successfully.
    124   @retval other          Some error occurs when executing this entry point.
    125 
    126 **/
    127 EFI_STATUS
    128 EFIAPI
    129 InitializeScsiBus(
    130   IN EFI_HANDLE           ImageHandle,
    131   IN EFI_SYSTEM_TABLE     *SystemTable
    132   )
    133 {
    134   EFI_STATUS              Status;
    135 
    136   //
    137   // Install driver model protocol(s).
    138   //
    139   Status = EfiLibInstallDriverBindingComponentName2 (
    140              ImageHandle,
    141              SystemTable,
    142              &gSCSIBusDriverBinding,
    143              ImageHandle,
    144              &gScsiBusComponentName,
    145              &gScsiBusComponentName2
    146              );
    147   ASSERT_EFI_ERROR (Status);
    148 
    149   return Status;
    150 }
    151 
    152 
    153 /**
    154   Test to see if this driver supports ControllerHandle.
    155 
    156   This service is called by the EFI boot service ConnectController(). In order
    157   to make drivers as small as possible, there are a few calling restrictions for
    158   this service. ConnectController() must follow these calling restrictions. If
    159   any other agent wishes to call Supported() it must also follow these calling
    160   restrictions.
    161 
    162   @param  This                Protocol instance pointer.
    163   @param  ControllerHandle    Handle of device to test
    164   @param  RemainingDevicePath Optional parameter use to pick a specific child
    165                               device to start.
    166 
    167   @retval EFI_SUCCESS         This driver supports this device
    168   @retval EFI_ALREADY_STARTED This driver is already running on this device
    169   @retval other               This driver does not support this device
    170 
    171 **/
    172 EFI_STATUS
    173 EFIAPI
    174 SCSIBusDriverBindingSupported (
    175   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    176   IN EFI_HANDLE                   Controller,
    177   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    178   )
    179 {
    180   EFI_STATUS                      Status;
    181   EFI_SCSI_PASS_THRU_PROTOCOL     *PassThru;
    182   EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtPassThru;
    183   UINT64                          Lun;
    184   UINT8                           *TargetId;
    185   SCSI_TARGET_ID                  ScsiTargetId;
    186 
    187   TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
    188   SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
    189 
    190   //
    191   // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
    192   // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
    193   // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
    194   //
    195   Status = gBS->OpenProtocol (
    196                   Controller,
    197                   &gEfiExtScsiPassThruProtocolGuid,
    198                   (VOID **)&ExtPassThru,
    199                   This->DriverBindingHandle,
    200                   Controller,
    201                   EFI_OPEN_PROTOCOL_BY_DRIVER
    202                   );
    203 
    204   if (Status == EFI_ALREADY_STARTED) {
    205     return EFI_SUCCESS;
    206   } else if (!EFI_ERROR(Status)) {
    207     //
    208     // Check if RemainingDevicePath is NULL or the End of Device Path Node,
    209     // if yes, return EFI_SUCCESS.
    210     //
    211     if ((RemainingDevicePath == NULL) || IsDevicePathEnd (RemainingDevicePath)) {
    212       //
    213       // Close protocol regardless of RemainingDevicePath validation
    214       //
    215       gBS->CloseProtocol (
    216              Controller,
    217              &gEfiExtScsiPassThruProtocolGuid,
    218              This->DriverBindingHandle,
    219              Controller
    220              );
    221       return EFI_SUCCESS;
    222     } else {
    223       //
    224       // If RemainingDevicePath isn't the End of Device Path Node, check its validation
    225       //
    226       Status = ExtPassThru->GetTargetLun (ExtPassThru, RemainingDevicePath, &TargetId, &Lun);
    227       //
    228       // Close protocol regardless of RemainingDevicePath validation
    229       //
    230       gBS->CloseProtocol (
    231              Controller,
    232              &gEfiExtScsiPassThruProtocolGuid,
    233              This->DriverBindingHandle,
    234              Controller
    235              );
    236       if (!EFI_ERROR(Status)) {
    237         return EFI_SUCCESS;
    238       }
    239     }
    240   }
    241 
    242   //
    243   // Come here in 2 condition:
    244   // 1. ExtPassThru doesn't exist.
    245   // 2. ExtPassThru exists but RemainingDevicePath is invalid.
    246   //
    247   Status = gBS->OpenProtocol (
    248                   Controller,
    249                   &gEfiScsiPassThruProtocolGuid,
    250                   (VOID **)&PassThru,
    251                   This->DriverBindingHandle,
    252                   Controller,
    253                   EFI_OPEN_PROTOCOL_BY_DRIVER
    254                   );
    255 
    256   if (Status == EFI_ALREADY_STARTED) {
    257     return EFI_SUCCESS;
    258   }
    259 
    260   if (EFI_ERROR (Status)) {
    261     return Status;
    262   }
    263 
    264   //
    265   // Test RemainingDevicePath is valid or not.
    266   //
    267   if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
    268     Status = PassThru->GetTargetLun (PassThru, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);
    269   }
    270 
    271   gBS->CloseProtocol (
    272          Controller,
    273          &gEfiScsiPassThruProtocolGuid,
    274          This->DriverBindingHandle,
    275          Controller
    276          );
    277   return Status;
    278 }
    279 
    280 
    281 /**
    282   Start this driver on ControllerHandle.
    283 
    284   This service is called by the EFI boot service ConnectController(). In order
    285   to make drivers as small as possible, there are a few calling restrictions for
    286   this service. ConnectController() must follow these calling restrictions. If
    287   any other agent wishes to call Start() it must also follow these calling
    288   restrictions.
    289 
    290   @param  This                 Protocol instance pointer.
    291   @param  ControllerHandle     Handle of device to bind driver to
    292   @param  RemainingDevicePath  Optional parameter use to pick a specific child
    293                                device to start.
    294 
    295   @retval EFI_SUCCESS          This driver is added to ControllerHandle
    296   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
    297   @retval other                This driver does not support this device
    298 
    299 **/
    300 EFI_STATUS
    301 EFIAPI
    302 SCSIBusDriverBindingStart (
    303   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    304   IN EFI_HANDLE                   Controller,
    305   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    306   )
    307 {
    308   UINT64                                Lun;
    309   UINT8                                 *TargetId;
    310   BOOLEAN                               ScanOtherPuns;
    311   BOOLEAN                               FromFirstTarget;
    312   BOOLEAN                               ExtScsiSupport;
    313   EFI_STATUS                            Status;
    314   EFI_STATUS                            DevicePathStatus;
    315   EFI_STATUS                            PassThruStatus;
    316   SCSI_BUS_DEVICE                       *ScsiBusDev;
    317   SCSI_TARGET_ID                        ScsiTargetId;
    318   EFI_DEVICE_PATH_PROTOCOL              *ParentDevicePath;
    319   EFI_SCSI_PASS_THRU_PROTOCOL           *ScsiInterface;
    320   EFI_EXT_SCSI_PASS_THRU_PROTOCOL       *ExtScsiInterface;
    321   EFI_SCSI_BUS_PROTOCOL                 *BusIdentify;
    322 
    323   TargetId        = NULL;
    324   ScanOtherPuns   = TRUE;
    325   FromFirstTarget = FALSE;
    326   ExtScsiSupport  = FALSE;
    327   PassThruStatus  = EFI_SUCCESS;
    328 
    329   TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
    330   SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
    331 
    332   DevicePathStatus = gBS->OpenProtocol (
    333                             Controller,
    334                             &gEfiDevicePathProtocolGuid,
    335                             (VOID **) &ParentDevicePath,
    336                             This->DriverBindingHandle,
    337                             Controller,
    338                             EFI_OPEN_PROTOCOL_BY_DRIVER
    339                             );
    340   if (EFI_ERROR (DevicePathStatus) && (DevicePathStatus != EFI_ALREADY_STARTED)) {
    341     return DevicePathStatus;
    342   }
    343 
    344   //
    345   // Report Status Code to indicate SCSI bus starts
    346   //
    347   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    348     EFI_PROGRESS_CODE,
    349     (EFI_IO_BUS_SCSI | EFI_IOB_PC_INIT),
    350     ParentDevicePath
    351     );
    352 
    353   //
    354   // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
    355   // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
    356   // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
    357   //
    358   Status = gBS->OpenProtocol (
    359                   Controller,
    360                   &gEfiExtScsiPassThruProtocolGuid,
    361                   (VOID **) &ExtScsiInterface,
    362                   This->DriverBindingHandle,
    363                   Controller,
    364                   EFI_OPEN_PROTOCOL_BY_DRIVER
    365                   );
    366   //
    367   // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
    368   //
    369   if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
    370     Status = gBS->OpenProtocol (
    371                     Controller,
    372                     &gEfiScsiPassThruProtocolGuid,
    373                     (VOID **) &ScsiInterface,
    374                     This->DriverBindingHandle,
    375                     Controller,
    376                     EFI_OPEN_PROTOCOL_BY_DRIVER
    377                     );
    378     //
    379     // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
    380     //
    381     if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
    382       if (!EFI_ERROR(DevicePathStatus)) {
    383         gBS->CloseProtocol (
    384                Controller,
    385                &gEfiDevicePathProtocolGuid,
    386                This->DriverBindingHandle,
    387                Controller
    388                );
    389       }
    390       return Status;
    391     }
    392   } else {
    393     //
    394     // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
    395     // with BY_DRIVER if it is also present on the handle. The intent is to prevent
    396     // another SCSI Bus Driver to work on the same host handle.
    397     //
    398     ExtScsiSupport = TRUE;
    399     PassThruStatus = gBS->OpenProtocol (
    400                             Controller,
    401                             &gEfiScsiPassThruProtocolGuid,
    402                             (VOID **) &ScsiInterface,
    403                             This->DriverBindingHandle,
    404                             Controller,
    405                             EFI_OPEN_PROTOCOL_BY_DRIVER
    406                             );
    407   }
    408 
    409   if (Status != EFI_ALREADY_STARTED) {
    410     //
    411     // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
    412     // on this handle for this time. Then construct Host controller private data.
    413     //
    414     ScsiBusDev = NULL;
    415     ScsiBusDev = AllocateZeroPool(sizeof(SCSI_BUS_DEVICE));
    416     if (ScsiBusDev == NULL) {
    417       Status = EFI_OUT_OF_RESOURCES;
    418       goto ErrorExit;
    419     }
    420     ScsiBusDev->Signature        = SCSI_BUS_DEVICE_SIGNATURE;
    421     ScsiBusDev->ExtScsiSupport   = ExtScsiSupport;
    422     ScsiBusDev->DevicePath       = ParentDevicePath;
    423     if (ScsiBusDev->ExtScsiSupport) {
    424       ScsiBusDev->ExtScsiInterface = ExtScsiInterface;
    425     } else {
    426       ScsiBusDev->ScsiInterface    = ScsiInterface;
    427     }
    428 
    429     //
    430     // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
    431     // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
    432     // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
    433     //
    434     Status = gBS->InstallProtocolInterface (
    435                     &Controller,
    436                     &gEfiCallerIdGuid,
    437                     EFI_NATIVE_INTERFACE,
    438                     &ScsiBusDev->BusIdentify
    439                     );
    440     if (EFI_ERROR (Status)) {
    441       goto ErrorExit;
    442     }
    443   } else {
    444     //
    445     // Go through here means Start() is re-invoked again, nothing special is required to do except
    446     // picking up Host controller private information.
    447     //
    448     Status = gBS->OpenProtocol (
    449                     Controller,
    450                     &gEfiCallerIdGuid,
    451                     (VOID **) &BusIdentify,
    452                     This->DriverBindingHandle,
    453                     Controller,
    454                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    455                     );
    456 
    457     if (EFI_ERROR (Status)) {
    458       return Status;
    459     }
    460     ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify);
    461   }
    462 
    463   //
    464   // Report Status Code to indicate detecting devices on bus
    465   //
    466   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    467     EFI_PROGRESS_CODE,
    468     (EFI_IO_BUS_SCSI | EFI_IOB_PC_DETECT),
    469     ParentDevicePath
    470     );
    471 
    472   Lun  = 0;
    473   if (RemainingDevicePath == NULL) {
    474     //
    475     // If RemainingDevicePath is NULL,
    476     // must enumerate all SCSI devices anyway
    477     //
    478     FromFirstTarget = TRUE;
    479   } else if (!IsDevicePathEnd (RemainingDevicePath)) {
    480     //
    481     // If RemainingDevicePath isn't the End of Device Path Node,
    482     // only scan the specified device by RemainingDevicePath
    483     //
    484     if (ScsiBusDev->ExtScsiSupport) {
    485       Status = ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun);
    486     } else {
    487       Status = ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);
    488     }
    489 
    490     if (EFI_ERROR (Status)) {
    491       return Status;
    492     }
    493   } else {
    494     //
    495     // If RemainingDevicePath is the End of Device Path Node,
    496     // skip enumerate any device and return EFI_SUCESSS
    497     //
    498     ScanOtherPuns = FALSE;
    499   }
    500 
    501   while(ScanOtherPuns) {
    502     if (FromFirstTarget) {
    503       //
    504       // Remaining Device Path is NULL, scan all the possible Puns in the
    505       // SCSI Channel.
    506       //
    507       if (ScsiBusDev->ExtScsiSupport) {
    508         Status = ScsiBusDev->ExtScsiInterface->GetNextTargetLun (ScsiBusDev->ExtScsiInterface, &TargetId, &Lun);
    509       } else {
    510         Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId.ScsiId.Scsi, &Lun);
    511       }
    512       if (EFI_ERROR (Status)) {
    513         //
    514         // no legal Pun and Lun found any more
    515         //
    516         break;
    517       }
    518     } else {
    519       ScanOtherPuns = FALSE;
    520     }
    521     //
    522     // Avoid creating handle for the host adapter.
    523     //
    524     if (ScsiBusDev->ExtScsiSupport) {
    525       if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) {
    526         continue;
    527       }
    528     } else {
    529       if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) {
    530         continue;
    531       }
    532     }
    533     //
    534     // Scan for the scsi device, if it attaches to the scsi bus,
    535     // then create handle and install scsi i/o protocol.
    536     //
    537     Status = ScsiScanCreateDevice (This, Controller, &ScsiTargetId, Lun, ScsiBusDev);
    538   }
    539   return EFI_SUCCESS;
    540 
    541 ErrorExit:
    542 
    543   if (ScsiBusDev != NULL) {
    544     FreePool (ScsiBusDev);
    545   }
    546 
    547   if (ExtScsiSupport) {
    548     gBS->CloseProtocol (
    549            Controller,
    550            &gEfiExtScsiPassThruProtocolGuid,
    551            This->DriverBindingHandle,
    552            Controller
    553            );
    554     if (!EFI_ERROR (PassThruStatus)) {
    555       gBS->CloseProtocol (
    556              Controller,
    557              &gEfiScsiPassThruProtocolGuid,
    558              This->DriverBindingHandle,
    559              Controller
    560              );
    561     }
    562   } else {
    563     gBS->CloseProtocol (
    564            Controller,
    565            &gEfiScsiPassThruProtocolGuid,
    566            This->DriverBindingHandle,
    567            Controller
    568            );
    569   }
    570   return Status;
    571 }
    572 
    573 /**
    574   Stop this driver on ControllerHandle.
    575 
    576   This service is called by the EFI boot service DisconnectController().
    577   In order to make drivers as small as possible, there are a few calling
    578   restrictions for this service. DisconnectController() must follow these
    579   calling restrictions. If any other agent wishes to call Stop() it must also
    580   follow these calling restrictions.
    581 
    582   @param  This              Protocol instance pointer.
    583   @param  ControllerHandle  Handle of device to stop driver on
    584   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
    585                             children is zero stop the entire bus driver.
    586   @param  ChildHandleBuffer List of Child Handles to Stop.
    587 
    588   @retval EFI_SUCCESS       This driver is removed ControllerHandle
    589   @retval other             This driver was not removed from this device
    590 
    591 **/
    592 EFI_STATUS
    593 EFIAPI
    594 SCSIBusDriverBindingStop (
    595   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
    596   IN  EFI_HANDLE                      Controller,
    597   IN  UINTN                           NumberOfChildren,
    598   IN  EFI_HANDLE                      *ChildHandleBuffer
    599   )
    600 {
    601   EFI_STATUS                  Status;
    602   BOOLEAN                     AllChildrenStopped;
    603   UINTN                       Index;
    604   EFI_SCSI_IO_PROTOCOL        *ScsiIo;
    605   SCSI_IO_DEV                 *ScsiIoDevice;
    606   VOID                        *ScsiPassThru;
    607   EFI_SCSI_BUS_PROTOCOL       *Scsidentifier;
    608   SCSI_BUS_DEVICE             *ScsiBusDev;
    609 
    610   if (NumberOfChildren == 0) {
    611     //
    612     // Get the SCSI_BUS_DEVICE
    613     //
    614     Status = gBS->OpenProtocol (
    615                     Controller,
    616                     &gEfiCallerIdGuid,
    617                     (VOID **) &Scsidentifier,
    618                     This->DriverBindingHandle,
    619                     Controller,
    620                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    621                     );
    622 
    623     if (EFI_ERROR (Status)) {
    624       return EFI_DEVICE_ERROR;
    625     }
    626 
    627     ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier);
    628 
    629     //
    630     // Uninstall SCSI Bus Protocol
    631     //
    632     gBS->UninstallProtocolInterface (
    633            Controller,
    634            &gEfiCallerIdGuid,
    635            &ScsiBusDev->BusIdentify
    636            );
    637 
    638     //
    639     // Close the bus driver
    640     //
    641     if (ScsiBusDev->ExtScsiSupport) {
    642       //
    643       // Close ExtPassThru Protocol from this controller handle
    644       //
    645       gBS->CloseProtocol (
    646              Controller,
    647              &gEfiExtScsiPassThruProtocolGuid,
    648              This->DriverBindingHandle,
    649              Controller
    650              );
    651       //
    652       // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.
    653       // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle.
    654       // So Stop() needs to try to close PassThru if present here.
    655       //
    656       gBS->CloseProtocol (
    657              Controller,
    658              &gEfiScsiPassThruProtocolGuid,
    659              This->DriverBindingHandle,
    660              Controller
    661              );
    662     } else {
    663       gBS->CloseProtocol (
    664              Controller,
    665              &gEfiScsiPassThruProtocolGuid,
    666              This->DriverBindingHandle,
    667              Controller
    668              );
    669     }
    670 
    671     gBS->CloseProtocol (
    672            Controller,
    673            &gEfiDevicePathProtocolGuid,
    674            This->DriverBindingHandle,
    675            Controller
    676            );
    677     FreePool (ScsiBusDev);
    678     return EFI_SUCCESS;
    679   }
    680 
    681   AllChildrenStopped = TRUE;
    682 
    683   for (Index = 0; Index < NumberOfChildren; Index++) {
    684 
    685     Status = gBS->OpenProtocol (
    686                     ChildHandleBuffer[Index],
    687                     &gEfiScsiIoProtocolGuid,
    688                     (VOID **) &ScsiIo,
    689                     This->DriverBindingHandle,
    690                     Controller,
    691                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    692                     );
    693     if (EFI_ERROR (Status)) {
    694       AllChildrenStopped = FALSE;
    695       continue;
    696     }
    697 
    698     ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (ScsiIo);
    699     //
    700     // Close the child handle
    701     //
    702     if (ScsiIoDevice->ExtScsiSupport) {
    703       Status = gBS->CloseProtocol (
    704                       Controller,
    705                       &gEfiExtScsiPassThruProtocolGuid,
    706                       This->DriverBindingHandle,
    707                       ChildHandleBuffer[Index]
    708                       );
    709 
    710     } else {
    711       Status = gBS->CloseProtocol (
    712                       Controller,
    713                       &gEfiScsiPassThruProtocolGuid,
    714                       This->DriverBindingHandle,
    715                       ChildHandleBuffer[Index]
    716                       );
    717     }
    718 
    719     Status = gBS->UninstallMultipleProtocolInterfaces (
    720                     ChildHandleBuffer[Index],
    721                     &gEfiDevicePathProtocolGuid,
    722                     ScsiIoDevice->DevicePath,
    723                     &gEfiScsiIoProtocolGuid,
    724                     &ScsiIoDevice->ScsiIo,
    725                     NULL
    726                     );
    727     if (EFI_ERROR (Status)) {
    728       AllChildrenStopped = FALSE;
    729       if (ScsiIoDevice->ExtScsiSupport) {
    730         gBS->OpenProtocol (
    731                Controller,
    732                &gEfiExtScsiPassThruProtocolGuid,
    733                &ScsiPassThru,
    734                This->DriverBindingHandle,
    735                ChildHandleBuffer[Index],
    736                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    737                );
    738       } else {
    739         gBS->OpenProtocol (
    740                Controller,
    741                &gEfiScsiPassThruProtocolGuid,
    742                &ScsiPassThru,
    743                This->DriverBindingHandle,
    744                ChildHandleBuffer[Index],
    745                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    746                );
    747       }
    748     } else {
    749       FreePool (ScsiIoDevice);
    750     }
    751   }
    752 
    753   if (!AllChildrenStopped) {
    754     return EFI_DEVICE_ERROR;
    755   }
    756 
    757   return EFI_SUCCESS;
    758 }
    759 
    760 
    761 /**
    762   Retrieves the device type information of the SCSI Controller.
    763 
    764   @param  This          Protocol instance pointer.
    765   @param  DeviceType    A pointer to the device type information retrieved from
    766                         the SCSI Controller.
    767 
    768   @retval EFI_SUCCESS             Retrieves the device type information successfully.
    769   @retval EFI_INVALID_PARAMETER   The DeviceType is NULL.
    770 
    771 **/
    772 EFI_STATUS
    773 EFIAPI
    774 ScsiGetDeviceType (
    775   IN  EFI_SCSI_IO_PROTOCOL     *This,
    776   OUT UINT8                    *DeviceType
    777   )
    778 {
    779   SCSI_IO_DEV *ScsiIoDevice;
    780 
    781   if (DeviceType == NULL) {
    782     return EFI_INVALID_PARAMETER;
    783   }
    784 
    785   ScsiIoDevice  = SCSI_IO_DEV_FROM_THIS (This);
    786   *DeviceType   = ScsiIoDevice->ScsiDeviceType;
    787   return EFI_SUCCESS;
    788 }
    789 
    790 
    791 /**
    792   Retrieves the device location in the SCSI channel.
    793 
    794   @param  This   Protocol instance pointer.
    795   @param  Target A pointer to the Target ID of a SCSI device
    796                  on the SCSI channel.
    797   @param  Lun    A pointer to the LUN of the SCSI device on
    798                  the SCSI channel.
    799 
    800   @retval EFI_SUCCESS           Retrieves the device location successfully.
    801   @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.
    802 
    803 **/
    804 EFI_STATUS
    805 EFIAPI
    806 ScsiGetDeviceLocation (
    807   IN  EFI_SCSI_IO_PROTOCOL    *This,
    808   IN OUT UINT8                **Target,
    809   OUT UINT64                  *Lun
    810   )
    811 {
    812   SCSI_IO_DEV *ScsiIoDevice;
    813 
    814   if (Target == NULL || Lun == NULL) {
    815     return EFI_INVALID_PARAMETER;
    816   }
    817 
    818   ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
    819 
    820   CopyMem (*Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
    821 
    822   *Lun         = ScsiIoDevice->Lun;
    823 
    824   return EFI_SUCCESS;
    825 }
    826 
    827 /**
    828   Resets the SCSI Bus that the SCSI Controller is attached to.
    829 
    830   @param  This  Protocol instance pointer.
    831 
    832   @retval  EFI_SUCCESS       The SCSI bus is reset successfully.
    833   @retval  EFI_DEVICE_ERROR  Errors encountered when resetting the SCSI bus.
    834   @retval  EFI_UNSUPPORTED   The bus reset operation is not supported by the
    835                              SCSI Host Controller.
    836   @retval  EFI_TIMEOUT       A timeout occurred while attempting to reset
    837                              the SCSI bus.
    838 **/
    839 EFI_STATUS
    840 EFIAPI
    841 ScsiResetBus (
    842   IN  EFI_SCSI_IO_PROTOCOL     *This
    843   )
    844 {
    845   SCSI_IO_DEV *ScsiIoDevice;
    846 
    847   ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
    848 
    849   //
    850   // Report Status Code to indicate reset happens
    851   //
    852   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    853     EFI_PROGRESS_CODE,
    854     (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
    855     ScsiIoDevice->ScsiBusDeviceData->DevicePath
    856     );
    857 
    858   if (ScsiIoDevice->ExtScsiSupport){
    859     return ScsiIoDevice->ExtScsiPassThru->ResetChannel (ScsiIoDevice->ExtScsiPassThru);
    860   } else {
    861     return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru);
    862   }
    863 }
    864 
    865 
    866 /**
    867   Resets the SCSI Controller that the device handle specifies.
    868 
    869   @param  This  Protocol instance pointer.
    870 
    871   @retval  EFI_SUCCESS       Reset the SCSI controller successfully.
    872   @retval  EFI_DEVICE_ERROR  Errors are encountered when resetting the SCSI Controller.
    873   @retval  EFI_UNSUPPORTED   The SCSI bus does not support a device reset operation.
    874   @retval  EFI_TIMEOUT       A timeout occurred while attempting to reset the
    875                              SCSI Controller.
    876 **/
    877 EFI_STATUS
    878 EFIAPI
    879 ScsiResetDevice (
    880   IN  EFI_SCSI_IO_PROTOCOL     *This
    881   )
    882 {
    883   SCSI_IO_DEV  *ScsiIoDevice;
    884   UINT8        Target[TARGET_MAX_BYTES];
    885 
    886   ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
    887 
    888   //
    889   // Report Status Code to indicate reset happens
    890   //
    891   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    892     EFI_PROGRESS_CODE,
    893     (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
    894     ScsiIoDevice->ScsiBusDeviceData->DevicePath
    895     );
    896 
    897   CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
    898 
    899 
    900   if (ScsiIoDevice->ExtScsiSupport) {
    901     return ScsiIoDevice->ExtScsiPassThru->ResetTargetLun (
    902                                         ScsiIoDevice->ExtScsiPassThru,
    903                                         Target,
    904                                         ScsiIoDevice->Lun
    905                                           );
    906   } else {
    907     return ScsiIoDevice->ScsiPassThru->ResetTarget (
    908                                           ScsiIoDevice->ScsiPassThru,
    909                                           ScsiIoDevice->Pun.ScsiId.Scsi,
    910                                           ScsiIoDevice->Lun
    911                                             );
    912   }
    913 }
    914 
    915 
    916 /**
    917   Sends a SCSI Request Packet to the SCSI Controller for execution.
    918 
    919   @param  This            Protocol instance pointer.
    920   @param  CommandPacket   The SCSI request packet to send to the SCSI
    921                           Controller specified by the device handle.
    922   @param  Event           If the SCSI bus where the SCSI device is attached
    923                           does not support non-blocking I/O, then Event is
    924                           ignored, and blocking I/O is performed.
    925                           If Event is NULL, then blocking I/O is performed.
    926                           If Event is not NULL and non-blocking I/O is
    927                           supported, then non-blocking I/O is performed,
    928                           and Event will be signaled when the SCSI Request
    929                           Packet completes.
    930 
    931   @retval EFI_SUCCESS         The SCSI Request Packet was sent by the host
    932                               successfully, and TransferLength bytes were
    933                               transferred to/from DataBuffer.See
    934                               HostAdapterStatus, TargetStatus,
    935                               SenseDataLength, and SenseData in that order
    936                               for additional status information.
    937   @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
    938                               but the entire DataBuffer could not be transferred.
    939                               The actual number of bytes transferred is returned
    940                               in TransferLength. See HostAdapterStatus,
    941                               TargetStatus, SenseDataLength, and SenseData in
    942                               that order for additional status information.
    943   @retval EFI_NOT_READY       The SCSI Request Packet could not be sent because
    944                               there are too many SCSI Command Packets already
    945                               queued.The caller may retry again later.
    946   @retval EFI_DEVICE_ERROR    A device error occurred while attempting to send
    947                               the SCSI Request Packet. See HostAdapterStatus,
    948                               TargetStatus, SenseDataLength, and SenseData in
    949                               that order for additional status information.
    950   @retval EFI_INVALID_PARAMETER  The contents of CommandPacket are invalid.
    951                                  The SCSI Request Packet was not sent, so no
    952                                  additional status information is available.
    953   @retval EFI_UNSUPPORTED     The command described by the SCSI Request Packet
    954                               is not supported by the SCSI initiator(i.e., SCSI
    955                               Host Controller). The SCSI Request Packet was not
    956                               sent, so no additional status information is
    957                               available.
    958   @retval EFI_TIMEOUT         A timeout occurred while waiting for the SCSI
    959                               Request Packet to execute. See HostAdapterStatus,
    960                               TargetStatus, SenseDataLength, and SenseData in
    961                               that order for additional status information.
    962 **/
    963 EFI_STATUS
    964 EFIAPI
    965 ScsiExecuteSCSICommand (
    966   IN     EFI_SCSI_IO_PROTOCOL                     *This,
    967   IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET          *Packet,
    968   IN     EFI_EVENT                                Event  OPTIONAL
    969   )
    970 {
    971   SCSI_IO_DEV                                 *ScsiIoDevice;
    972   EFI_STATUS                                  Status;
    973   UINT8                                       Target[TARGET_MAX_BYTES];
    974   EFI_EVENT                                   PacketEvent;
    975   EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *ExtRequestPacket;
    976   SCSI_EVENT_DATA                             EventData;
    977 
    978   PacketEvent = NULL;
    979 
    980   if (Packet == NULL) {
    981     return EFI_INVALID_PARAMETER;
    982   }
    983 
    984   ScsiIoDevice  = SCSI_IO_DEV_FROM_THIS (This);
    985   CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
    986 
    987   if (ScsiIoDevice->ExtScsiSupport) {
    988     ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;
    989 
    990     if (((ScsiIoDevice->ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event !=  NULL)) {
    991       Status = ScsiIoDevice->ExtScsiPassThru->PassThru (
    992                                                 ScsiIoDevice->ExtScsiPassThru,
    993                                                 Target,
    994                                                 ScsiIoDevice->Lun,
    995                                                 ExtRequestPacket,
    996                                                 Event
    997                                                 );
    998     } else {
    999       //
   1000       // If there's no event or the SCSI Device doesn't support NON-BLOCKING,
   1001       // let the 'Event' parameter for PassThru() be NULL.
   1002       //
   1003       Status = ScsiIoDevice->ExtScsiPassThru->PassThru (
   1004                                                 ScsiIoDevice->ExtScsiPassThru,
   1005                                                 Target,
   1006                                                 ScsiIoDevice->Lun,
   1007                                                 ExtRequestPacket,
   1008                                                 NULL
   1009                                                 );
   1010       if ((!EFI_ERROR(Status)) && (Event != NULL)) {
   1011         //
   1012         // Signal Event to tell caller to pick up the SCSI IO packet if the
   1013         // PassThru() succeeds.
   1014         //
   1015         gBS->SignalEvent (Event);
   1016       }
   1017     }
   1018   } else {
   1019 
   1020     mWorkingBuffer = AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
   1021 
   1022     if (mWorkingBuffer == NULL) {
   1023       return EFI_DEVICE_ERROR;
   1024     }
   1025 
   1026     //
   1027     // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
   1028     //
   1029     Status = ScsiioToPassThruPacket(Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer);
   1030     if (EFI_ERROR(Status)) {
   1031       FreePool(mWorkingBuffer);
   1032       return Status;
   1033     }
   1034 
   1035     if (((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event !=  NULL)) {
   1036       EventData.Data1 = (VOID*)Packet;
   1037       EventData.Data2 = Event;
   1038       //
   1039       // Create Event
   1040       //
   1041       Status = gBS->CreateEvent (
   1042                        EVT_NOTIFY_SIGNAL,
   1043                        TPL_NOTIFY,
   1044                        NotifyFunction,
   1045                        &EventData,
   1046                        &PacketEvent
   1047                        );
   1048       if (EFI_ERROR(Status)) {
   1049         FreePool(mWorkingBuffer);
   1050         return Status;
   1051       }
   1052 
   1053       Status = ScsiIoDevice->ScsiPassThru->PassThru (
   1054                                           ScsiIoDevice->ScsiPassThru,
   1055                                           ScsiIoDevice->Pun.ScsiId.Scsi,
   1056                                           ScsiIoDevice->Lun,
   1057                                           mWorkingBuffer,
   1058                                           PacketEvent
   1059                                           );
   1060 
   1061       if (EFI_ERROR(Status)) {
   1062         FreePool(mWorkingBuffer);
   1063         gBS->CloseEvent(PacketEvent);
   1064         return Status;
   1065       }
   1066 
   1067     } else {
   1068       //
   1069       // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
   1070       // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
   1071       //
   1072       Status = ScsiIoDevice->ScsiPassThru->PassThru (
   1073                                           ScsiIoDevice->ScsiPassThru,
   1074                                           ScsiIoDevice->Pun.ScsiId.Scsi,
   1075                                           ScsiIoDevice->Lun,
   1076                                           mWorkingBuffer,
   1077                                           NULL
   1078                                           );
   1079       if (EFI_ERROR(Status)) {
   1080         FreePool(mWorkingBuffer);
   1081         return Status;
   1082       }
   1083 
   1084       PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer,Packet);
   1085       //
   1086       // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
   1087       // free mWorkingBuffer.
   1088       //
   1089       FreePool(mWorkingBuffer);
   1090 
   1091       //
   1092       // Signal Event to tell caller to pick up the SCSI IO Packet.
   1093       //
   1094       if (Event != NULL) {
   1095         gBS->SignalEvent (Event);
   1096       }
   1097     }
   1098   }
   1099   return Status;
   1100 }
   1101 
   1102 
   1103 /**
   1104   Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
   1105 
   1106   @param  This           Protocol instance pointer
   1107   @param  Controller     Controller handle
   1108   @param  TargetId       Tartget to be scanned
   1109   @param  Lun            The Lun of the SCSI device on the SCSI channel.
   1110   @param  ScsiBusDev     The pointer of SCSI_BUS_DEVICE
   1111 
   1112   @retval EFI_SUCCESS           Successfully to discover the device and attach
   1113                                 ScsiIoProtocol to it.
   1114   @retval EFI_OUT_OF_RESOURCES  Fail to discover the device.
   1115 
   1116 **/
   1117 EFI_STATUS
   1118 EFIAPI
   1119 ScsiScanCreateDevice (
   1120   IN     EFI_DRIVER_BINDING_PROTOCOL   *This,
   1121   IN     EFI_HANDLE                    Controller,
   1122   IN     SCSI_TARGET_ID                *TargetId,
   1123   IN     UINT64                        Lun,
   1124   IN OUT SCSI_BUS_DEVICE               *ScsiBusDev
   1125   )
   1126 {
   1127   EFI_STATUS                Status;
   1128   SCSI_IO_DEV               *ScsiIoDevice;
   1129   EFI_DEVICE_PATH_PROTOCOL  *ScsiDevicePath;
   1130   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
   1131   EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;
   1132   EFI_HANDLE                 DeviceHandle;
   1133 
   1134   DevicePath          = NULL;
   1135   RemainingDevicePath = NULL;
   1136   ScsiDevicePath      = NULL;
   1137   ScsiIoDevice        = NULL;
   1138 
   1139   //
   1140   // Build Device Path
   1141   //
   1142   if (ScsiBusDev->ExtScsiSupport){
   1143     Status = ScsiBusDev->ExtScsiInterface->BuildDevicePath (
   1144                                              ScsiBusDev->ExtScsiInterface,
   1145                                              &TargetId->ScsiId.ExtScsi[0],
   1146                                              Lun,
   1147                                              &ScsiDevicePath
   1148                                              );
   1149   } else {
   1150     Status = ScsiBusDev->ScsiInterface->BuildDevicePath (
   1151                                           ScsiBusDev->ScsiInterface,
   1152                                           TargetId->ScsiId.Scsi,
   1153                                           Lun,
   1154                                           &ScsiDevicePath
   1155                                           );
   1156   }
   1157 
   1158   if (EFI_ERROR(Status)) {
   1159     return Status;
   1160   }
   1161 
   1162   DevicePath = AppendDevicePathNode (
   1163                  ScsiBusDev->DevicePath,
   1164                  ScsiDevicePath
   1165                  );
   1166 
   1167   if (DevicePath == NULL) {
   1168     Status = EFI_OUT_OF_RESOURCES;
   1169     goto ErrorExit;
   1170   }
   1171 
   1172   DeviceHandle = NULL;
   1173   RemainingDevicePath = DevicePath;
   1174   Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
   1175   if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
   1176     //
   1177     // The device has been started, directly return to fast boot.
   1178     //
   1179     Status = EFI_ALREADY_STARTED;
   1180     goto ErrorExit;
   1181   }
   1182 
   1183   ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV));
   1184   if (ScsiIoDevice == NULL) {
   1185     Status = EFI_OUT_OF_RESOURCES;
   1186     goto ErrorExit;
   1187   }
   1188 
   1189   ScsiIoDevice->Signature                 = SCSI_IO_DEV_SIGNATURE;
   1190   ScsiIoDevice->ScsiBusDeviceData         = ScsiBusDev;
   1191   CopyMem(&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES);
   1192   ScsiIoDevice->Lun                       = Lun;
   1193 
   1194   if (ScsiBusDev->ExtScsiSupport) {
   1195     ScsiIoDevice->ExtScsiPassThru         = ScsiBusDev->ExtScsiInterface;
   1196     ScsiIoDevice->ExtScsiSupport          = TRUE;
   1197     ScsiIoDevice->ScsiIo.IoAlign          = ScsiIoDevice->ExtScsiPassThru->Mode->IoAlign;
   1198 
   1199   } else {
   1200     ScsiIoDevice->ScsiPassThru            = ScsiBusDev->ScsiInterface;
   1201     ScsiIoDevice->ExtScsiSupport          = FALSE;
   1202     ScsiIoDevice->ScsiIo.IoAlign          = ScsiIoDevice->ScsiPassThru->Mode->IoAlign;
   1203   }
   1204 
   1205   ScsiIoDevice->ScsiIo.GetDeviceType      = ScsiGetDeviceType;
   1206   ScsiIoDevice->ScsiIo.GetDeviceLocation  = ScsiGetDeviceLocation;
   1207   ScsiIoDevice->ScsiIo.ResetBus           = ScsiResetBus;
   1208   ScsiIoDevice->ScsiIo.ResetDevice        = ScsiResetDevice;
   1209   ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand;
   1210 
   1211   //
   1212   // Report Status Code here since the new SCSI device will be discovered
   1213   //
   1214   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
   1215     EFI_PROGRESS_CODE,
   1216     (EFI_IO_BUS_SCSI | EFI_IOB_PC_ENABLE),
   1217     ScsiBusDev->DevicePath
   1218     );
   1219 
   1220   if (!DiscoverScsiDevice (ScsiIoDevice)) {
   1221     Status = EFI_OUT_OF_RESOURCES;
   1222     goto ErrorExit;
   1223   }
   1224 
   1225   ScsiIoDevice->DevicePath = DevicePath;
   1226 
   1227   Status = gBS->InstallMultipleProtocolInterfaces (
   1228                   &ScsiIoDevice->Handle,
   1229                   &gEfiDevicePathProtocolGuid,
   1230                   ScsiIoDevice->DevicePath,
   1231                   &gEfiScsiIoProtocolGuid,
   1232                   &ScsiIoDevice->ScsiIo,
   1233                   NULL
   1234                   );
   1235   if (EFI_ERROR (Status)) {
   1236     goto ErrorExit;
   1237   } else {
   1238     if (ScsiBusDev->ExtScsiSupport) {
   1239       gBS->OpenProtocol (
   1240              Controller,
   1241              &gEfiExtScsiPassThruProtocolGuid,
   1242              (VOID **) &(ScsiBusDev->ExtScsiInterface),
   1243              This->DriverBindingHandle,
   1244              ScsiIoDevice->Handle,
   1245              EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
   1246              );
   1247      } else {
   1248       gBS->OpenProtocol (
   1249              Controller,
   1250              &gEfiScsiPassThruProtocolGuid,
   1251              (VOID **) &(ScsiBusDev->ScsiInterface),
   1252              This->DriverBindingHandle,
   1253              ScsiIoDevice->Handle,
   1254              EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
   1255              );
   1256      }
   1257   }
   1258   return EFI_SUCCESS;
   1259 
   1260 ErrorExit:
   1261 
   1262   //
   1263   // The memory space for ScsiDevicePath is allocated in
   1264   // ScsiPassThru->BuildDevicePath() function; It is no longer used
   1265   // after AppendDevicePathNode,so free the memory it occupies.
   1266   //
   1267   FreePool (ScsiDevicePath);
   1268 
   1269   if (DevicePath != NULL) {
   1270     FreePool (DevicePath);
   1271   }
   1272 
   1273   if (ScsiIoDevice != NULL) {
   1274     FreePool (ScsiIoDevice);
   1275   }
   1276 
   1277   return Status;
   1278 }
   1279 
   1280 
   1281 /**
   1282   Discovery SCSI Device
   1283 
   1284   @param  ScsiIoDevice    The pointer of SCSI_IO_DEV
   1285 
   1286   @retval  TRUE   Find SCSI Device and verify it.
   1287   @retval  FALSE  Unable to find SCSI Device.
   1288 
   1289 **/
   1290 BOOLEAN
   1291 DiscoverScsiDevice (
   1292   IN OUT  SCSI_IO_DEV   *ScsiIoDevice
   1293   )
   1294 {
   1295   EFI_STATUS            Status;
   1296   UINT32                InquiryDataLength;
   1297   UINT8                 SenseDataLength;
   1298   UINT8                 HostAdapterStatus;
   1299   UINT8                 TargetStatus;
   1300   EFI_SCSI_INQUIRY_DATA *InquiryData;
   1301   UINT8                 MaxRetry;
   1302   UINT8                 Index;
   1303   BOOLEAN               ScsiDeviceFound;
   1304 
   1305   HostAdapterStatus = 0;
   1306   TargetStatus      = 0;
   1307 
   1308   InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA));
   1309   if (InquiryData == NULL) {
   1310     ScsiDeviceFound = FALSE;
   1311     goto Done;
   1312   }
   1313 
   1314   //
   1315   // Using Inquiry command to scan for the device
   1316   //
   1317   InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
   1318   SenseDataLength   = 0;
   1319   ZeroMem (InquiryData, InquiryDataLength);
   1320 
   1321   MaxRetry = 2;
   1322   for (Index = 0; Index < MaxRetry; Index++) {
   1323     Status = ScsiInquiryCommand (
   1324               &ScsiIoDevice->ScsiIo,
   1325               SCSI_BUS_TIMEOUT,
   1326               NULL,
   1327               &SenseDataLength,
   1328               &HostAdapterStatus,
   1329               &TargetStatus,
   1330               (VOID *) InquiryData,
   1331               &InquiryDataLength,
   1332               FALSE
   1333               );
   1334     if (!EFI_ERROR (Status)) {
   1335       break;
   1336     } else if ((Status == EFI_BAD_BUFFER_SIZE) ||
   1337                (Status == EFI_INVALID_PARAMETER) ||
   1338                (Status == EFI_UNSUPPORTED)) {
   1339       ScsiDeviceFound = FALSE;
   1340       goto Done;
   1341     }
   1342   }
   1343 
   1344   if (Index == MaxRetry) {
   1345     ScsiDeviceFound = FALSE;
   1346     goto Done;
   1347   }
   1348 
   1349   //
   1350   // Retrieved inquiry data successfully
   1351   //
   1352   if ((InquiryData->Peripheral_Qualifier != 0) &&
   1353       (InquiryData->Peripheral_Qualifier != 3)) {
   1354     ScsiDeviceFound = FALSE;
   1355     goto Done;
   1356   }
   1357 
   1358   if (InquiryData->Peripheral_Qualifier == 3) {
   1359     if (InquiryData->Peripheral_Type != 0x1f) {
   1360       ScsiDeviceFound = FALSE;
   1361       goto Done;
   1362     }
   1363   }
   1364 
   1365   if (0x1e >= InquiryData->Peripheral_Type && InquiryData->Peripheral_Type >= 0xa) {
   1366     ScsiDeviceFound = FALSE;
   1367     goto Done;
   1368   }
   1369 
   1370   //
   1371   // valid device type and peripheral qualifier combination.
   1372   //
   1373   ScsiIoDevice->ScsiDeviceType  = InquiryData->Peripheral_Type;
   1374   ScsiIoDevice->RemovableDevice = InquiryData->Rmb;
   1375   if (InquiryData->Version == 0) {
   1376     ScsiIoDevice->ScsiVersion = 0;
   1377   } else {
   1378     //
   1379     // ANSI-approved version
   1380     //
   1381     ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData->Version & 0x07);
   1382   }
   1383 
   1384   ScsiDeviceFound = TRUE;
   1385 
   1386 Done:
   1387   FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA));
   1388 
   1389   return ScsiDeviceFound;
   1390 }
   1391 
   1392 
   1393 /**
   1394   Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
   1395 
   1396   @param  Packet         The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
   1397   @param  CommandPacket  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
   1398 
   1399 **/
   1400 EFI_STATUS
   1401 EFIAPI
   1402 ScsiioToPassThruPacket (
   1403   IN      EFI_SCSI_IO_SCSI_REQUEST_PACKET         *Packet,
   1404   OUT     EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *CommandPacket
   1405   )
   1406 {
   1407   //
   1408   //EFI 1.10 doesn't support Bi-Direction Command.
   1409   //
   1410   if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL) {
   1411     return EFI_UNSUPPORTED;
   1412   }
   1413 
   1414   ZeroMem (CommandPacket, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
   1415 
   1416   CommandPacket->Timeout           = Packet->Timeout;
   1417   CommandPacket->Cdb               = Packet->Cdb;
   1418   CommandPacket->CdbLength         = Packet->CdbLength;
   1419   CommandPacket->DataDirection     = Packet->DataDirection;
   1420   CommandPacket->HostAdapterStatus = Packet->HostAdapterStatus;
   1421   CommandPacket->TargetStatus      = Packet->TargetStatus;
   1422   CommandPacket->SenseData         = Packet->SenseData;
   1423   CommandPacket->SenseDataLength   = Packet->SenseDataLength;
   1424 
   1425   if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
   1426     CommandPacket->DataBuffer = Packet->InDataBuffer;
   1427     CommandPacket->TransferLength = Packet->InTransferLength;
   1428   } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
   1429     CommandPacket->DataBuffer = Packet->OutDataBuffer;
   1430     CommandPacket->TransferLength = Packet->OutTransferLength;
   1431   }
   1432   return EFI_SUCCESS;
   1433 }
   1434 
   1435 
   1436 /**
   1437   Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
   1438 
   1439   @param  ScsiPacket  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
   1440   @param  Packet      The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
   1441 
   1442 **/
   1443 EFI_STATUS
   1444 EFIAPI
   1445 PassThruToScsiioPacket (
   1446   IN     EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *ScsiPacket,
   1447   OUT    EFI_SCSI_IO_SCSI_REQUEST_PACKET         *Packet
   1448   )
   1449 {
   1450   Packet->Timeout           = ScsiPacket->Timeout;
   1451   Packet->Cdb               = ScsiPacket->Cdb;
   1452   Packet->CdbLength         = ScsiPacket->CdbLength;
   1453   Packet->DataDirection     = ScsiPacket->DataDirection;
   1454   Packet->HostAdapterStatus = ScsiPacket->HostAdapterStatus;
   1455   Packet->TargetStatus      = ScsiPacket->TargetStatus;
   1456   Packet->SenseData         = ScsiPacket->SenseData;
   1457   Packet->SenseDataLength   = ScsiPacket->SenseDataLength;
   1458 
   1459   if (ScsiPacket->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
   1460     Packet->InDataBuffer = ScsiPacket->DataBuffer;
   1461     Packet->InTransferLength = ScsiPacket->TransferLength;
   1462   } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
   1463     Packet->OutDataBuffer = ScsiPacket->DataBuffer;
   1464     Packet->OutTransferLength = ScsiPacket->TransferLength;
   1465   }
   1466 
   1467   return EFI_SUCCESS;
   1468 }
   1469 
   1470 /**
   1471   Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
   1472   SCSI IO Packet.
   1473 
   1474   @param  Event    The instance of EFI_EVENT.
   1475   @param  Context  The parameter passed in.
   1476 
   1477 **/
   1478 VOID
   1479 EFIAPI
   1480 NotifyFunction (
   1481   IN  EFI_EVENT  Event,
   1482   IN  VOID       *Context
   1483   )
   1484 {
   1485   EFI_SCSI_IO_SCSI_REQUEST_PACKET          *Packet;
   1486   EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *ScsiPacket;
   1487   EFI_EVENT                                CallerEvent;
   1488   SCSI_EVENT_DATA                          *PassData;
   1489 
   1490   PassData = (SCSI_EVENT_DATA*)Context;
   1491   Packet  = (EFI_SCSI_IO_SCSI_REQUEST_PACKET *)PassData->Data1;
   1492   ScsiPacket =  (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer;
   1493 
   1494   //
   1495   // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
   1496   //
   1497   PassThruToScsiioPacket(ScsiPacket, Packet);
   1498 
   1499   //
   1500   // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
   1501   // free mWorkingBuffer.
   1502   //
   1503   gBS->FreePool(mWorkingBuffer);
   1504 
   1505   //
   1506   // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
   1507   //
   1508   CallerEvent = PassData->Data2;
   1509   gBS->CloseEvent(Event);
   1510   gBS->SignalEvent(CallerEvent);
   1511 }
   1512 
   1513