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
IScsiIsDevicePathSupported(IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
IScsiCheckAip()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
IScsiSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL,IN UINT8 IpVersion)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
IScsiStart(IN EFI_HANDLE Image,IN EFI_HANDLE ControllerHandle,IN UINT8 IpVersion)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
IScsiStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL,IN UINT8 IpVersion)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
IScsiIp4DriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
IScsiIp4DriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
IScsiIp4DriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)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
IScsiIp6DriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
IScsiIp6DriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
IScsiIp6DriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)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
IScsiUnload(IN EFI_HANDLE ImageHandle)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
IScsiDriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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