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