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