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