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