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