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