Home | History | Annotate | Download | only in IScsiDxe
      1 /** @file
      2   The entry point of IScsi driver.
      3 
      4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "IScsiImpl.h"
     16 
     17 EFI_DRIVER_BINDING_PROTOCOL gIScsiDriverBinding = {
     18   IScsiDriverBindingSupported,
     19   IScsiDriverBindingStart,
     20   IScsiDriverBindingStop,
     21   0xa,
     22   NULL,
     23   NULL
     24 };
     25 
     26 /**
     27   Tests to see if this driver supports the RemainingDevicePath.
     28 
     29   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
     30                                    parameter is ignored by device drivers, and is optional for bus
     31                                    drivers. For bus drivers, if this parameter is not NULL, then
     32                                    the bus driver must determine if the bus controller specified
     33                                    by ControllerHandle and the child controller specified
     34                                    by RemainingDevicePath are both supported by this
     35                                    bus driver.
     36 
     37   @retval EFI_SUCCESS              The RemainingDevicePath is supported or NULL.
     38   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
     39                                    RemainingDevicePath is not supported by the driver specified by This.
     40 **/
     41 EFI_STATUS
     42 IScsiIsDevicePathSupported (
     43   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
     44   )
     45 {
     46   EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;
     47 
     48   CurrentDevicePath = RemainingDevicePath;
     49   if (CurrentDevicePath != NULL) {
     50     while (!IsDevicePathEnd (CurrentDevicePath)) {
     51       if ((CurrentDevicePath->Type == MESSAGING_DEVICE_PATH) && (CurrentDevicePath->SubType == MSG_ISCSI_DP)) {
     52         return EFI_SUCCESS;
     53       }
     54 
     55       CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
     56     }
     57 
     58     return EFI_UNSUPPORTED;
     59   }
     60 
     61   return EFI_SUCCESS;
     62 }
     63 
     64 /**
     65   Tests to see if this driver supports a given controller. If a child device is provided,
     66   it further tests to see if this driver supports creating a handle for the specified child device.
     67 
     68   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
     69   @param[in]  ControllerHandle     The handle of the controller to test. This handle
     70                                    must support a protocol interface that supplies
     71                                    an I/O abstraction to the driver.
     72   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.
     73                                    This parameter is ignored by device drivers, and is optional for bus drivers.
     74 
     75 
     76   @retval EFI_SUCCESS              The device specified by ControllerHandle and
     77                                    RemainingDevicePath is supported by the driver specified by This.
     78   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
     79                                    RemainingDevicePath is already being managed by the driver
     80                                    specified by This.
     81   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
     82                                    RemainingDevicePath is already being managed by a different
     83                                    driver or an application that requires exclusive acces.
     84                                    Currently not implemented.
     85   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
     86                                    RemainingDevicePath is not supported by the driver specified by This.
     87 **/
     88 EFI_STATUS
     89 EFIAPI
     90 IScsiDriverBindingSupported (
     91   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
     92   IN EFI_HANDLE                   ControllerHandle,
     93   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
     94   )
     95 {
     96   EFI_STATUS                Status;
     97 
     98   Status = gBS->OpenProtocol (
     99                   ControllerHandle,
    100                   &gEfiCallerIdGuid,
    101                   NULL,
    102                   This->DriverBindingHandle,
    103                   ControllerHandle,
    104                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    105                   );
    106   if (!EFI_ERROR (Status)) {
    107     return EFI_ALREADY_STARTED;
    108   }
    109 
    110   Status = gBS->OpenProtocol (
    111                   ControllerHandle,
    112                   &gEfiTcp4ServiceBindingProtocolGuid,
    113                   NULL,
    114                   This->DriverBindingHandle,
    115                   ControllerHandle,
    116                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    117                   );
    118   if (EFI_ERROR (Status)) {
    119     return EFI_UNSUPPORTED;
    120   }
    121 
    122   Status = IScsiIsDevicePathSupported (RemainingDevicePath);
    123   if (EFI_ERROR (Status)) {
    124     return EFI_UNSUPPORTED;
    125   }
    126 
    127   if (IScsiDhcpIsConfigured (ControllerHandle)) {
    128     Status = gBS->OpenProtocol (
    129                     ControllerHandle,
    130                     &gEfiDhcp4ServiceBindingProtocolGuid,
    131                     NULL,
    132                     This->DriverBindingHandle,
    133                     ControllerHandle,
    134                     EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    135                     );
    136     if (EFI_ERROR (Status)) {
    137       return EFI_UNSUPPORTED;
    138     }
    139   }
    140 
    141   return EFI_SUCCESS;
    142 }
    143 
    144 /**
    145   Start this driver on ControllerHandle.
    146 
    147   The Start() function is designed to be invoked from the EFI boot service ConnectController().
    148   As a result, much of the error checking on the parameters to Start() has been moved into this
    149   common boot service. It is legal to call Start() from other locations, but the following calling
    150   restrictions must be followed or the system behavior will not be deterministic.
    151   1. ControllerHandle must be a valid EFI_HANDLE.
    152   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
    153      EFI_DEVICE_PATH_PROTOCOL.
    154   3. Prior to calling Start(), the Supported() function for the driver specified by This must
    155      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
    156 
    157   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    158   @param[in]  ControllerHandle     The handle of the controller to start. This handle
    159                                    must support a protocol interface that supplies
    160                                    an I/O abstraction to the driver.
    161   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.
    162                                    This parameter is ignored by device drivers, and is optional for bus drivers.
    163 
    164   @retval EFI_SUCCESS              The device was started.
    165   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.
    166                                    Currently not implemented.
    167   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
    168   @retval Others                   The driver failded to start the device.
    169 **/
    170 EFI_STATUS
    171 EFIAPI
    172 IScsiDriverBindingStart (
    173   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    174   IN EFI_HANDLE                   ControllerHandle,
    175   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    176   )
    177 {
    178   EFI_STATUS        Status;
    179   ISCSI_DRIVER_DATA *Private;
    180   VOID              *Interface;
    181 
    182   Private = IScsiCreateDriverData (This->DriverBindingHandle, ControllerHandle);
    183   if (Private == NULL) {
    184     return EFI_OUT_OF_RESOURCES;
    185   }
    186 
    187   //
    188   // Create a underlayer child instance, but not need to configure it. Just open ChildHandle
    189   // via BY_DRIVER. That is, establishing the relationship between ControllerHandle and ChildHandle.
    190   // Therefore, when DisconnectController(), especially VLAN virtual controller handle,
    191   // IScsiDriverBindingStop() will be called.
    192   //
    193   Status = NetLibCreateServiceChild (
    194              ControllerHandle,
    195              This->DriverBindingHandle,
    196              &gEfiTcp4ServiceBindingProtocolGuid,
    197              &Private->ChildHandle
    198              );
    199 
    200   if (EFI_ERROR (Status)) {
    201     goto ON_ERROR;
    202   }
    203 
    204   Status = gBS->OpenProtocol (
    205                   Private->ChildHandle,
    206                   &gEfiTcp4ProtocolGuid,
    207                   &Interface,
    208                   This->DriverBindingHandle,
    209                   ControllerHandle,
    210                   EFI_OPEN_PROTOCOL_BY_DRIVER
    211                   );
    212   if (EFI_ERROR (Status)) {
    213     goto ON_ERROR;
    214   }
    215 
    216   //
    217   // Always install private protocol no matter what happens later. We need to
    218   // keep the relationship between ControllerHandle and ChildHandle.
    219   //
    220   Status = gBS->InstallProtocolInterface (
    221                   &ControllerHandle,
    222                   &gEfiCallerIdGuid,
    223                   EFI_NATIVE_INTERFACE,
    224                   &Private->IScsiIdentifier
    225                   );
    226   if (EFI_ERROR (Status)) {
    227     goto ON_ERROR;
    228   }
    229 
    230   //
    231   // Try to add a port configuration page for this controller.
    232   //
    233   IScsiConfigUpdateForm (This->DriverBindingHandle, ControllerHandle, TRUE);
    234 
    235   //
    236   // Get the iSCSI configuration data of this controller.
    237   //
    238   Status = IScsiGetConfigData (Private);
    239   if (EFI_ERROR (Status)) {
    240     goto ON_ERROR;
    241   }
    242   //
    243   // Try to login and create an iSCSI session according to the configuration.
    244   //
    245   Status = IScsiSessionLogin (Private);
    246   if (Status == EFI_MEDIA_CHANGED) {
    247     //
    248     // The specified target is not available and the redirection information is
    249     // got, login the session again with the updated target address.
    250     //
    251     Status = IScsiSessionLogin (Private);
    252   }
    253 
    254   if (EFI_ERROR (Status)) {
    255     goto ON_ERROR;
    256   }
    257   //
    258   // Duplicate the Session's tcp connection device path. The source port field
    259   // will be set to zero as one iSCSI session is comprised of several iSCSI
    260   // connections.
    261   //
    262   Private->DevicePath = IScsiGetTcpConnDevicePath (Private);
    263   if (Private->DevicePath == NULL) {
    264     goto ON_ERROR;
    265   }
    266   //
    267   // Install the updated device path onto the ExtScsiPassThruHandle.
    268   //
    269   Status = gBS->InstallProtocolInterface (
    270                   &Private->ExtScsiPassThruHandle,
    271                   &gEfiDevicePathProtocolGuid,
    272                   EFI_NATIVE_INTERFACE,
    273                   Private->DevicePath
    274                   );
    275   if (EFI_ERROR (Status)) {
    276     goto ON_ERROR;
    277   }
    278 
    279   //
    280   // ISCSI children should share the default Tcp child, just open the default Tcp child via BY_CHILD_CONTROLLER.
    281   //
    282   Status = gBS->OpenProtocol (
    283                   Private->ChildHandle, /// Default Tcp child
    284                   &gEfiTcp4ProtocolGuid,
    285                   &Interface,
    286                   This->DriverBindingHandle,
    287                   Private->ExtScsiPassThruHandle,
    288                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    289                   );
    290   if (EFI_ERROR (Status)) {
    291     gBS->UninstallMultipleProtocolInterfaces (
    292            Private->ExtScsiPassThruHandle,
    293            &gEfiExtScsiPassThruProtocolGuid,
    294            &Private->IScsiExtScsiPassThru,
    295            &gEfiDevicePathProtocolGuid,
    296            Private->DevicePath,
    297            NULL
    298            );
    299 
    300     goto ON_ERROR;
    301   }
    302 
    303   //
    304   // Update/Publish the iSCSI Boot Firmware Table.
    305   //
    306   IScsiPublishIbft ();
    307 
    308   return EFI_SUCCESS;
    309 
    310 ON_ERROR:
    311 
    312   IScsiSessionAbort (&Private->Session);
    313 
    314   return Status;
    315 }
    316 
    317 /**
    318   Stop this driver on ControllerHandle.
    319 
    320   Release the control of this controller and remove the IScsi functions. The Stop()
    321   function is designed to be invoked from the EFI boot service DisconnectController().
    322   As a result, much of the error checking on the parameters to Stop() has been moved
    323   into this common boot service. It is legal to call Stop() from other locations,
    324   but the following calling restrictions must be followed or the system behavior will not be deterministic.
    325   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
    326      same driver's Start() function.
    327   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
    328      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
    329      Start() function, and the Start() function must have called OpenProtocol() on
    330      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
    331 
    332   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    333   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
    334                                 support a bus specific I/O protocol for the driver
    335                                 to use to stop the device.
    336   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.Not used.
    337   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
    338                                 if NumberOfChildren is 0.Not used.
    339 
    340   @retval EFI_SUCCESS           The device was stopped.
    341   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
    342   @retval EFI_INVALID_PARAMETER Child handle is NULL.
    343   @retval EFI_ACCESS_DENIED     The protocol could not be removed from the Handle
    344                                 because its interfaces are being used.
    345 
    346 **/
    347 EFI_STATUS
    348 EFIAPI
    349 IScsiDriverBindingStop (
    350   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    351   IN EFI_HANDLE                   ControllerHandle,
    352   IN UINTN                        NumberOfChildren,
    353   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
    354   )
    355 {
    356   EFI_HANDLE                      IScsiController;
    357   EFI_STATUS                      Status;
    358   ISCSI_PRIVATE_PROTOCOL          *IScsiIdentifier;
    359   ISCSI_DRIVER_DATA               *Private;
    360   EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
    361   ISCSI_CONNECTION                *Conn;
    362 
    363   if (NumberOfChildren != 0) {
    364     //
    365     // We should have only one child.
    366     //
    367     Status = gBS->OpenProtocol (
    368                     ChildHandleBuffer[0],
    369                     &gEfiExtScsiPassThruProtocolGuid,
    370                     (VOID **) &PassThru,
    371                     This->DriverBindingHandle,
    372                     ControllerHandle,
    373                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    374                     );
    375     if (EFI_ERROR (Status)) {
    376       return EFI_DEVICE_ERROR;
    377     }
    378 
    379     Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);
    380     Conn    = NET_LIST_HEAD (&Private->Session.Conns, ISCSI_CONNECTION, Link);
    381 
    382     //
    383     // Previously the TCP4 protocol is opened BY_CHILD_CONTROLLER. Just close
    384     // the protocol here but not uninstall the device path protocol and
    385     // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.
    386     //
    387     gBS->CloseProtocol (
    388            Private->ChildHandle,
    389            &gEfiTcp4ProtocolGuid,
    390            Private->Image,
    391            Private->ExtScsiPassThruHandle
    392            );
    393 
    394     gBS->CloseProtocol (
    395           Conn->Tcp4Io.Handle,
    396           &gEfiTcp4ProtocolGuid,
    397           Private->Image,
    398           Private->ExtScsiPassThruHandle
    399           );
    400 
    401     return EFI_SUCCESS;
    402   }
    403   //
    404   // Get the handle of the controller we are controling.
    405   //
    406   IScsiController = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid);
    407 
    408   Status = gBS->OpenProtocol (
    409                   IScsiController,
    410                   &gEfiCallerIdGuid,
    411                   (VOID **)&IScsiIdentifier,
    412                   This->DriverBindingHandle,
    413                   ControllerHandle,
    414                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    415                   );
    416   if (EFI_ERROR (Status)) {
    417     return EFI_DEVICE_ERROR;
    418   }
    419 
    420   Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);
    421 
    422   if (Private->ChildHandle != NULL) {
    423     Status = gBS->CloseProtocol (
    424                     Private->ChildHandle,
    425                     &gEfiTcp4ProtocolGuid,
    426                     This->DriverBindingHandle,
    427                     IScsiController
    428                     );
    429 
    430     ASSERT (!EFI_ERROR (Status));
    431 
    432     Status = NetLibDestroyServiceChild (
    433                IScsiController,
    434                This->DriverBindingHandle,
    435                &gEfiTcp4ServiceBindingProtocolGuid,
    436                Private->ChildHandle
    437                );
    438     ASSERT (!EFI_ERROR (Status));
    439   }
    440 
    441   IScsiConfigUpdateForm (This->DriverBindingHandle, IScsiController, FALSE);
    442 
    443   //
    444   // Uninstall the private protocol.
    445   //
    446   gBS->UninstallProtocolInterface (
    447         IScsiController,
    448         &gEfiCallerIdGuid,
    449         &Private->IScsiIdentifier
    450         );
    451 
    452   //
    453   // Update the iSCSI Boot Firware Table.
    454   //
    455   IScsiPublishIbft ();
    456 
    457   IScsiSessionAbort (&Private->Session);
    458   Status = IScsiCleanDriverData (Private);
    459   if (EFI_ERROR (Status)) {
    460     return Status;
    461   }
    462 
    463   return EFI_SUCCESS;
    464 }
    465 
    466 /**
    467   Unloads an image(the iSCSI driver).
    468 
    469   @param[in]  ImageHandle       Handle that identifies the image to be unloaded.
    470 
    471   @retval EFI_SUCCESS           The image has been unloaded.
    472   @retval Others                Other errors as indicated.
    473 **/
    474 EFI_STATUS
    475 EFIAPI
    476 EfiIScsiUnload (
    477   IN EFI_HANDLE  ImageHandle
    478   )
    479 {
    480   EFI_STATUS                        Status;
    481   UINTN                             DeviceHandleCount;
    482   EFI_HANDLE                        *DeviceHandleBuffer;
    483   UINTN                             Index;
    484   EFI_COMPONENT_NAME_PROTOCOL       *ComponentName;
    485   EFI_COMPONENT_NAME2_PROTOCOL      *ComponentName2;
    486 
    487   //
    488   // Try to disonnect the driver from the devices it's controlling.
    489   //
    490   Status = gBS->LocateHandleBuffer (
    491                   AllHandles,
    492                   NULL,
    493                   NULL,
    494                   &DeviceHandleCount,
    495                   &DeviceHandleBuffer
    496                   );
    497   if (EFI_ERROR (Status)) {
    498     return Status;
    499   }
    500 
    501   for (Index = 0; Index < DeviceHandleCount; Index++) {
    502     Status = IScsiTestManagedDevice (
    503                DeviceHandleBuffer[Index],
    504                gIScsiDriverBinding.DriverBindingHandle,
    505                &gEfiTcp4ProtocolGuid
    506                );
    507     if (EFI_ERROR (Status)) {
    508       continue;
    509     }
    510     Status = gBS->DisconnectController (
    511                     DeviceHandleBuffer[Index],
    512                     gIScsiDriverBinding.DriverBindingHandle,
    513                     NULL
    514                     );
    515     if (EFI_ERROR (Status)) {
    516       goto ON_EXIT;
    517     }
    518   }
    519 
    520   //
    521   // Unload the iSCSI configuration form.
    522   //
    523   Status = IScsiConfigFormUnload (gIScsiDriverBinding.DriverBindingHandle);
    524   if (EFI_ERROR (Status)) {
    525     goto ON_EXIT;
    526   }
    527 
    528   //
    529   // Uninstall the ComponentName and ComponentName2 protocol from iSCSI4 driver binding handle
    530   // if it has been installed.
    531   //
    532   Status = gBS->HandleProtocol (
    533                   gIScsiDriverBinding.DriverBindingHandle,
    534                   &gEfiComponentNameProtocolGuid,
    535                   (VOID **) &ComponentName
    536                   );
    537   if (!EFI_ERROR (Status)) {
    538     Status = gBS->UninstallMultipleProtocolInterfaces (
    539            gIScsiDriverBinding.DriverBindingHandle,
    540            &gEfiComponentNameProtocolGuid,
    541            ComponentName,
    542            NULL
    543            );
    544     if (EFI_ERROR (Status)) {
    545       goto ON_EXIT;
    546     }
    547   }
    548 
    549   Status = gBS->HandleProtocol (
    550                   gIScsiDriverBinding.DriverBindingHandle,
    551                   &gEfiComponentName2ProtocolGuid,
    552                   (VOID **) &ComponentName2
    553                   );
    554   if (!EFI_ERROR (Status)) {
    555     gBS->UninstallMultipleProtocolInterfaces (
    556            gIScsiDriverBinding.DriverBindingHandle,
    557            &gEfiComponentName2ProtocolGuid,
    558            ComponentName2,
    559            NULL
    560            );
    561     if (EFI_ERROR (Status)) {
    562       goto ON_EXIT;
    563     }
    564   }
    565 
    566   Status = gBS->UninstallMultipleProtocolInterfaces (
    567                   ImageHandle,
    568                   &gEfiDriverBindingProtocolGuid,
    569                   &gIScsiDriverBinding,
    570                   &gEfiIScsiInitiatorNameProtocolGuid,
    571                   &gIScsiInitiatorName,
    572                   NULL
    573                   );
    574 ON_EXIT:
    575 
    576   if (DeviceHandleBuffer != NULL) {
    577     FreePool (DeviceHandleBuffer);
    578   }
    579 
    580   return Status;
    581 }
    582 
    583 /**
    584   This is the declaration of an EFI image entry point. This entry point is
    585   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
    586   both device drivers and bus drivers. It initialize the global variables and
    587   publish the driver binding protocol.
    588 
    589   @param[in]   ImageHandle      The firmware allocated handle for the UEFI image.
    590   @param[in]   SystemTable      A pointer to the EFI System Table.
    591 
    592   @retval EFI_SUCCESS           The operation completed successfully.
    593   @retval EFI_ACCESS_DENIED     EFI_ISCSI_INITIATOR_NAME_PROTOCOL was installed unexpectedly.
    594   @retval Others                Other errors as indicated.
    595 **/
    596 EFI_STATUS
    597 EFIAPI
    598 IScsiDriverEntryPoint (
    599   IN EFI_HANDLE         ImageHandle,
    600   IN EFI_SYSTEM_TABLE   *SystemTable
    601   )
    602 {
    603   EFI_STATUS                         Status;
    604   EFI_ISCSI_INITIATOR_NAME_PROTOCOL  *IScsiInitiatorName;
    605 
    606   //
    607   // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.
    608   //
    609   Status = gBS->LocateProtocol (
    610                    &gEfiIScsiInitiatorNameProtocolGuid,
    611                    NULL,
    612                    (VOID**) &IScsiInitiatorName
    613                    );
    614 
    615   if (!EFI_ERROR (Status)) {
    616     return EFI_ACCESS_DENIED;
    617   }
    618 
    619   //
    620   // Initialize the EFI Driver Library
    621   //
    622   Status = EfiLibInstallDriverBindingComponentName2 (
    623              ImageHandle,
    624              SystemTable,
    625              &gIScsiDriverBinding,
    626              ImageHandle,
    627              &gIScsiComponentName,
    628              &gIScsiComponentName2
    629            );
    630 
    631   if (!EFI_ERROR (Status)) {
    632     //
    633     // Install the iSCSI Initiator Name Protocol.
    634     //
    635     Status = gBS->InstallProtocolInterface (
    636                     &ImageHandle,
    637                     &gEfiIScsiInitiatorNameProtocolGuid,
    638                     EFI_NATIVE_INTERFACE,
    639                     &gIScsiInitiatorName
    640                     );
    641     if (EFI_ERROR (Status)) {
    642       gBS->UninstallMultipleProtocolInterfaces (
    643             ImageHandle,
    644             &gEfiDriverBindingProtocolGuid,
    645             &gIScsiDriverBinding,
    646             &gEfiComponentName2ProtocolGuid,
    647             &gIScsiComponentName2,
    648             &gEfiComponentNameProtocolGuid,
    649             &gIScsiComponentName,
    650             NULL
    651             );
    652       return Status;
    653     }
    654 
    655     //
    656     // Initialize the configuration form of iSCSI.
    657     //
    658     Status = IScsiConfigFormInit ();
    659     if (EFI_ERROR (Status)) {
    660       gBS->UninstallMultipleProtocolInterfaces (
    661             ImageHandle,
    662             &gEfiDriverBindingProtocolGuid,
    663             &gIScsiDriverBinding,
    664             &gEfiComponentName2ProtocolGuid,
    665             &gIScsiComponentName2,
    666             &gEfiComponentNameProtocolGuid,
    667             &gIScsiComponentName,
    668             &gEfiIScsiInitiatorNameProtocolGuid,
    669             &gIScsiInitiatorName,
    670             NULL
    671             );
    672     }
    673   }
    674   return Status;
    675 }
    676 
    677