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 gIScsiIp4DriverBinding = {
     18   IScsiIp4DriverBindingSupported,
     19   IScsiIp4DriverBindingStart,
     20   IScsiIp4DriverBindingStop,
     21   0xa,
     22   NULL,
     23   NULL
     24 };
     25 
     26 EFI_DRIVER_BINDING_PROTOCOL gIScsiIp6DriverBinding = {
     27   IScsiIp6DriverBindingSupported,
     28   IScsiIp6DriverBindingStart,
     29   IScsiIp6DriverBindingStop,
     30   0xa,
     31   NULL,
     32   NULL
     33 };
     34 
     35 EFI_GUID                    gIScsiV4PrivateGuid = ISCSI_V4_PRIVATE_GUID;
     36 EFI_GUID                    gIScsiV6PrivateGuid = ISCSI_V6_PRIVATE_GUID;
     37 ISCSI_PRIVATE_DATA          *mPrivate           = NULL;
     38 
     39 /**
     40   Tests to see if this driver supports the RemainingDevicePath.
     41 
     42   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
     43                                    parameter is ignored by device drivers, and is optional for bus
     44                                    drivers. For bus drivers, if this parameter is not NULL, then
     45                                    the bus driver must determine if the bus controller specified
     46                                    by ControllerHandle and the child controller specified
     47                                    by RemainingDevicePath are both supported by this
     48                                    bus driver.
     49 
     50   @retval EFI_SUCCESS              The RemainingDevicePath is supported or NULL.
     51   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
     52                                    RemainingDevicePath is not supported by the driver specified by This.
     53 **/
     54 EFI_STATUS
     55 IScsiIsDevicePathSupported (
     56   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
     57   )
     58 {
     59   EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;
     60 
     61   CurrentDevicePath = RemainingDevicePath;
     62   if (CurrentDevicePath != NULL) {
     63     while (!IsDevicePathEnd (CurrentDevicePath)) {
     64       if ((CurrentDevicePath->Type == MESSAGING_DEVICE_PATH) && (CurrentDevicePath->SubType == MSG_ISCSI_DP)) {
     65         return EFI_SUCCESS;
     66       }
     67 
     68       CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
     69     }
     70 
     71     return EFI_UNSUPPORTED;
     72   }
     73 
     74   return EFI_SUCCESS;
     75 }
     76 
     77 /**
     78   Check whether an iSCSI HBA adapter already installs an AIP instance with
     79   network boot policy matching the value specified in PcdIScsiAIPNetworkBootPolicy.
     80   If yes, return EFI_SUCCESS.
     81 
     82   @retval EFI_SUCCESS              Found an AIP with matching network boot policy.
     83   @retval EFI_NOT_FOUND            AIP is unavailable or the network boot policy
     84                                    not matched.
     85 **/
     86 EFI_STATUS
     87 IScsiCheckAip (
     88   )
     89 {
     90   UINTN                            AipHandleCount;
     91   EFI_HANDLE                       *AipHandleBuffer;
     92   UINTN                            AipIndex;
     93   EFI_ADAPTER_INFORMATION_PROTOCOL *Aip;
     94   EFI_EXT_SCSI_PASS_THRU_PROTOCOL  *ExtScsiPassThru;
     95   EFI_GUID                         *InfoTypesBuffer;
     96   UINTN                            InfoTypeBufferCount;
     97   UINTN                            TypeIndex;
     98   VOID                             *InfoBlock;
     99   UINTN                            InfoBlockSize;
    100   BOOLEAN                          Supported;
    101   EFI_ADAPTER_INFO_NETWORK_BOOT    *NetworkBoot;
    102   EFI_STATUS                       Status;
    103   UINT8                            NetworkBootPolicy;
    104 
    105   //
    106   // Check any AIP instances exist in system.
    107   //
    108   AipHandleCount  = 0;
    109   AipHandleBuffer = NULL;
    110   Status = gBS->LocateHandleBuffer (
    111                   ByProtocol,
    112                   &gEfiAdapterInformationProtocolGuid,
    113                   NULL,
    114                   &AipHandleCount,
    115                   &AipHandleBuffer
    116                   );
    117   if (EFI_ERROR (Status) || AipHandleCount == 0) {
    118     return EFI_NOT_FOUND;
    119   }
    120 
    121   ASSERT (AipHandleBuffer != NULL);
    122 
    123   InfoBlock = NULL;
    124 
    125   for (AipIndex = 0; AipIndex < AipHandleCount; AipIndex++) {
    126     Status = gBS->HandleProtocol (
    127                     AipHandleBuffer[AipIndex],
    128                     &gEfiAdapterInformationProtocolGuid,
    129                     (VOID *) &Aip
    130                     );
    131     ASSERT_EFI_ERROR (Status);
    132     ASSERT (Aip != NULL);
    133 
    134     Status = gBS->HandleProtocol (
    135                     AipHandleBuffer[AipIndex],
    136                     &gEfiExtScsiPassThruProtocolGuid,
    137                     (VOID *) &ExtScsiPassThru
    138                     );
    139     if (EFI_ERROR (Status) || ExtScsiPassThru == NULL) {
    140       continue;
    141     }
    142 
    143     InfoTypesBuffer     = NULL;
    144     InfoTypeBufferCount = 0;
    145     Status = Aip->GetSupportedTypes (Aip, &InfoTypesBuffer, &InfoTypeBufferCount);
    146     if (EFI_ERROR (Status) || InfoTypesBuffer == NULL) {
    147       continue;
    148     }
    149     //
    150     // Check whether the AIP instance has Network boot information block.
    151     //
    152     Supported = FALSE;
    153     for (TypeIndex = 0; TypeIndex < InfoTypeBufferCount; TypeIndex++) {
    154       if (CompareGuid (&InfoTypesBuffer[TypeIndex], &gEfiAdapterInfoNetworkBootGuid)) {
    155         Supported = TRUE;
    156         break;
    157       }
    158     }
    159 
    160     FreePool (InfoTypesBuffer);
    161     if (!Supported) {
    162       continue;
    163     }
    164 
    165     //
    166     // We now have network boot information block.
    167     //
    168     InfoBlock     = NULL;
    169     InfoBlockSize = 0;
    170     Status = Aip->GetInformation (Aip, &gEfiAdapterInfoNetworkBootGuid, &InfoBlock, &InfoBlockSize);
    171     if (EFI_ERROR (Status) || InfoBlock == NULL) {
    172       continue;
    173     }
    174 
    175     //
    176     // Check whether the network boot policy matches.
    177     //
    178     NetworkBoot = (EFI_ADAPTER_INFO_NETWORK_BOOT *) InfoBlock;
    179     NetworkBootPolicy = PcdGet8 (PcdIScsiAIPNetworkBootPolicy);
    180 
    181     if (NetworkBootPolicy == STOP_UEFI_ISCSI_IF_HBA_INSTALL_AIP) {
    182       Status = EFI_SUCCESS;
    183       goto Exit;
    184     }
    185     if (((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_SUPPORT_IP4) != 0 &&
    186          !NetworkBoot->iScsiIpv4BootCapablity) ||
    187          ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_SUPPORT_IP6) != 0 &&
    188          !NetworkBoot->iScsiIpv6BootCapablity) ||
    189          ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_SUPPORT_OFFLOAD) != 0 &&
    190          !NetworkBoot->OffloadCapability) ||
    191          ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_SUPPORT_MPIO) != 0 &&
    192          !NetworkBoot->iScsiMpioCapability) ||
    193          ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_CONFIGURED_IP4) != 0 &&
    194          !NetworkBoot->iScsiIpv4Boot) ||
    195          ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_CONFIGURED_IP6) != 0 &&
    196          !NetworkBoot->iScsiIpv6Boot)) {
    197       FreePool (InfoBlock);
    198       continue;
    199     }
    200 
    201     Status = EFI_SUCCESS;
    202     goto Exit;
    203   }
    204 
    205   Status = EFI_NOT_FOUND;
    206 
    207 Exit:
    208   if (InfoBlock != NULL) {
    209     FreePool (InfoBlock);
    210   }
    211   if (AipHandleBuffer != NULL) {
    212     FreePool (AipHandleBuffer);
    213   }
    214   return Status;
    215 }
    216 
    217 /**
    218   Tests to see if this driver supports a given controller. This is the worker function for
    219   IScsiIp4(6)DriverBindingSupported.
    220 
    221   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    222   @param[in]  ControllerHandle     The handle of the controller to test. This handle
    223                                    must support a protocol interface that supplies
    224                                    an I/O abstraction to the driver.
    225   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
    226                                    parameter is ignored by device drivers, and is optional for bus
    227                                    drivers. For bus drivers, if this parameter is not NULL, then
    228                                    the bus driver must determine if the bus controller specified
    229                                    by ControllerHandle and the child controller specified
    230                                    by RemainingDevicePath are both supported by this
    231                                    bus driver.
    232   @param[in]  IpVersion            IP_VERSION_4 or IP_VERSION_6.
    233 
    234   @retval EFI_SUCCESS              The device specified by ControllerHandle and
    235                                    RemainingDevicePath is supported by the driver specified by This.
    236   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
    237                                    RemainingDevicePath is already being managed by the driver
    238                                    specified by This.
    239   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
    240                                    RemainingDevicePath is not supported by the driver specified by This.
    241 **/
    242 EFI_STATUS
    243 EFIAPI
    244 IScsiSupported (
    245   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    246   IN EFI_HANDLE                   ControllerHandle,
    247   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL,
    248   IN UINT8                        IpVersion
    249   )
    250 {
    251   EFI_STATUS                Status;
    252   EFI_GUID                  *IScsiServiceBindingGuid;
    253   EFI_GUID                  *TcpServiceBindingGuid;
    254   EFI_GUID                  *DhcpServiceBindingGuid;
    255 
    256   if (IpVersion == IP_VERSION_4) {
    257     IScsiServiceBindingGuid  = &gIScsiV4PrivateGuid;
    258     TcpServiceBindingGuid    = &gEfiTcp4ServiceBindingProtocolGuid;
    259     DhcpServiceBindingGuid   = &gEfiDhcp4ServiceBindingProtocolGuid;
    260   } else {
    261     IScsiServiceBindingGuid  = &gIScsiV6PrivateGuid;
    262     TcpServiceBindingGuid    = &gEfiTcp6ServiceBindingProtocolGuid;
    263     DhcpServiceBindingGuid   = &gEfiDhcp6ServiceBindingProtocolGuid;
    264   }
    265 
    266   Status = gBS->OpenProtocol (
    267                   ControllerHandle,
    268                   IScsiServiceBindingGuid,
    269                   NULL,
    270                   This->DriverBindingHandle,
    271                   ControllerHandle,
    272                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    273                   );
    274   if (!EFI_ERROR (Status)) {
    275     return EFI_ALREADY_STARTED;
    276   }
    277 
    278   Status = gBS->OpenProtocol (
    279                   ControllerHandle,
    280                   TcpServiceBindingGuid,
    281                   NULL,
    282                   This->DriverBindingHandle,
    283                   ControllerHandle,
    284                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    285                   );
    286   if (EFI_ERROR (Status)) {
    287     return EFI_UNSUPPORTED;
    288   }
    289 
    290   Status = IScsiIsDevicePathSupported (RemainingDevicePath);
    291   if (EFI_ERROR (Status)) {
    292     return EFI_UNSUPPORTED;
    293   }
    294 
    295   if (IScsiDhcpIsConfigured (ControllerHandle, IpVersion)) {
    296     Status = gBS->OpenProtocol (
    297                     ControllerHandle,
    298                     DhcpServiceBindingGuid,
    299                     NULL,
    300                     This->DriverBindingHandle,
    301                     ControllerHandle,
    302                     EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    303                     );
    304     if (EFI_ERROR (Status)) {
    305       return EFI_UNSUPPORTED;
    306     }
    307   }
    308 
    309   return EFI_SUCCESS;
    310 }
    311 
    312 
    313 /**
    314   Start to manage the controller. This is the worker function for
    315   IScsiIp4(6)DriverBindingStart.
    316 
    317   @param[in]  Image                Handle of the image.
    318   @param[in]  ControllerHandle     Handle of the controller.
    319   @param[in]  IpVersion            IP_VERSION_4 or IP_VERSION_6.
    320 
    321   @retval EFI_SUCCES            This driver was started.
    322   @retval EFI_ALREADY_STARTED   This driver is already running on this device.
    323   @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
    324   @retval EFI_NOT_FOUND         There is no sufficient information to establish
    325                                 the iScsi session.
    326   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
    327   @retval EFI_DEVICE_ERROR      Failed to get TCP connection device path.
    328   @retval EFI_ACCESS_DENIED     The protocol could not be removed from the Handle
    329                                 because its interfaces are being used.
    330 
    331 **/
    332 EFI_STATUS
    333 IScsiStart (
    334   IN EFI_HANDLE                   Image,
    335   IN EFI_HANDLE                   ControllerHandle,
    336   IN UINT8                        IpVersion
    337   )
    338 {
    339   EFI_STATUS                      Status;
    340   ISCSI_DRIVER_DATA               *Private;
    341   LIST_ENTRY                      *Entry;
    342   LIST_ENTRY                      *NextEntry;
    343   ISCSI_ATTEMPT_CONFIG_NVDATA     *AttemptConfigData;
    344   ISCSI_SESSION                   *Session;
    345   UINT8                           Index;
    346   EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExistIScsiExtScsiPassThru;
    347   ISCSI_DRIVER_DATA               *ExistPrivate;
    348   UINT8                           *AttemptConfigOrder;
    349   UINTN                           AttemptConfigOrderSize;
    350   UINT8                           BootSelected;
    351   EFI_HANDLE                      *HandleBuffer;
    352   UINTN                           NumberOfHandles;
    353   EFI_DEVICE_PATH_PROTOCOL        *DevicePath;
    354   EFI_GUID                        *IScsiPrivateGuid;
    355   EFI_GUID                        *TcpServiceBindingGuid;
    356   CHAR16                          MacString[ISCSI_MAX_MAC_STRING_LEN];
    357   BOOLEAN                         NeedUpdate;
    358   VOID                            *Interface;
    359   EFI_GUID                        *ProtocolGuid;
    360   UINT8                           NetworkBootPolicy;
    361   ISCSI_SESSION_CONFIG_NVDATA     *NvData;
    362 
    363   //
    364   // Test to see if iSCSI driver supports the given controller.
    365   //
    366 
    367   if (IpVersion == IP_VERSION_4) {
    368     IScsiPrivateGuid      = &gIScsiV4PrivateGuid;
    369     TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
    370     ProtocolGuid          = &gEfiTcp4ProtocolGuid;
    371   } else if (IpVersion == IP_VERSION_6) {
    372     IScsiPrivateGuid      = &gIScsiV6PrivateGuid;
    373     TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
    374     ProtocolGuid          = &gEfiTcp6ProtocolGuid;
    375   } else {
    376     return EFI_INVALID_PARAMETER;
    377   }
    378 
    379   Status = gBS->OpenProtocol (
    380                   ControllerHandle,
    381                   IScsiPrivateGuid,
    382                   NULL,
    383                   Image,
    384                   ControllerHandle,
    385                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    386                   );
    387   if (!EFI_ERROR (Status)) {
    388     return EFI_ALREADY_STARTED;
    389   }
    390 
    391   Status = gBS->OpenProtocol (
    392                   ControllerHandle,
    393                   TcpServiceBindingGuid,
    394                   NULL,
    395                   Image,
    396                   ControllerHandle,
    397                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    398                   );
    399   if (EFI_ERROR (Status)) {
    400     return EFI_UNSUPPORTED;
    401   }
    402 
    403   NetworkBootPolicy = PcdGet8 (PcdIScsiAIPNetworkBootPolicy);
    404   if (NetworkBootPolicy != ALWAYS_USE_UEFI_ISCSI_AND_IGNORE_AIP) {
    405     //
    406     // Check existing iSCSI AIP.
    407     //
    408     Status = IScsiCheckAip ();
    409     if (!EFI_ERROR (Status)) {
    410       //
    411       // Find iSCSI AIP with specified network boot policy. return EFI_ABORTED.
    412       //
    413       return EFI_ABORTED;
    414     }
    415   }
    416 
    417   //
    418   // Record the incoming NIC info.
    419   //
    420   Status = IScsiAddNic (ControllerHandle);
    421   if (EFI_ERROR (Status)) {
    422     return Status;
    423   }
    424 
    425   //
    426   // Create the instance private data.
    427   //
    428   Private = IScsiCreateDriverData (Image, ControllerHandle);
    429   if (Private == NULL) {
    430     return EFI_OUT_OF_RESOURCES;
    431   }
    432 
    433   //
    434   // Create a underlayer child instance, but not need to configure it. Just open ChildHandle
    435   // via BY_DRIVER. That is, establishing the relationship between ControllerHandle and ChildHandle.
    436   // Therefore, when DisconnectController(), especially VLAN virtual controller handle,
    437   // IScsiDriverBindingStop() will be called.
    438   //
    439   Status = NetLibCreateServiceChild (
    440              ControllerHandle,
    441              Image,
    442              TcpServiceBindingGuid,
    443              &Private->ChildHandle
    444              );
    445 
    446   if (EFI_ERROR (Status)) {
    447     goto ON_ERROR;
    448   }
    449 
    450   Status = gBS->OpenProtocol (
    451                   Private->ChildHandle, /// Default Tcp child
    452                   ProtocolGuid,
    453                   &Interface,
    454                   Image,
    455                   ControllerHandle,
    456                   EFI_OPEN_PROTOCOL_BY_DRIVER
    457                   );
    458 
    459   if (EFI_ERROR (Status)) {
    460     goto ON_ERROR;
    461   }
    462 
    463   //
    464   // Always install private protocol no matter what happens later. We need to
    465   // keep the relationship between ControllerHandle and ChildHandle.
    466   //
    467   Status = gBS->InstallProtocolInterface (
    468                   &ControllerHandle,
    469                   IScsiPrivateGuid,
    470                   EFI_NATIVE_INTERFACE,
    471                   &Private->IScsiIdentifier
    472                   );
    473   if (EFI_ERROR (Status)) {
    474     goto ON_ERROR;
    475   }
    476 
    477   if (IpVersion == IP_VERSION_4) {
    478     mPrivate->Ipv6Flag = FALSE;
    479   } else {
    480     mPrivate->Ipv6Flag = TRUE;
    481   }
    482 
    483   //
    484   // Get the current iSCSI configuration data.
    485   //
    486   Status = IScsiGetConfigData (Private);
    487   if (EFI_ERROR (Status)) {
    488     goto ON_ERROR;
    489   }
    490 
    491   //
    492   // If there is already a successul attempt, check whether this attempt is the
    493   // first "enabled for MPIO" attempt. If not, still try the first attempt.
    494   // In single path mode, try all attempts.
    495   //
    496   ExistPrivate = NULL;
    497   Status       = EFI_NOT_FOUND;
    498 
    499   if (mPrivate->OneSessionEstablished && mPrivate->EnableMpio) {
    500     AttemptConfigData = NULL;
    501     NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
    502      AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
    503       if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
    504         break;
    505       }
    506     }
    507 
    508     if (AttemptConfigData == NULL) {
    509       goto ON_ERROR;
    510     }
    511 
    512     if (AttemptConfigData->AttemptConfigIndex == mPrivate->BootSelectedIndex) {
    513       goto ON_EXIT;
    514     }
    515 
    516     //
    517     // Uninstall the original ExtScsiPassThru first.
    518     //
    519 
    520     //
    521     // Locate all ExtScsiPassThru protocol instances.
    522     //
    523     Status = gBS->LocateHandleBuffer (
    524                     ByProtocol,
    525                     &gEfiExtScsiPassThruProtocolGuid,
    526                     NULL,
    527                     &NumberOfHandles,
    528                     &HandleBuffer
    529                     );
    530     if (EFI_ERROR (Status)) {
    531       goto ON_ERROR;
    532     }
    533 
    534     //
    535     // Find ExtScsiPassThru protocol instance produced by this driver.
    536     //
    537     ExistIScsiExtScsiPassThru = NULL;
    538     for (Index = 0; Index < NumberOfHandles && ExistIScsiExtScsiPassThru == NULL; Index++) {
    539       Status = gBS->HandleProtocol (
    540                       HandleBuffer[Index],
    541                       &gEfiDevicePathProtocolGuid,
    542                       (VOID **) &DevicePath
    543                       );
    544       if (EFI_ERROR (Status)) {
    545         continue;
    546       }
    547 
    548       while (!IsDevicePathEnd (DevicePath)) {
    549         if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_MAC_ADDR_DP)) {
    550           //
    551           // Get the ExtScsiPassThru protocol instance.
    552           //
    553           Status = gBS->HandleProtocol (
    554                           HandleBuffer[Index],
    555                           &gEfiExtScsiPassThruProtocolGuid,
    556                           (VOID **) &ExistIScsiExtScsiPassThru
    557                           );
    558           ASSERT_EFI_ERROR (Status);
    559           break;
    560         }
    561 
    562         DevicePath = NextDevicePathNode (DevicePath);
    563       }
    564     }
    565 
    566     FreePool (HandleBuffer);
    567 
    568     if (ExistIScsiExtScsiPassThru == NULL) {
    569       Status = EFI_NOT_FOUND;
    570       goto ON_ERROR;
    571     }
    572 
    573     ExistPrivate = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (ExistIScsiExtScsiPassThru);
    574 
    575     Status = gBS->UninstallProtocolInterface (
    576                     ExistPrivate->ExtScsiPassThruHandle,
    577                     &gEfiExtScsiPassThruProtocolGuid,
    578                     &ExistPrivate->IScsiExtScsiPassThru
    579                     );
    580     if (EFI_ERROR (Status)) {
    581       goto ON_ERROR;
    582     }
    583   }
    584 
    585   //
    586   // Install the Ext SCSI PASS THRU protocol.
    587   //
    588   Status = gBS->InstallProtocolInterface (
    589                   &Private->ExtScsiPassThruHandle,
    590                   &gEfiExtScsiPassThruProtocolGuid,
    591                   EFI_NATIVE_INTERFACE,
    592                   &Private->IScsiExtScsiPassThru
    593                   );
    594   if (EFI_ERROR (Status)) {
    595     goto ON_ERROR;
    596   }
    597 
    598   BootSelected = 0;
    599 
    600   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {
    601     AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
    602     //
    603     // Don't process the attempt that does not associate with the current NIC or
    604     // this attempt is disabled or established.
    605     //
    606     if (AttemptConfigData->NicIndex != mPrivate->CurrentNic ||
    607         AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED ||
    608         AttemptConfigData->ValidPath) {
    609       continue;
    610     }
    611 
    612     //
    613     // In multipath mode, don't process attempts configured for single path.
    614     // In default single path mode, don't process attempts configured for multipath.
    615     //
    616     if ((mPrivate->EnableMpio &&
    617          AttemptConfigData->SessionConfigData.Enabled != ISCSI_ENABLED_FOR_MPIO) ||
    618         (!mPrivate->EnableMpio &&
    619          AttemptConfigData->SessionConfigData.Enabled != ISCSI_ENABLED)) {
    620       continue;
    621     }
    622 
    623     //
    624     // Don't process the attempt that fails to get the init/target information from DHCP.
    625     //
    626     if (AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp &&
    627         !AttemptConfigData->DhcpSuccess) {
    628       if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {
    629         mPrivate->ValidSinglePathCount--;
    630       }
    631       continue;
    632     }
    633 
    634     //
    635     // Don't process the autoconfigure path if it is already established.
    636     //
    637     if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
    638         AttemptConfigData->AutoConfigureSuccess) {
    639       continue;
    640     }
    641 
    642     //
    643     // Don't process the attempt if its IP mode is not in the current IP version.
    644     //
    645     if (!mPrivate->Ipv6Flag) {
    646       if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {
    647         continue;
    648       }
    649       if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
    650           AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {
    651         continue;
    652       }
    653     } else {
    654       if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {
    655         continue;
    656       }
    657       if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
    658           AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {
    659         continue;
    660       }
    661     }
    662 
    663     //
    664     // Fill in the Session and init it.
    665     //
    666     Session = (ISCSI_SESSION *) AllocateZeroPool (sizeof (ISCSI_SESSION));
    667     if (Session == NULL) {
    668       Status = EFI_OUT_OF_RESOURCES;
    669       goto ON_ERROR;
    670     }
    671 
    672     Session->Private    = Private;
    673     Session->ConfigData = AttemptConfigData;
    674     Session->AuthType   = AttemptConfigData->AuthenticationType;
    675 
    676     AsciiStrToUnicodeStrS (AttemptConfigData->MacString, MacString, ARRAY_SIZE (MacString));
    677     UnicodeSPrint (
    678       mPrivate->PortString,
    679       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
    680       L"%s%d",
    681       MacString,
    682       (UINTN) AttemptConfigData->AttemptConfigIndex
    683       );
    684 
    685     if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {
    686       Session->AuthData.CHAP.AuthConfig = &AttemptConfigData->AuthConfigData.CHAP;
    687     }
    688 
    689     IScsiSessionInit (Session, FALSE);
    690 
    691     //
    692     // Try to login and create an iSCSI session according to the configuration.
    693     //
    694     Status = IScsiSessionLogin (Session);
    695     if (Status == EFI_MEDIA_CHANGED) {
    696       //
    697       // The specified target is not available, and the redirection information is
    698       // received. Login the session again with the updated target address.
    699       //
    700       Status = IScsiSessionLogin (Session);
    701     } else if (Status == EFI_NOT_READY) {
    702       Status = IScsiSessionReLogin (Session);
    703     }
    704 
    705     //
    706     // Restore the origial user setting which specifies the proxy/virtual iSCSI target to NV region.
    707     //
    708     NvData = &AttemptConfigData->SessionConfigData;
    709     if (NvData->RedirectFlag) {
    710       NvData->TargetPort = NvData->OriginalTargetPort;
    711       CopyMem (&NvData->TargetIp, &NvData->OriginalTargetIp, sizeof (EFI_IP_ADDRESS));
    712       NvData->RedirectFlag = FALSE;
    713 
    714       gRT->SetVariable (
    715              mPrivate->PortString,
    716              &gEfiIScsiInitiatorNameProtocolGuid,
    717              ISCSI_CONFIG_VAR_ATTR,
    718              sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
    719              AttemptConfigData
    720              );
    721     }
    722 
    723     if (EFI_ERROR (Status)) {
    724       //
    725       // In Single path mode, only the successful attempt will be recorded in iBFT;
    726       // in multi-path mode, all the attempt entries in MPIO will be recorded in iBFT.
    727       //
    728       if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {
    729         mPrivate->ValidSinglePathCount--;
    730       }
    731 
    732       FreePool (Session);
    733 
    734     } else {
    735       AttemptConfigData->ValidPath = TRUE;
    736 
    737       //
    738       // Do not record the attempt in iBFT if it login with KRB5.
    739       // TODO: record KRB5 attempt information in the iSCSI device path.
    740       //
    741       if (Session->AuthType == ISCSI_AUTH_TYPE_KRB) {
    742         if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {
    743           mPrivate->ValidSinglePathCount--;
    744         }
    745 
    746         AttemptConfigData->ValidiBFTPath = FALSE;
    747       } else {
    748         AttemptConfigData->ValidiBFTPath = TRUE;
    749       }
    750 
    751       //
    752       // IScsi session success. Update the attempt state to NVR.
    753       //
    754       if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
    755         AttemptConfigData->AutoConfigureSuccess = TRUE;
    756       }
    757 
    758       gRT->SetVariable (
    759              mPrivate->PortString,
    760              &gEfiIScsiInitiatorNameProtocolGuid,
    761              ISCSI_CONFIG_VAR_ATTR,
    762              sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
    763              AttemptConfigData
    764              );
    765 
    766       //
    767       // Select the first login session. Abort others.
    768       //
    769       if (Private->Session == NULL) {
    770         Private->Session = Session;
    771         BootSelected     = AttemptConfigData->AttemptConfigIndex;
    772         //
    773         // Don't validate other attempt in multipath mode if one is success.
    774         //
    775         if (mPrivate->EnableMpio) {
    776           break;
    777         }
    778       } else {
    779         IScsiSessionAbort (Session);
    780         FreePool (Session);
    781       }
    782     }
    783   }
    784 
    785   //
    786   // All attempts configured for this driver instance are not valid.
    787   //
    788   if (Private->Session == NULL) {
    789     Status = gBS->UninstallProtocolInterface (
    790                     Private->ExtScsiPassThruHandle,
    791                     &gEfiExtScsiPassThruProtocolGuid,
    792                     &Private->IScsiExtScsiPassThru
    793                     );
    794     ASSERT_EFI_ERROR (Status);
    795     Private->ExtScsiPassThruHandle = NULL;
    796 
    797     //
    798     // Reinstall the original ExtScsiPassThru back.
    799     //
    800     if (mPrivate->OneSessionEstablished && ExistPrivate != NULL) {
    801       Status = gBS->InstallProtocolInterface (
    802                       &ExistPrivate->ExtScsiPassThruHandle,
    803                       &gEfiExtScsiPassThruProtocolGuid,
    804                       EFI_NATIVE_INTERFACE,
    805                       &ExistPrivate->IScsiExtScsiPassThru
    806                       );
    807       if (EFI_ERROR (Status)) {
    808         goto ON_ERROR;
    809       }
    810 
    811       goto ON_EXIT;
    812     }
    813 
    814     Status = EFI_NOT_FOUND;
    815 
    816     goto ON_ERROR;
    817   }
    818 
    819   NeedUpdate = TRUE;
    820   //
    821   // More than one attempt successes.
    822   //
    823   if (Private->Session != NULL && mPrivate->OneSessionEstablished) {
    824 
    825     AttemptConfigOrder = IScsiGetVariableAndSize (
    826                            L"AttemptOrder",
    827                            &gIScsiConfigGuid,
    828                            &AttemptConfigOrderSize
    829                            );
    830     if (AttemptConfigOrder == NULL) {
    831       goto ON_ERROR;
    832     }
    833     for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
    834       if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex ||
    835           AttemptConfigOrder[Index] == BootSelected) {
    836         break;
    837       }
    838     }
    839 
    840     if (mPrivate->EnableMpio) {
    841       //
    842       // Use the attempt in earlier order. Abort the later one in MPIO.
    843       //
    844       if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {
    845         IScsiSessionAbort (Private->Session);
    846         FreePool (Private->Session);
    847         Private->Session = NULL;
    848         gBS->UninstallProtocolInterface (
    849                Private->ExtScsiPassThruHandle,
    850                &gEfiExtScsiPassThruProtocolGuid,
    851                &Private->IScsiExtScsiPassThru
    852                );
    853         Private->ExtScsiPassThruHandle = NULL;
    854 
    855         //
    856         // Reinstall the original ExtScsiPassThru back.
    857         //
    858         Status = gBS->InstallProtocolInterface (
    859                         &ExistPrivate->ExtScsiPassThruHandle,
    860                         &gEfiExtScsiPassThruProtocolGuid,
    861                         EFI_NATIVE_INTERFACE,
    862                         &ExistPrivate->IScsiExtScsiPassThru
    863                         );
    864         if (EFI_ERROR (Status)) {
    865           goto ON_ERROR;
    866         }
    867 
    868         goto ON_EXIT;
    869       } else {
    870         if (AttemptConfigOrder[Index] != BootSelected) {
    871           goto ON_ERROR;
    872         }
    873         mPrivate->BootSelectedIndex = BootSelected;
    874         //
    875         // Clear the resource in ExistPrivate.
    876         //
    877         gBS->UninstallProtocolInterface (
    878                ExistPrivate->Controller,
    879                IScsiPrivateGuid,
    880                &ExistPrivate->IScsiIdentifier
    881                );
    882 
    883         IScsiRemoveNic (ExistPrivate->Controller);
    884         if (ExistPrivate->Session != NULL) {
    885           IScsiSessionAbort (ExistPrivate->Session);
    886         }
    887 
    888         if (ExistPrivate->DevicePath != NULL) {
    889           Status = gBS->UninstallProtocolInterface (
    890                           ExistPrivate->ExtScsiPassThruHandle,
    891                           &gEfiDevicePathProtocolGuid,
    892                           ExistPrivate->DevicePath
    893                           );
    894           if (EFI_ERROR (Status)) {
    895             goto ON_ERROR;
    896           }
    897 
    898           FreePool (ExistPrivate->DevicePath);
    899         }
    900 
    901         gBS->CloseEvent (ExistPrivate->ExitBootServiceEvent);
    902         FreePool (ExistPrivate);
    903 
    904       }
    905     } else {
    906       //
    907       // Use the attempt in earlier order as boot selected in single path mode.
    908       //
    909       if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {
    910         NeedUpdate = FALSE;
    911       }
    912     }
    913 
    914   }
    915 
    916   if (NeedUpdate) {
    917     mPrivate->OneSessionEstablished = TRUE;
    918     mPrivate->BootSelectedIndex     = BootSelected;
    919   }
    920 
    921   //
    922   // Duplicate the Session's tcp connection device path. The source port field
    923   // will be set to zero as one iSCSI session is comprised of several iSCSI
    924   // connections.
    925   //
    926   Private->DevicePath = IScsiGetTcpConnDevicePath (Private->Session);
    927   if (Private->DevicePath == NULL) {
    928     Status = EFI_DEVICE_ERROR;
    929     goto ON_ERROR;
    930   }
    931   //
    932   // Install the updated device path onto the ExtScsiPassThruHandle.
    933   //
    934   Status = gBS->InstallProtocolInterface (
    935                   &Private->ExtScsiPassThruHandle,
    936                   &gEfiDevicePathProtocolGuid,
    937                   EFI_NATIVE_INTERFACE,
    938                   Private->DevicePath
    939                   );
    940   if (EFI_ERROR (Status)) {
    941     goto ON_ERROR;
    942   }
    943 
    944   //
    945   // ISCSI children should share the default Tcp child, just open the default Tcp child via BY_CHILD_CONTROLLER.
    946   //
    947   Status = gBS->OpenProtocol (
    948                   Private->ChildHandle, /// Default Tcp child
    949                   ProtocolGuid,
    950                   &Interface,
    951                   Image,
    952                   Private->ExtScsiPassThruHandle,
    953                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    954                   );
    955   if (EFI_ERROR (Status)) {
    956     gBS->UninstallMultipleProtocolInterfaces (
    957            Private->ExtScsiPassThruHandle,
    958            &gEfiExtScsiPassThruProtocolGuid,
    959            &Private->IScsiExtScsiPassThru,
    960            &gEfiDevicePathProtocolGuid,
    961            Private->DevicePath,
    962            NULL
    963            );
    964 
    965     goto ON_ERROR;
    966   }
    967 
    968 ON_EXIT:
    969 
    970   //
    971   // Update/Publish the iSCSI Boot Firmware Table.
    972   //
    973   if (mPrivate->BootSelectedIndex != 0) {
    974     IScsiPublishIbft ();
    975   }
    976 
    977   return EFI_SUCCESS;
    978 
    979 ON_ERROR:
    980 
    981   if (Private->Session != NULL) {
    982     IScsiSessionAbort (Private->Session);
    983   }
    984 
    985   return Status;
    986 }
    987 
    988 /**
    989   Stops a device controller or a bus controller. This is the worker function for
    990   IScsiIp4(6)DriverBindingStop.
    991 
    992   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    993   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
    994                                 support a bus specific I/O protocol for the driver
    995                                 to use to stop the device.
    996   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
    997   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
    998                                 if NumberOfChildren is 0.
    999   @param[in]  IpVersion         IP_VERSION_4 or IP_VERSION_6.
   1000 
   1001   @retval EFI_SUCCESS           The device was stopped.
   1002   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
   1003   @retval EFI_INVALID_PARAMETER Child handle is NULL.
   1004   @retval EFI_ACCESS_DENIED     The protocol could not be removed from the Handle
   1005                                 because its interfaces are being used.
   1006 
   1007 **/
   1008 EFI_STATUS
   1009 EFIAPI
   1010 IScsiStop (
   1011   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
   1012   IN EFI_HANDLE                   ControllerHandle,
   1013   IN UINTN                        NumberOfChildren,
   1014   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL,
   1015   IN UINT8                        IpVersion
   1016   )
   1017 {
   1018   EFI_HANDLE                      IScsiController;
   1019   EFI_STATUS                      Status;
   1020   ISCSI_PRIVATE_PROTOCOL          *IScsiIdentifier;
   1021   ISCSI_DRIVER_DATA               *Private;
   1022   EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
   1023   ISCSI_CONNECTION                *Conn;
   1024   EFI_GUID                        *ProtocolGuid;
   1025   EFI_GUID                        *TcpServiceBindingGuid;
   1026   EFI_GUID                        *TcpProtocolGuid;
   1027 
   1028 
   1029   if (NumberOfChildren != 0) {
   1030     //
   1031     // We should have only one child.
   1032     //
   1033     Status = gBS->OpenProtocol (
   1034                     ChildHandleBuffer[0],
   1035                     &gEfiExtScsiPassThruProtocolGuid,
   1036                     (VOID **) &PassThru,
   1037                     This->DriverBindingHandle,
   1038                     ControllerHandle,
   1039                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1040                     );
   1041     if (EFI_ERROR (Status)) {
   1042       return EFI_DEVICE_ERROR;
   1043     }
   1044 
   1045     Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);
   1046     Conn    = NET_LIST_HEAD (&Private->Session->Conns, ISCSI_CONNECTION, Link);
   1047 
   1048     //
   1049     // Previously the TCP protocol is opened BY_CHILD_CONTROLLER. Just close
   1050     // the protocol here, but do not uninstall the device path protocol and
   1051     // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.
   1052     //
   1053     if (IpVersion == IP_VERSION_4) {
   1054       ProtocolGuid = &gEfiTcp4ProtocolGuid;
   1055     } else {
   1056       ProtocolGuid = &gEfiTcp6ProtocolGuid;
   1057     }
   1058 
   1059     gBS->CloseProtocol (
   1060            Private->ChildHandle,
   1061            ProtocolGuid,
   1062            Private->Image,
   1063            Private->ExtScsiPassThruHandle
   1064            );
   1065 
   1066     gBS->CloseProtocol (
   1067            Conn->TcpIo.Handle,
   1068            ProtocolGuid,
   1069            Private->Image,
   1070            Private->ExtScsiPassThruHandle
   1071            );
   1072 
   1073     return EFI_SUCCESS;
   1074   }
   1075 
   1076   //
   1077   // Get the handle of the controller we are controling.
   1078   //
   1079   if (IpVersion == IP_VERSION_4) {
   1080     ProtocolGuid            = &gIScsiV4PrivateGuid;
   1081     TcpProtocolGuid         = &gEfiTcp4ProtocolGuid;
   1082     TcpServiceBindingGuid   = &gEfiTcp4ServiceBindingProtocolGuid;
   1083   } else {
   1084     ProtocolGuid            = &gIScsiV6PrivateGuid;
   1085     TcpProtocolGuid         = &gEfiTcp6ProtocolGuid;
   1086     TcpServiceBindingGuid   = &gEfiTcp6ServiceBindingProtocolGuid;
   1087   }
   1088   IScsiController = NetLibGetNicHandle (ControllerHandle, TcpProtocolGuid);
   1089   if (IScsiController == NULL) {
   1090     return EFI_SUCCESS;
   1091   }
   1092 
   1093   Status = gBS->OpenProtocol (
   1094                   IScsiController,
   1095                   ProtocolGuid,
   1096                   (VOID **) &IScsiIdentifier,
   1097                   This->DriverBindingHandle,
   1098                   ControllerHandle,
   1099                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1100                   );
   1101   if (EFI_ERROR (Status)) {
   1102     return EFI_DEVICE_ERROR;
   1103   }
   1104 
   1105   Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);
   1106   ASSERT (Private != NULL);
   1107 
   1108   if (Private->ChildHandle != NULL) {
   1109     Status = gBS->CloseProtocol (
   1110                     Private->ChildHandle,
   1111                     TcpProtocolGuid,
   1112                     This->DriverBindingHandle,
   1113                     IScsiController
   1114                     );
   1115 
   1116     ASSERT (!EFI_ERROR (Status));
   1117 
   1118     Status = NetLibDestroyServiceChild (
   1119                IScsiController,
   1120                This->DriverBindingHandle,
   1121                TcpServiceBindingGuid,
   1122                Private->ChildHandle
   1123                );
   1124 
   1125     ASSERT (!EFI_ERROR (Status));
   1126   }
   1127 
   1128   gBS->UninstallProtocolInterface (
   1129          IScsiController,
   1130          ProtocolGuid,
   1131          &Private->IScsiIdentifier
   1132          );
   1133 
   1134   //
   1135   // Remove this NIC.
   1136   //
   1137   IScsiRemoveNic (IScsiController);
   1138 
   1139   //
   1140   // Update the iSCSI Boot Firware Table.
   1141   //
   1142   IScsiPublishIbft ();
   1143 
   1144   if (Private->Session != NULL) {
   1145     IScsiSessionAbort (Private->Session);
   1146   }
   1147 
   1148   Status = IScsiCleanDriverData (Private);
   1149 
   1150   if (EFI_ERROR (Status)) {
   1151     return Status;
   1152   }
   1153 
   1154   return EFI_SUCCESS;
   1155 }
   1156 
   1157 /**
   1158   Tests to see if this driver supports a given controller. If a child device is provided,
   1159   it tests to see if this driver supports creating a handle for the specified child device.
   1160 
   1161   This function checks to see if the driver specified by This supports the device specified by
   1162   ControllerHandle. Drivers typically use the device path attached to
   1163   ControllerHandle and/or the services from the bus I/O abstraction attached to
   1164   ControllerHandle to determine if the driver supports ControllerHandle. This function
   1165   may be called many times during platform initialization. In order to reduce boot times, the tests
   1166   performed by this function must be very small and take as little time as possible to execute. This
   1167   function must not change the state of any hardware devices, and this function must be aware that the
   1168   device specified by ControllerHandle may already be managed by the same driver or a
   1169   different driver. This function must match its calls to AllocatePages() with FreePages(),
   1170   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
   1171   Since ControllerHandle may have been previously started by the same driver, if a protocol is
   1172   already in the opened state, then it must not be closed with CloseProtocol(). This is required
   1173   to guarantee the state of ControllerHandle is not modified by this function.
   1174 
   1175   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
   1176   @param[in]  ControllerHandle     The handle of the controller to test. This handle
   1177                                    must support a protocol interface that supplies
   1178                                    an I/O abstraction to the driver.
   1179   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
   1180                                    parameter is ignored by device drivers, and is optional for bus
   1181                                    drivers. For bus drivers, if this parameter is not NULL, then
   1182                                    the bus driver must determine if the bus controller specified
   1183                                    by ControllerHandle and the child controller specified
   1184                                    by RemainingDevicePath are both supported by this
   1185                                    bus driver.
   1186 
   1187   @retval EFI_SUCCESS              The device specified by ControllerHandle and
   1188                                    RemainingDevicePath is supported by the driver specified by This.
   1189   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
   1190                                    RemainingDevicePath is already managed by the driver
   1191                                    specified by This.
   1192   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
   1193                                    RemainingDevicePath is already managed by a different
   1194                                    driver or an application that requires exclusive access.
   1195                                    Currently not implemented.
   1196   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
   1197                                    RemainingDevicePath is not supported by the driver specified by This.
   1198 **/
   1199 EFI_STATUS
   1200 EFIAPI
   1201 IScsiIp4DriverBindingSupported (
   1202   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
   1203   IN EFI_HANDLE                   ControllerHandle,
   1204   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
   1205   )
   1206 {
   1207   return IScsiSupported (
   1208            This,
   1209            ControllerHandle,
   1210            RemainingDevicePath,
   1211            IP_VERSION_4
   1212            );
   1213 }
   1214 
   1215 /**
   1216   Starts a device controller or a bus controller.
   1217 
   1218   The Start() function is designed to be invoked from the EFI boot service ConnectController().
   1219   As a result, much of the error checking on the parameters to Start() has been moved into this
   1220   common boot service. It is legal to call Start() from other locations,
   1221   but the following calling restrictions must be followed or the system behavior will not be deterministic.
   1222   1. ControllerHandle must be a valid EFI_HANDLE.
   1223   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
   1224      EFI_DEVICE_PATH_PROTOCOL.
   1225   3. Prior to calling Start(), the Supported() function for the driver specified by This must
   1226      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
   1227 
   1228   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
   1229   @param[in]  ControllerHandle     The handle of the controller to start. This handle
   1230                                    must support a protocol interface that supplies
   1231                                    an I/O abstraction to the driver.
   1232   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
   1233                                    parameter is ignored by device drivers, and is optional for bus
   1234                                    drivers. For a bus driver, if this parameter is NULL, then handles
   1235                                    for all the children of Controller are created by this driver.
   1236                                    If this parameter is not NULL and the first Device Path Node is
   1237                                    not the End of Device Path Node, then only the handle for the
   1238                                    child device specified by the first Device Path Node of
   1239                                    RemainingDevicePath is created by this driver.
   1240                                    If the first Device Path Node of RemainingDevicePath is
   1241                                    the End of Device Path Node, no child handle is created by this
   1242                                    driver.
   1243 
   1244   @retval EFI_SUCCESS              The device was started.
   1245   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error. Currently not implemented.
   1246   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
   1247   @retval Others                   The driver failed to start the device.
   1248 
   1249 **/
   1250 EFI_STATUS
   1251 EFIAPI
   1252 IScsiIp4DriverBindingStart (
   1253   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
   1254   IN EFI_HANDLE                   ControllerHandle,
   1255   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
   1256   )
   1257 {
   1258   EFI_STATUS        Status;
   1259 
   1260   Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_4);
   1261   if (Status == EFI_ALREADY_STARTED) {
   1262     Status = EFI_SUCCESS;
   1263   }
   1264 
   1265   return Status;
   1266 }
   1267 
   1268 /**
   1269   Stops a device controller or a bus controller.
   1270 
   1271   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
   1272   As a result, much of the error checking on the parameters to Stop() has been moved
   1273   into this common boot service. It is legal to call Stop() from other locations,
   1274   but the following calling restrictions must be followed or the system behavior will not be deterministic.
   1275   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
   1276      same driver's Start() function.
   1277   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
   1278      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
   1279      Start() function, and the Start() function must have called OpenProtocol() on
   1280      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
   1281 
   1282   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
   1283   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
   1284                                 support a bus specific I/O protocol for the driver
   1285                                 to use to stop the device.
   1286   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
   1287   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
   1288                                 if NumberOfChildren is 0.
   1289 
   1290   @retval EFI_SUCCESS           The device was stopped.
   1291   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
   1292 
   1293 **/
   1294 EFI_STATUS
   1295 EFIAPI
   1296 IScsiIp4DriverBindingStop (
   1297   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
   1298   IN EFI_HANDLE                   ControllerHandle,
   1299   IN UINTN                        NumberOfChildren,
   1300   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
   1301   )
   1302 {
   1303   return IScsiStop (
   1304            This,
   1305            ControllerHandle,
   1306            NumberOfChildren,
   1307            ChildHandleBuffer,
   1308            IP_VERSION_4
   1309            );
   1310 }
   1311 
   1312 /**
   1313   Tests to see if this driver supports a given controller. If a child device is provided,
   1314   it tests to see if this driver supports creating a handle for the specified child device.
   1315 
   1316   This function checks to see if the driver specified by This supports the device specified by
   1317   ControllerHandle. Drivers typically use the device path attached to
   1318   ControllerHandle and/or the services from the bus I/O abstraction attached to
   1319   ControllerHandle to determine if the driver supports ControllerHandle. This function
   1320   may be called many times during platform initialization. In order to reduce boot times, the tests
   1321   performed by this function must be very small and take as little time as possible to execute. This
   1322   function must not change the state of any hardware devices, and this function must be aware that the
   1323   device specified by ControllerHandle may already be managed by the same driver or a
   1324   different driver. This function must match its calls to AllocatePages() with FreePages(),
   1325   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
   1326   Since ControllerHandle may have been previously started by the same driver, if a protocol is
   1327   already in the opened state, then it must not be closed with CloseProtocol(). This is required
   1328   to guarantee the state of ControllerHandle is not modified by this function.
   1329 
   1330   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
   1331   @param[in]  ControllerHandle     The handle of the controller to test. This handle
   1332                                    must support a protocol interface that supplies
   1333                                    an I/O abstraction to the driver.
   1334   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
   1335                                    parameter is ignored by device drivers, and is optional for bus
   1336                                    drivers. For bus drivers, if this parameter is not NULL, then
   1337                                    the bus driver must determine if the bus controller specified
   1338                                    by ControllerHandle and the child controller specified
   1339                                    by RemainingDevicePath are both supported by this
   1340                                    bus driver.
   1341 
   1342   @retval EFI_SUCCESS              The device specified by ControllerHandle and
   1343                                    RemainingDevicePath is supported by the driver specified by This.
   1344   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
   1345                                    RemainingDevicePath is already managed by the driver
   1346                                    specified by This.
   1347   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
   1348                                    RemainingDevicePath is already managed by a different
   1349                                    driver or an application that requires exclusive access.
   1350                                    Currently not implemented.
   1351   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
   1352                                    RemainingDevicePath is not supported by the driver specified by This.
   1353 **/
   1354 EFI_STATUS
   1355 EFIAPI
   1356 IScsiIp6DriverBindingSupported (
   1357   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
   1358   IN EFI_HANDLE                   ControllerHandle,
   1359   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
   1360   )
   1361 {
   1362   return IScsiSupported (
   1363            This,
   1364            ControllerHandle,
   1365            RemainingDevicePath,
   1366            IP_VERSION_6
   1367            );
   1368 }
   1369 
   1370 /**
   1371   Starts a device controller or a bus controller.
   1372 
   1373   The Start() function is designed to be invoked from the EFI boot service ConnectController().
   1374   As a result, much of the error checking on the parameters to Start() has been moved into this
   1375   common boot service. It is legal to call Start() from other locations,
   1376   but the following calling restrictions must be followed or the system behavior will not be deterministic.
   1377   1. ControllerHandle must be a valid EFI_HANDLE.
   1378   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
   1379      EFI_DEVICE_PATH_PROTOCOL.
   1380   3. Prior to calling Start(), the Supported() function for the driver specified by This must
   1381      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
   1382 
   1383   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
   1384   @param[in]  ControllerHandle     The handle of the controller to start. This handle
   1385                                    must support a protocol interface that supplies
   1386                                    an I/O abstraction to the driver.
   1387   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
   1388                                    parameter is ignored by device drivers, and is optional for bus
   1389                                    drivers. For a bus driver, if this parameter is NULL, then handles
   1390                                    for all the children of Controller are created by this driver.
   1391                                    If this parameter is not NULL and the first Device Path Node is
   1392                                    not the End of Device Path Node, then only the handle for the
   1393                                    child device specified by the first Device Path Node of
   1394                                    RemainingDevicePath is created by this driver.
   1395                                    If the first Device Path Node of RemainingDevicePath is
   1396                                    the End of Device Path Node, no child handle is created by this
   1397                                    driver.
   1398 
   1399   @retval EFI_SUCCESS              The device was started.
   1400   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error. Currently not implemented.
   1401   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
   1402   @retval Others                   The driver failed to start the device.
   1403 
   1404 **/
   1405 EFI_STATUS
   1406 EFIAPI
   1407 IScsiIp6DriverBindingStart (
   1408   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
   1409   IN EFI_HANDLE                   ControllerHandle,
   1410   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
   1411   )
   1412 {
   1413   EFI_STATUS        Status;
   1414 
   1415   Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_6);
   1416   if (Status == EFI_ALREADY_STARTED) {
   1417     Status = EFI_SUCCESS;
   1418   }
   1419 
   1420   return Status;
   1421 }
   1422 
   1423 /**
   1424   Stops a device controller or a bus controller.
   1425 
   1426   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
   1427   As a result, much of the error checking on the parameters to Stop() has been moved
   1428   into this common boot service. It is legal to call Stop() from other locations,
   1429   but the following calling restrictions must be followed or the system behavior will not be deterministic.
   1430   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
   1431      same driver's Start() function.
   1432   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
   1433      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
   1434      Start() function, and the Start() function must have called OpenProtocol() on
   1435      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
   1436 
   1437   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
   1438   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
   1439                                 support a bus specific I/O protocol for the driver
   1440                                 to use to stop the device.
   1441   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
   1442   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
   1443                                 if NumberOfChildren is 0.
   1444 
   1445   @retval EFI_SUCCESS           The device was stopped.
   1446   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
   1447 
   1448 **/
   1449 EFI_STATUS
   1450 EFIAPI
   1451 IScsiIp6DriverBindingStop (
   1452   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
   1453   IN EFI_HANDLE                   ControllerHandle,
   1454   IN UINTN                        NumberOfChildren,
   1455   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
   1456   )
   1457 {
   1458   return IScsiStop (
   1459            This,
   1460            ControllerHandle,
   1461            NumberOfChildren,
   1462            ChildHandleBuffer,
   1463            IP_VERSION_6
   1464            );
   1465 }
   1466 
   1467 /**
   1468   Unload the iSCSI driver.
   1469 
   1470   @param[in]  ImageHandle          The handle of the driver image.
   1471 
   1472   @retval     EFI_SUCCESS          The driver is unloaded.
   1473   @retval     EFI_DEVICE_ERROR     An unexpected error occurred.
   1474 
   1475 **/
   1476 EFI_STATUS
   1477 EFIAPI
   1478 IScsiUnload (
   1479   IN EFI_HANDLE  ImageHandle
   1480   )
   1481 {
   1482   EFI_STATUS                        Status;
   1483   UINTN                             DeviceHandleCount;
   1484   EFI_HANDLE                        *DeviceHandleBuffer;
   1485   UINTN                             Index;
   1486   EFI_COMPONENT_NAME_PROTOCOL       *ComponentName;
   1487   EFI_COMPONENT_NAME2_PROTOCOL      *ComponentName2;
   1488 
   1489   //
   1490   // Try to disonnect the driver from the devices it's controlling.
   1491   //
   1492   Status = gBS->LocateHandleBuffer (
   1493                   AllHandles,
   1494                   NULL,
   1495                   NULL,
   1496                   &DeviceHandleCount,
   1497                   &DeviceHandleBuffer
   1498                   );
   1499   if (EFI_ERROR (Status)) {
   1500     return Status;
   1501   }
   1502 
   1503   //
   1504   // Disconnect the iSCSI4 driver from the controlled device.
   1505   //
   1506   for (Index = 0; Index < DeviceHandleCount; Index++) {
   1507     Status = IScsiTestManagedDevice (
   1508                DeviceHandleBuffer[Index],
   1509                gIScsiIp4DriverBinding.DriverBindingHandle,
   1510                &gEfiTcp4ProtocolGuid)
   1511                ;
   1512     if (EFI_ERROR (Status)) {
   1513       continue;
   1514     }
   1515     Status = gBS->DisconnectController (
   1516                     DeviceHandleBuffer[Index],
   1517                     gIScsiIp4DriverBinding.DriverBindingHandle,
   1518                     NULL
   1519                     );
   1520     if (EFI_ERROR (Status)) {
   1521       goto ON_EXIT;
   1522     }
   1523   }
   1524 
   1525   //
   1526   // Disconnect the iSCSI6 driver from the controlled device.
   1527   //
   1528   for (Index = 0; Index < DeviceHandleCount; Index++) {
   1529     Status = IScsiTestManagedDevice (
   1530                DeviceHandleBuffer[Index],
   1531                gIScsiIp6DriverBinding.DriverBindingHandle,
   1532                &gEfiTcp6ProtocolGuid
   1533                );
   1534     if (EFI_ERROR (Status)) {
   1535       continue;
   1536     }
   1537     Status = gBS->DisconnectController (
   1538                     DeviceHandleBuffer[Index],
   1539                     gIScsiIp6DriverBinding.DriverBindingHandle,
   1540                     NULL
   1541                     );
   1542     if (EFI_ERROR (Status)) {
   1543       goto ON_EXIT;
   1544     }
   1545   }
   1546 
   1547   //
   1548   // Unload the iSCSI configuration form.
   1549   //
   1550   Status = IScsiConfigFormUnload (gIScsiIp4DriverBinding.DriverBindingHandle);
   1551   if (EFI_ERROR (Status)) {
   1552     goto ON_EXIT;
   1553   }
   1554 
   1555   //
   1556   // Uninstall the protocols installed by iSCSI driver.
   1557   //
   1558   Status = gBS->UninstallMultipleProtocolInterfaces (
   1559                   ImageHandle,
   1560                   &gEfiAuthenticationInfoProtocolGuid,
   1561                   &gIScsiAuthenticationInfo,
   1562                   NULL
   1563                   );
   1564   if (EFI_ERROR (Status)) {
   1565     goto ON_EXIT;
   1566   }
   1567 
   1568   if (gIScsiControllerNameTable!= NULL) {
   1569     Status = FreeUnicodeStringTable (gIScsiControllerNameTable);
   1570     if (EFI_ERROR (Status)) {
   1571       goto ON_EXIT;
   1572     }
   1573     gIScsiControllerNameTable = NULL;
   1574   }
   1575 
   1576   //
   1577   // Uninstall the ComponentName and ComponentName2 protocol from iSCSI4 driver binding handle
   1578   // if it has been installed.
   1579   //
   1580   Status = gBS->HandleProtocol (
   1581                   gIScsiIp4DriverBinding.DriverBindingHandle,
   1582                   &gEfiComponentNameProtocolGuid,
   1583                   (VOID **) &ComponentName
   1584                   );
   1585   if (!EFI_ERROR (Status)) {
   1586     Status = gBS->UninstallMultipleProtocolInterfaces (
   1587            gIScsiIp4DriverBinding.DriverBindingHandle,
   1588            &gEfiComponentNameProtocolGuid,
   1589            ComponentName,
   1590            NULL
   1591            );
   1592     if (EFI_ERROR (Status)) {
   1593       goto ON_EXIT;
   1594     }
   1595   }
   1596 
   1597   Status = gBS->HandleProtocol (
   1598                   gIScsiIp4DriverBinding.DriverBindingHandle,
   1599                   &gEfiComponentName2ProtocolGuid,
   1600                   (VOID **) &ComponentName2
   1601                   );
   1602   if (!EFI_ERROR (Status)) {
   1603     gBS->UninstallMultipleProtocolInterfaces (
   1604            gIScsiIp4DriverBinding.DriverBindingHandle,
   1605            &gEfiComponentName2ProtocolGuid,
   1606            ComponentName2,
   1607            NULL
   1608            );
   1609     if (EFI_ERROR (Status)) {
   1610       goto ON_EXIT;
   1611     }
   1612   }
   1613 
   1614   //
   1615   // Uninstall the ComponentName and ComponentName2 protocol from iSCSI6 driver binding handle
   1616   // if it has been installed.
   1617   //
   1618   Status = gBS->HandleProtocol (
   1619                   gIScsiIp6DriverBinding.DriverBindingHandle,
   1620                   &gEfiComponentNameProtocolGuid,
   1621                   (VOID **) &ComponentName
   1622                   );
   1623   if (!EFI_ERROR (Status)) {
   1624     Status = gBS->UninstallMultipleProtocolInterfaces (
   1625            gIScsiIp6DriverBinding.DriverBindingHandle,
   1626            &gEfiComponentNameProtocolGuid,
   1627            ComponentName,
   1628            NULL
   1629            );
   1630     if (EFI_ERROR (Status)) {
   1631       goto ON_EXIT;
   1632     }
   1633   }
   1634 
   1635   Status = gBS->HandleProtocol (
   1636                   gIScsiIp6DriverBinding.DriverBindingHandle,
   1637                   &gEfiComponentName2ProtocolGuid,
   1638                   (VOID **) &ComponentName2
   1639                   );
   1640   if (!EFI_ERROR (Status)) {
   1641     gBS->UninstallMultipleProtocolInterfaces (
   1642            gIScsiIp6DriverBinding.DriverBindingHandle,
   1643            &gEfiComponentName2ProtocolGuid,
   1644            ComponentName2,
   1645            NULL
   1646            );
   1647     if (EFI_ERROR (Status)) {
   1648       goto ON_EXIT;
   1649     }
   1650   }
   1651 
   1652   //
   1653   // Uninstall the IScsiInitiatorNameProtocol and all the driver binding protocols.
   1654   //
   1655   Status = gBS->UninstallMultipleProtocolInterfaces (
   1656                   gIScsiIp4DriverBinding.DriverBindingHandle,
   1657                   &gEfiDriverBindingProtocolGuid,
   1658                   &gIScsiIp4DriverBinding,
   1659                   &gEfiIScsiInitiatorNameProtocolGuid,
   1660                   &gIScsiInitiatorName,
   1661                   NULL
   1662                   );
   1663   if (EFI_ERROR (Status)) {
   1664     goto ON_EXIT;
   1665   }
   1666 
   1667   Status = gBS->UninstallMultipleProtocolInterfaces (
   1668                   gIScsiIp6DriverBinding.DriverBindingHandle,
   1669                   &gEfiDriverBindingProtocolGuid,
   1670                   &gIScsiIp6DriverBinding,
   1671                   NULL
   1672                   );
   1673 
   1674 ON_EXIT:
   1675 
   1676   if (DeviceHandleBuffer != NULL) {
   1677     FreePool (DeviceHandleBuffer);
   1678   }
   1679 
   1680   return Status;
   1681 }
   1682 
   1683 /**
   1684   This is the declaration of an EFI image entry point. This entry point is
   1685   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
   1686   both device drivers and bus drivers.
   1687 
   1688   The entry point for iSCSI driver which initializes the global variables and
   1689   installs the driver binding, component name protocol, iSCSI initiator name
   1690   protocol and Authentication Info protocol on its image.
   1691 
   1692   @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.
   1693   @param[in]  SystemTable       A pointer to the EFI System Table.
   1694 
   1695   @retval EFI_SUCCESS           The operation completed successfully.
   1696   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
   1697 
   1698 **/
   1699 EFI_STATUS
   1700 EFIAPI
   1701 IScsiDriverEntryPoint (
   1702   IN EFI_HANDLE         ImageHandle,
   1703   IN EFI_SYSTEM_TABLE   *SystemTable
   1704   )
   1705 {
   1706   EFI_STATUS                         Status;
   1707   EFI_ISCSI_INITIATOR_NAME_PROTOCOL  *IScsiInitiatorName;
   1708   EFI_AUTHENTICATION_INFO_PROTOCOL   *AuthenticationInfo;
   1709 
   1710   //
   1711   // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.
   1712   //
   1713   Status = gBS->LocateProtocol (
   1714                   &gEfiIScsiInitiatorNameProtocolGuid,
   1715                   NULL,
   1716                   (VOID **) &IScsiInitiatorName
   1717                   );
   1718   if (!EFI_ERROR (Status)) {
   1719     return EFI_ACCESS_DENIED;
   1720   }
   1721 
   1722   //
   1723   // Initialize the EFI Driver Library.
   1724   //
   1725   Status = EfiLibInstallDriverBindingComponentName2 (
   1726              ImageHandle,
   1727              SystemTable,
   1728              &gIScsiIp4DriverBinding,
   1729              ImageHandle,
   1730              &gIScsiComponentName,
   1731              &gIScsiComponentName2
   1732              );
   1733   if (EFI_ERROR (Status)) {
   1734     return Status;
   1735   }
   1736 
   1737   Status = EfiLibInstallDriverBindingComponentName2 (
   1738              ImageHandle,
   1739              SystemTable,
   1740              &gIScsiIp6DriverBinding,
   1741              NULL,
   1742              &gIScsiComponentName,
   1743              &gIScsiComponentName2
   1744              );
   1745   if (EFI_ERROR (Status)) {
   1746     goto Error1;
   1747   }
   1748 
   1749   //
   1750   // Install the iSCSI Initiator Name Protocol.
   1751   //
   1752   Status = gBS->InstallProtocolInterface (
   1753                   &ImageHandle,
   1754                   &gEfiIScsiInitiatorNameProtocolGuid,
   1755                   EFI_NATIVE_INTERFACE,
   1756                   &gIScsiInitiatorName
   1757                   );
   1758   if (EFI_ERROR (Status)) {
   1759     goto Error2;
   1760   }
   1761 
   1762   //
   1763   // Create the private data structures.
   1764   //
   1765   mPrivate = AllocateZeroPool (sizeof (ISCSI_PRIVATE_DATA));
   1766   if (mPrivate == NULL) {
   1767     Status = EFI_OUT_OF_RESOURCES;
   1768     goto Error3;
   1769   }
   1770 
   1771   InitializeListHead (&mPrivate->NicInfoList);
   1772   InitializeListHead (&mPrivate->AttemptConfigs);
   1773 
   1774   //
   1775   // Initialize the configuration form of iSCSI.
   1776   //
   1777   Status = IScsiConfigFormInit (gIScsiIp4DriverBinding.DriverBindingHandle);
   1778   if (EFI_ERROR (Status)) {
   1779     goto Error4;
   1780   }
   1781 
   1782   //
   1783   // There should be only one EFI_AUTHENTICATION_INFO_PROTOCOL. If already exists,
   1784   // do not produce the protocol instance.
   1785   //
   1786   Status = gBS->LocateProtocol (
   1787                   &gEfiAuthenticationInfoProtocolGuid,
   1788                   NULL,
   1789                   (VOID **) &AuthenticationInfo
   1790                   );
   1791   if (Status == EFI_NOT_FOUND) {
   1792     Status = gBS->InstallProtocolInterface (
   1793                     &ImageHandle,
   1794                     &gEfiAuthenticationInfoProtocolGuid,
   1795                     EFI_NATIVE_INTERFACE,
   1796                     &gIScsiAuthenticationInfo
   1797                     );
   1798     if (EFI_ERROR (Status)) {
   1799       goto Error5;
   1800     }
   1801   }
   1802 
   1803   return EFI_SUCCESS;
   1804 
   1805 Error5:
   1806   IScsiConfigFormUnload (gIScsiIp4DriverBinding.DriverBindingHandle);
   1807 
   1808 Error4:
   1809   FreePool (mPrivate);
   1810 
   1811 Error3:
   1812   gBS->UninstallMultipleProtocolInterfaces (
   1813          ImageHandle,
   1814          &gEfiIScsiInitiatorNameProtocolGuid,
   1815          &gIScsiInitiatorName,
   1816          NULL
   1817          );
   1818 
   1819 Error2:
   1820   gBS->UninstallMultipleProtocolInterfaces (
   1821          gIScsiIp6DriverBinding.DriverBindingHandle,
   1822          &gEfiDriverBindingProtocolGuid,
   1823          &gIScsiIp6DriverBinding,
   1824          &gEfiComponentName2ProtocolGuid,
   1825          &gIScsiComponentName2,
   1826          &gEfiComponentNameProtocolGuid,
   1827          &gIScsiComponentName,
   1828          NULL
   1829          );
   1830 
   1831 Error1:
   1832   gBS->UninstallMultipleProtocolInterfaces (
   1833          ImageHandle,
   1834          &gEfiDriverBindingProtocolGuid,
   1835          &gIScsiIp4DriverBinding,
   1836          &gEfiComponentName2ProtocolGuid,
   1837          &gIScsiComponentName2,
   1838          &gEfiComponentNameProtocolGuid,
   1839          &gIScsiComponentName,
   1840          NULL
   1841          );
   1842 
   1843   return Status;
   1844 }
   1845 
   1846