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