Fix a bug about the iSCSI DHCP dependency issue.
[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   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,\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     ASSERT (AttemptConfigOrder != NULL);\r
655     for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {\r
656       if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex ||\r
657           AttemptConfigOrder[Index] == BootSelected) {\r
658         break;\r
659       }\r
660     }\r
661 \r
662     if (mPrivate->EnableMpio) {\r
663       //\r
664       // Use the attempt in earlier order. Abort the later one in MPIO.\r
665       //\r
666       if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {\r
667         IScsiSessionAbort (Private->Session);\r
668         FreePool (Private->Session);\r
669         Private->Session = NULL;\r
670         gBS->UninstallProtocolInterface (\r
671                Private->ExtScsiPassThruHandle,\r
672                &gEfiExtScsiPassThruProtocolGuid,\r
673                &Private->IScsiExtScsiPassThru\r
674                );\r
675         Private->ExtScsiPassThruHandle = NULL;\r
676 \r
677         //\r
678         // Reinstall the original ExtScsiPassThru back.\r
679         //\r
680         Status = gBS->InstallProtocolInterface (\r
681                         &ExistPrivate->ExtScsiPassThruHandle,\r
682                         &gEfiExtScsiPassThruProtocolGuid,\r
683                         EFI_NATIVE_INTERFACE,\r
684                         &ExistPrivate->IScsiExtScsiPassThru\r
685                         );\r
686         if (EFI_ERROR (Status)) {\r
687           goto ON_ERROR;\r
688         }\r
689 \r
690         goto ON_EXIT;\r
691       } else {\r
692         ASSERT (AttemptConfigOrder[Index] == BootSelected);\r
693         mPrivate->BootSelectedIndex = BootSelected;\r
694         //\r
695         // Clear the resource in ExistPrivate.\r
696         //\r
697         gBS->UninstallProtocolInterface (\r
698                ExistPrivate->Controller,\r
699                IScsiPrivateGuid,\r
700                &ExistPrivate->IScsiIdentifier\r
701                ); \r
702         \r
703         IScsiRemoveNic (ExistPrivate->Controller);\r
704         if (ExistPrivate->Session != NULL) {\r
705           IScsiSessionAbort (ExistPrivate->Session);\r
706         }\r
707 \r
708         IScsiCleanDriverData (ExistPrivate);\r
709       }\r
710     } else {\r
711       //\r
712       // Use the attempt in earlier order as boot selected in single path mode.\r
713       //\r
714       if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {\r
715         NeedUpdate = FALSE;\r
716       }\r
717     }\r
718 \r
719   }\r
720 \r
721   if (NeedUpdate) {\r
722     mPrivate->OneSessionEstablished = TRUE;\r
723     mPrivate->BootSelectedIndex     = BootSelected;\r
724   }\r
725 \r
726   //\r
727   // Duplicate the Session's tcp connection device path. The source port field\r
728   // will be set to zero as one iSCSI session is comprised of several iSCSI\r
729   // connections.\r
730   //\r
731   Private->DevicePath = IScsiGetTcpConnDevicePath (Private->Session);\r
732   if (Private->DevicePath == NULL) {\r
733     Status = EFI_DEVICE_ERROR;\r
734     goto ON_ERROR;\r
735   }\r
736   //\r
737   // Install the updated device path onto the ExtScsiPassThruHandle.\r
738   //\r
739   Status = gBS->InstallProtocolInterface (\r
740                   &Private->ExtScsiPassThruHandle,\r
741                   &gEfiDevicePathProtocolGuid,\r
742                   EFI_NATIVE_INTERFACE,\r
743                   Private->DevicePath\r
744                   );\r
745   if (EFI_ERROR (Status)) {\r
746     goto ON_ERROR;\r
747   }\r
748 \r
749 ON_EXIT:\r
750 \r
751   //\r
752   // Update/Publish the iSCSI Boot Firmware Table.\r
753   //\r
754   if (mPrivate->BootSelectedIndex != 0) {\r
755     IScsiPublishIbft ();\r
756   }\r
757 \r
758   return EFI_SUCCESS;\r
759 \r
760 ON_ERROR:\r
761 \r
762   if (Private->Session != NULL) {\r
763     IScsiSessionAbort (Private->Session);\r
764   }\r
765 \r
766   return Status;\r
767 }\r
768 \r
769 /**\r
770   Stops a device controller or a bus controller. This is the worker function for\r
771   IScsiIp4(6)DriverBindingStop.\r
772   \r
773   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
774   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must \r
775                                 support a bus specific I/O protocol for the driver \r
776                                 to use to stop the device.\r
777   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
778   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL \r
779                                 if NumberOfChildren is 0.\r
780   @param[in]  IpVersion         IP_VERSION_4 or IP_VERSION_6.\r
781   \r
782   @retval EFI_SUCCESS           The device was stopped.\r
783   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
784 \r
785 **/\r
786 EFI_STATUS\r
787 EFIAPI\r
788 IScsiStop (\r
789   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
790   IN EFI_HANDLE                   ControllerHandle,\r
791   IN UINTN                        NumberOfChildren,\r
792   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL,\r
793   IN UINT8                        IpVersion\r
794   )\r
795 {\r
796   EFI_HANDLE                      IScsiController;\r
797   EFI_STATUS                      Status;\r
798   ISCSI_PRIVATE_PROTOCOL          *IScsiIdentifier;\r
799   ISCSI_DRIVER_DATA               *Private;\r
800   EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;\r
801   ISCSI_CONNECTION                *Conn;\r
802   EFI_GUID                        *ProtocolGuid;\r
803   EFI_GUID                        *TcpServiceBindingGuid;\r
804   EFI_GUID                        *TcpProtocolGuid;\r
805 \r
806 \r
807   if (NumberOfChildren != 0) {\r
808     //\r
809     // We should have only one child.\r
810     //\r
811     Status = gBS->OpenProtocol (\r
812                     ChildHandleBuffer[0],\r
813                     &gEfiExtScsiPassThruProtocolGuid,\r
814                     (VOID **) &PassThru,\r
815                     This->DriverBindingHandle,\r
816                     ControllerHandle,\r
817                     EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
818                     );\r
819     if (EFI_ERROR (Status)) {\r
820       return EFI_DEVICE_ERROR;\r
821     }\r
822 \r
823     Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);\r
824     Conn    = NET_LIST_HEAD (&Private->Session->Conns, ISCSI_CONNECTION, Link);\r
825 \r
826     //\r
827     // Previously the TCP protocol is opened BY_CHILD_CONTROLLER. Just close\r
828     // the protocol here, but do not uninstall the device path protocol and\r
829     // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.\r
830     //\r
831     if (IpVersion == IP_VERSION_4) {\r
832       ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
833     } else {\r
834       ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
835     }\r
836 \r
837     gBS->CloseProtocol (\r
838            Conn->TcpIo.Handle,\r
839            ProtocolGuid,\r
840            Private->Image,\r
841            Private->ExtScsiPassThruHandle\r
842            );\r
843 \r
844     return EFI_SUCCESS;\r
845   }\r
846   //\r
847   // Get the handle of the controller we are controling.\r
848   //\r
849   if (IpVersion == IP_VERSION_4) {\r
850     ProtocolGuid            = &gIScsiV4PrivateGuid;\r
851     TcpProtocolGuid         = &gEfiTcp4ProtocolGuid;\r
852     TcpServiceBindingGuid   = &gEfiTcp4ServiceBindingProtocolGuid;\r
853   } else {\r
854     ProtocolGuid            = &gIScsiV6PrivateGuid;\r
855     TcpProtocolGuid         = &gEfiTcp6ProtocolGuid;\r
856     TcpServiceBindingGuid   = &gEfiTcp6ServiceBindingProtocolGuid;\r
857   }\r
858   IScsiController = NetLibGetNicHandle (ControllerHandle, TcpProtocolGuid);\r
859   if (IScsiController == NULL) {\r
860     return EFI_SUCCESS;\r
861   }\r
862 \r
863   Status = gBS->OpenProtocol (\r
864                   IScsiController,\r
865                   ProtocolGuid,\r
866                   (VOID **) &IScsiIdentifier,\r
867                   This->DriverBindingHandle,\r
868                   ControllerHandle,\r
869                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
870                   );\r
871   if (EFI_ERROR (Status)) {\r
872     return EFI_DEVICE_ERROR;\r
873   }\r
874 \r
875   Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);\r
876   ASSERT (Private != NULL);\r
877 \r
878   if (Private->ChildHandle != NULL) {\r
879     Status = gBS->CloseProtocol (\r
880                     Private->ChildHandle,\r
881                     TcpProtocolGuid,\r
882                     This->DriverBindingHandle,\r
883                     IScsiController\r
884                     );\r
885                     \r
886     ASSERT (!EFI_ERROR (Status));\r
887 \r
888     Status = NetLibDestroyServiceChild (\r
889                IScsiController,\r
890                This->DriverBindingHandle,\r
891                TcpServiceBindingGuid,\r
892                Private->ChildHandle\r
893                );\r
894 \r
895     ASSERT (!EFI_ERROR (Status));\r
896   }\r
897 \r
898   gBS->UninstallProtocolInterface (\r
899          IScsiController,\r
900          ProtocolGuid,\r
901          &Private->IScsiIdentifier\r
902          ); \r
903 \r
904   //\r
905   // Remove this NIC.\r
906   //\r
907   IScsiRemoveNic (IScsiController);\r
908 \r
909   //\r
910   // Update the iSCSI Boot Firware Table.\r
911   //\r
912   IScsiPublishIbft ();\r
913 \r
914   if (Private->Session != NULL) {\r
915     IScsiSessionAbort (Private->Session);\r
916   }\r
917 \r
918   IScsiCleanDriverData (Private);\r
919 \r
920   return EFI_SUCCESS;\r
921 }\r
922 \r
923 /**\r
924   Tests to see if this driver supports a given controller. If a child device is provided, \r
925   it tests to see if this driver supports creating a handle for the specified child device.\r
926 \r
927   This function checks to see if the driver specified by This supports the device specified by \r
928   ControllerHandle. Drivers typically use the device path attached to \r
929   ControllerHandle and/or the services from the bus I/O abstraction attached to \r
930   ControllerHandle to determine if the driver supports ControllerHandle. This function \r
931   may be called many times during platform initialization. In order to reduce boot times, the tests \r
932   performed by this function must be very small and take as little time as possible to execute. This \r
933   function must not change the state of any hardware devices, and this function must be aware that the \r
934   device specified by ControllerHandle may already be managed by the same driver or a \r
935   different driver. This function must match its calls to AllocatePages() with FreePages(), \r
936   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().  \r
937   Since ControllerHandle may have been previously started by the same driver, if a protocol is \r
938   already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
939   to guarantee the state of ControllerHandle is not modified by this function.\r
940 \r
941   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
942   @param[in]  ControllerHandle     The handle of the controller to test. This handle \r
943                                    must support a protocol interface that supplies \r
944                                    an I/O abstraction to the driver.\r
945   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
946                                    parameter is ignored by device drivers, and is optional for bus \r
947                                    drivers. For bus drivers, if this parameter is not NULL, then \r
948                                    the bus driver must determine if the bus controller specified \r
949                                    by ControllerHandle and the child controller specified \r
950                                    by RemainingDevicePath are both supported by this \r
951                                    bus driver.\r
952 \r
953   @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
954                                    RemainingDevicePath is supported by the driver specified by This.\r
955   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
956                                    RemainingDevicePath is already managed by the driver\r
957                                    specified by This.\r
958   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
959                                    RemainingDevicePath is already managed by a different\r
960                                    driver or an application that requires exclusive access.\r
961                                    Currently not implemented.\r
962   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
963                                    RemainingDevicePath is not supported by the driver specified by This.\r
964 **/\r
965 EFI_STATUS\r
966 EFIAPI\r
967 IScsiIp4DriverBindingSupported (\r
968   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
969   IN EFI_HANDLE                   ControllerHandle,\r
970   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
971   )\r
972 {\r
973   return IScsiSupported (\r
974            This,\r
975            ControllerHandle,\r
976            RemainingDevicePath,\r
977            IP_VERSION_4\r
978            );\r
979 }\r
980 \r
981 /**\r
982   Starts a device controller or a bus controller.\r
983 \r
984   The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
985   As a result, much of the error checking on the parameters to Start() has been moved into this \r
986   common boot service. It is legal to call Start() from other locations, \r
987   but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
988   1. ControllerHandle must be a valid EFI_HANDLE.\r
989   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
990      EFI_DEVICE_PATH_PROTOCOL.\r
991   3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
992      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.  \r
993 \r
994   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
995   @param[in]  ControllerHandle     The handle of the controller to start. This handle \r
996                                    must support a protocol interface that supplies \r
997                                    an I/O abstraction to the driver.\r
998   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
999                                    parameter is ignored by device drivers, and is optional for bus \r
1000                                    drivers. For a bus driver, if this parameter is NULL, then handles \r
1001                                    for all the children of Controller are created by this driver.  \r
1002                                    If this parameter is not NULL and the first Device Path Node is \r
1003                                    not the End of Device Path Node, then only the handle for the \r
1004                                    child device specified by the first Device Path Node of \r
1005                                    RemainingDevicePath is created by this driver.\r
1006                                    If the first Device Path Node of RemainingDevicePath is \r
1007                                    the End of Device Path Node, no child handle is created by this\r
1008                                    driver.\r
1009 \r
1010   @retval EFI_SUCCESS              The device was started.\r
1011   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error. Currently not implemented.\r
1012   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
1013   @retval Others                   The driver failed to start the device.\r
1014 \r
1015 **/\r
1016 EFI_STATUS\r
1017 EFIAPI\r
1018 IScsiIp4DriverBindingStart (\r
1019   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
1020   IN EFI_HANDLE                   ControllerHandle,\r
1021   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
1022   )\r
1023 {\r
1024   EFI_STATUS        Status;\r
1025 \r
1026   Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_4);\r
1027   if (Status == EFI_ALREADY_STARTED) {\r
1028     Status = EFI_SUCCESS;\r
1029   }\r
1030 \r
1031   return Status;\r
1032 }\r
1033 \r
1034 /**\r
1035   Stops a device controller or a bus controller.\r
1036   \r
1037   The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
1038   As a result, much of the error checking on the parameters to Stop() has been moved \r
1039   into this common boot service. It is legal to call Stop() from other locations, \r
1040   but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
1041   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
1042      same driver's Start() function.\r
1043   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
1044      EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
1045      Start() function, and the Start() function must have called OpenProtocol() on\r
1046      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
1047   \r
1048   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1049   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must \r
1050                                 support a bus specific I/O protocol for the driver \r
1051                                 to use to stop the device.\r
1052   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
1053   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL \r
1054                                 if NumberOfChildren is 0.\r
1055 \r
1056   @retval EFI_SUCCESS           The device was stopped.\r
1057   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
1058 \r
1059 **/\r
1060 EFI_STATUS\r
1061 EFIAPI\r
1062 IScsiIp4DriverBindingStop (\r
1063   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
1064   IN EFI_HANDLE                   ControllerHandle,\r
1065   IN UINTN                        NumberOfChildren,\r
1066   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL\r
1067   )\r
1068 {\r
1069   return IScsiStop (\r
1070            This,\r
1071            ControllerHandle,\r
1072            NumberOfChildren,\r
1073            ChildHandleBuffer,\r
1074            IP_VERSION_4\r
1075            );\r
1076 }\r
1077 \r
1078 /**\r
1079   Tests to see if this driver supports a given controller. If a child device is provided, \r
1080   it tests to see if this driver supports creating a handle for the specified child device.\r
1081 \r
1082   This function checks to see if the driver specified by This supports the device specified by \r
1083   ControllerHandle. Drivers typically use the device path attached to \r
1084   ControllerHandle and/or the services from the bus I/O abstraction attached to \r
1085   ControllerHandle to determine if the driver supports ControllerHandle. This function \r
1086   may be called many times during platform initialization. In order to reduce boot times, the tests \r
1087   performed by this function must be very small and take as little time as possible to execute. This \r
1088   function must not change the state of any hardware devices, and this function must be aware that the \r
1089   device specified by ControllerHandle may already be managed by the same driver or a \r
1090   different driver. This function must match its calls to AllocatePages() with FreePages(), \r
1091   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().  \r
1092   Since ControllerHandle may have been previously started by the same driver, if a protocol is \r
1093   already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
1094   to guarantee the state of ControllerHandle is not modified by this function.\r
1095 \r
1096   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1097   @param[in]  ControllerHandle     The handle of the controller to test. This handle \r
1098                                    must support a protocol interface that supplies \r
1099                                    an I/O abstraction to the driver.\r
1100   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
1101                                    parameter is ignored by device drivers, and is optional for bus \r
1102                                    drivers. For bus drivers, if this parameter is not NULL, then \r
1103                                    the bus driver must determine if the bus controller specified \r
1104                                    by ControllerHandle and the child controller specified \r
1105                                    by RemainingDevicePath are both supported by this \r
1106                                    bus driver.\r
1107 \r
1108   @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
1109                                    RemainingDevicePath is supported by the driver specified by This.\r
1110   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
1111                                    RemainingDevicePath is already managed by the driver\r
1112                                    specified by This.\r
1113   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
1114                                    RemainingDevicePath is already managed by a different\r
1115                                    driver or an application that requires exclusive access.\r
1116                                    Currently not implemented.\r
1117   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
1118                                    RemainingDevicePath is not supported by the driver specified by This.\r
1119 **/\r
1120 EFI_STATUS\r
1121 EFIAPI\r
1122 IScsiIp6DriverBindingSupported (\r
1123   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
1124   IN EFI_HANDLE                   ControllerHandle,\r
1125   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
1126   )\r
1127 {\r
1128   return IScsiSupported (\r
1129            This,\r
1130            ControllerHandle,\r
1131            RemainingDevicePath,\r
1132            IP_VERSION_6\r
1133            );\r
1134 }\r
1135 \r
1136 /**\r
1137   Starts a device controller or a bus controller.\r
1138 \r
1139   The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
1140   As a result, much of the error checking on the parameters to Start() has been moved into this \r
1141   common boot service. It is legal to call Start() from other locations, \r
1142   but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
1143   1. ControllerHandle must be a valid EFI_HANDLE.\r
1144   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
1145      EFI_DEVICE_PATH_PROTOCOL.\r
1146   3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
1147      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.  \r
1148 \r
1149   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1150   @param[in]  ControllerHandle     The handle of the controller to start. This handle \r
1151                                    must support a protocol interface that supplies \r
1152                                    an I/O abstraction to the driver.\r
1153   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
1154                                    parameter is ignored by device drivers, and is optional for bus \r
1155                                    drivers. For a bus driver, if this parameter is NULL, then handles \r
1156                                    for all the children of Controller are created by this driver.  \r
1157                                    If this parameter is not NULL and the first Device Path Node is \r
1158                                    not the End of Device Path Node, then only the handle for the \r
1159                                    child device specified by the first Device Path Node of \r
1160                                    RemainingDevicePath is created by this driver.\r
1161                                    If the first Device Path Node of RemainingDevicePath is \r
1162                                    the End of Device Path Node, no child handle is created by this\r
1163                                    driver.\r
1164 \r
1165   @retval EFI_SUCCESS              The device was started.\r
1166   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error. Currently not implemented.\r
1167   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
1168   @retval Others                   The driver failed to start the device.\r
1169 \r
1170 **/\r
1171 EFI_STATUS\r
1172 EFIAPI\r
1173 IScsiIp6DriverBindingStart (\r
1174   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
1175   IN EFI_HANDLE                   ControllerHandle,\r
1176   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
1177   )\r
1178 {\r
1179   EFI_STATUS        Status;\r
1180 \r
1181   Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_6);\r
1182   if (Status == EFI_ALREADY_STARTED) {\r
1183     Status = EFI_SUCCESS;\r
1184   }\r
1185 \r
1186   return Status;\r
1187 }\r
1188 \r
1189 /**\r
1190   Stops a device controller or a bus controller.\r
1191   \r
1192   The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
1193   As a result, much of the error checking on the parameters to Stop() has been moved \r
1194   into this common boot service. It is legal to call Stop() from other locations, \r
1195   but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
1196   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
1197      same driver's Start() function.\r
1198   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
1199      EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
1200      Start() function, and the Start() function must have called OpenProtocol() on\r
1201      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
1202   \r
1203   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1204   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must \r
1205                                 support a bus specific I/O protocol for the driver \r
1206                                 to use to stop the device.\r
1207   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
1208   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL \r
1209                                 if NumberOfChildren is 0.\r
1210 \r
1211   @retval EFI_SUCCESS           The device was stopped.\r
1212   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
1213 \r
1214 **/\r
1215 EFI_STATUS\r
1216 EFIAPI\r
1217 IScsiIp6DriverBindingStop (\r
1218   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
1219   IN EFI_HANDLE                   ControllerHandle,\r
1220   IN UINTN                        NumberOfChildren,\r
1221   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL\r
1222   )\r
1223 {\r
1224   return IScsiStop (\r
1225            This,\r
1226            ControllerHandle,\r
1227            NumberOfChildren,\r
1228            ChildHandleBuffer,\r
1229            IP_VERSION_6\r
1230            );\r
1231 }\r
1232 \r
1233 /**\r
1234   Unload the iSCSI driver.\r
1235 \r
1236   @param[in]  ImageHandle          The handle of the driver image.\r
1237 \r
1238   @retval     EFI_SUCCESS          The driver is unloaded.\r
1239   @retval     EFI_DEVICE_ERROR     An unexpected error occurred.\r
1240 \r
1241 **/\r
1242 EFI_STATUS\r
1243 EFIAPI\r
1244 IScsiUnload (\r
1245   IN EFI_HANDLE  ImageHandle\r
1246   )\r
1247 {\r
1248   EFI_STATUS  Status;\r
1249   UINTN       DeviceHandleCount;\r
1250   EFI_HANDLE  *DeviceHandleBuffer;\r
1251   UINTN       Index;\r
1252 \r
1253   //\r
1254   // Try to disonnect the driver from the devices it's controlling.\r
1255   //\r
1256   Status = gBS->LocateHandleBuffer (\r
1257                   AllHandles,\r
1258                   NULL,\r
1259                   NULL,\r
1260                   &DeviceHandleCount,\r
1261                   &DeviceHandleBuffer\r
1262                   );\r
1263   if (EFI_ERROR (Status)) {\r
1264     return Status;\r
1265   }\r
1266 \r
1267   for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1268     gBS->DisconnectController (\r
1269            DeviceHandleBuffer[Index],\r
1270            gIScsiIp4DriverBinding.DriverBindingHandle,\r
1271            NULL\r
1272            );\r
1273     gBS->DisconnectController (\r
1274            DeviceHandleBuffer[Index],\r
1275            gIScsiIp6DriverBinding.DriverBindingHandle,\r
1276            NULL\r
1277            );\r
1278   }\r
1279 \r
1280   //\r
1281   // Unload the iSCSI configuration form.\r
1282   //\r
1283   IScsiConfigFormUnload (gIScsiIp4DriverBinding.DriverBindingHandle);\r
1284 \r
1285   //\r
1286   // Uninstall the protocols installed by iSCSI driver.\r
1287   //\r
1288   gBS->UninstallMultipleProtocolInterfaces (\r
1289          ImageHandle,\r
1290          &gEfiAuthenticationInfoProtocolGuid,\r
1291          &gIScsiAuthenticationInfo,\r
1292          NULL\r
1293          );\r
1294 \r
1295   if (gIScsiControllerNameTable!= NULL) {\r
1296     FreeUnicodeStringTable (gIScsiControllerNameTable);\r
1297     gIScsiControllerNameTable = NULL;\r
1298   }\r
1299   \r
1300   gBS->UninstallMultipleProtocolInterfaces (\r
1301          gIScsiIp4DriverBinding.DriverBindingHandle,\r
1302          &gEfiDriverBindingProtocolGuid,\r
1303          &gIScsiIp4DriverBinding,\r
1304          &gEfiComponentName2ProtocolGuid,\r
1305          &gIScsiComponentName2,\r
1306          &gEfiComponentNameProtocolGuid,\r
1307          &gIScsiComponentName,\r
1308          &gEfiIScsiInitiatorNameProtocolGuid,\r
1309          &gIScsiInitiatorName,\r
1310          NULL\r
1311          );\r
1312 \r
1313   gBS->UninstallMultipleProtocolInterfaces (\r
1314          gIScsiIp6DriverBinding.DriverBindingHandle,\r
1315          &gEfiDriverBindingProtocolGuid,\r
1316          &gIScsiIp6DriverBinding,\r
1317          &gEfiComponentName2ProtocolGuid,\r
1318          &gIScsiComponentName2,\r
1319          &gEfiComponentNameProtocolGuid,\r
1320          &gIScsiComponentName,\r
1321          NULL\r
1322          );\r
1323 \r
1324   return EFI_SUCCESS;\r
1325 }\r
1326 \r
1327 /**\r
1328   This is the declaration of an EFI image entry point. This entry point is\r
1329   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
1330   both device drivers and bus drivers.\r
1331   \r
1332   The entry point for iSCSI driver which initializes the global variables and\r
1333   installs the driver binding, component name protocol, iSCSI initiator name\r
1334   protocol and Authentication Info protocol on its image.\r
1335   \r
1336   @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.\r
1337   @param[in]  SystemTable       A pointer to the EFI System Table.\r
1338 \r
1339   @retval EFI_SUCCESS           The operation completed successfully.\r
1340   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
1341 \r
1342 **/\r
1343 EFI_STATUS\r
1344 EFIAPI\r
1345 IScsiDriverEntryPoint (\r
1346   IN EFI_HANDLE         ImageHandle,\r
1347   IN EFI_SYSTEM_TABLE   *SystemTable\r
1348   )\r
1349 {\r
1350   EFI_STATUS                         Status;\r
1351   EFI_ISCSI_INITIATOR_NAME_PROTOCOL  *IScsiInitiatorName;\r
1352   EFI_AUTHENTICATION_INFO_PROTOCOL   *AuthenticationInfo;\r
1353 \r
1354   //\r
1355   // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.\r
1356   //\r
1357   Status = gBS->LocateProtocol (\r
1358                   &gEfiIScsiInitiatorNameProtocolGuid,\r
1359                   NULL,\r
1360                   (VOID **) &IScsiInitiatorName\r
1361                   );\r
1362   if (!EFI_ERROR (Status)) {\r
1363     return EFI_ACCESS_DENIED;\r
1364   }\r
1365 \r
1366   //\r
1367   // Initialize the EFI Driver Library.\r
1368   //\r
1369   Status = EfiLibInstallDriverBindingComponentName2 (\r
1370              ImageHandle,\r
1371              SystemTable,\r
1372              &gIScsiIp4DriverBinding,\r
1373              ImageHandle,\r
1374              &gIScsiComponentName,\r
1375              &gIScsiComponentName2\r
1376              );\r
1377   if (EFI_ERROR (Status)) {\r
1378     return Status;\r
1379   }\r
1380 \r
1381   Status = EfiLibInstallDriverBindingComponentName2 (\r
1382              ImageHandle,\r
1383              SystemTable,\r
1384              &gIScsiIp6DriverBinding,\r
1385              NULL,\r
1386              &gIScsiComponentName,\r
1387              &gIScsiComponentName2\r
1388              );\r
1389   if (EFI_ERROR (Status)) {\r
1390     goto Error1;\r
1391   }\r
1392   \r
1393   //\r
1394   // Install the iSCSI Initiator Name Protocol.\r
1395   //\r
1396   Status = gBS->InstallProtocolInterface (\r
1397                   &ImageHandle,\r
1398                   &gEfiIScsiInitiatorNameProtocolGuid,\r
1399                   EFI_NATIVE_INTERFACE,\r
1400                   &gIScsiInitiatorName\r
1401                   );\r
1402   if (EFI_ERROR (Status)) {\r
1403     goto Error2;\r
1404   } \r
1405 \r
1406   //\r
1407   // Create the private data structures.\r
1408   //\r
1409   mPrivate = AllocateZeroPool (sizeof (ISCSI_PRIVATE_DATA));\r
1410   if (mPrivate == NULL) {\r
1411     Status = EFI_OUT_OF_RESOURCES;\r
1412     goto Error3;\r
1413   }\r
1414 \r
1415   InitializeListHead (&mPrivate->NicInfoList);\r
1416   InitializeListHead (&mPrivate->AttemptConfigs);\r
1417 \r
1418   //\r
1419   // Initialize the configuration form of iSCSI.\r
1420   //\r
1421   Status = IScsiConfigFormInit (gIScsiIp4DriverBinding.DriverBindingHandle);\r
1422   if (EFI_ERROR (Status)) {\r
1423     goto Error4;\r
1424   }\r
1425 \r
1426   //\r
1427   // There should be only one EFI_AUTHENTICATION_INFO_PROTOCOL. If already exists,\r
1428   // do not produce the protocol instance.\r
1429   //\r
1430   Status = gBS->LocateProtocol (\r
1431                   &gEfiAuthenticationInfoProtocolGuid,\r
1432                   NULL,\r
1433                   (VOID **) &AuthenticationInfo\r
1434                   );\r
1435   if (Status == EFI_NOT_FOUND) {\r
1436     Status = gBS->InstallProtocolInterface (\r
1437                     &ImageHandle,\r
1438                     &gEfiAuthenticationInfoProtocolGuid,\r
1439                     EFI_NATIVE_INTERFACE,\r
1440                     &gIScsiAuthenticationInfo\r
1441                     );\r
1442     if (EFI_ERROR (Status)) {\r
1443       goto Error5;\r
1444     }    \r
1445   }\r
1446 \r
1447   return EFI_SUCCESS;\r
1448 \r
1449 Error5:\r
1450   IScsiConfigFormUnload (gIScsiIp4DriverBinding.DriverBindingHandle);\r
1451 \r
1452 Error4:\r
1453   FreePool (mPrivate);\r
1454 \r
1455 Error3:\r
1456   gBS->UninstallMultipleProtocolInterfaces (\r
1457          ImageHandle,\r
1458          &gEfiIScsiInitiatorNameProtocolGuid,\r
1459          &gIScsiInitiatorName,\r
1460          NULL\r
1461          );\r
1462 \r
1463 Error2:\r
1464   gBS->UninstallMultipleProtocolInterfaces (\r
1465          gIScsiIp6DriverBinding.DriverBindingHandle,\r
1466          &gEfiDriverBindingProtocolGuid,\r
1467          &gIScsiIp6DriverBinding,\r
1468          &gEfiComponentName2ProtocolGuid,\r
1469          &gIScsiComponentName2,\r
1470          &gEfiComponentNameProtocolGuid,\r
1471          &gIScsiComponentName,\r
1472          NULL\r
1473          );\r
1474 \r
1475 Error1:\r
1476   gBS->UninstallMultipleProtocolInterfaces (\r
1477          ImageHandle,\r
1478          &gEfiDriverBindingProtocolGuid,\r
1479          &gIScsiIp4DriverBinding,\r
1480          &gEfiComponentName2ProtocolGuid,\r
1481          &gIScsiComponentName2,\r
1482          &gEfiComponentNameProtocolGuid,\r
1483          &gIScsiComponentName,\r
1484          NULL\r
1485          );\r
1486 \r
1487   return Status;\r
1488 }\r
1489 \r