]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/IScsiDxe/IScsiDriver.c
NetworkPkg: Fix suspicious dereference of pointer before NULL check
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiDriver.c
1 /** @file
2 The entry point of IScsi driver.
3
4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "IScsiImpl.h"
16
17 EFI_DRIVER_BINDING_PROTOCOL gIScsiIp4DriverBinding = {
18 IScsiIp4DriverBindingSupported,
19 IScsiIp4DriverBindingStart,
20 IScsiIp4DriverBindingStop,
21 0xa,
22 NULL,
23 NULL
24 };
25
26 EFI_DRIVER_BINDING_PROTOCOL gIScsiIp6DriverBinding = {
27 IScsiIp6DriverBindingSupported,
28 IScsiIp6DriverBindingStart,
29 IScsiIp6DriverBindingStop,
30 0xa,
31 NULL,
32 NULL
33 };
34
35 EFI_GUID gIScsiV4PrivateGuid = ISCSI_V4_PRIVATE_GUID;
36 EFI_GUID gIScsiV6PrivateGuid = ISCSI_V6_PRIVATE_GUID;
37 ISCSI_PRIVATE_DATA *mPrivate = NULL;
38
39 /**
40 Tests to see if this driver supports the RemainingDevicePath.
41
42 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
43 parameter is ignored by device drivers, and is optional for bus
44 drivers. For bus drivers, if this parameter is not NULL, then
45 the bus driver must determine if the bus controller specified
46 by ControllerHandle and the child controller specified
47 by RemainingDevicePath are both supported by this
48 bus driver.
49
50 @retval EFI_SUCCESS The RemainingDevicePath is supported or NULL.
51 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
52 RemainingDevicePath is not supported by the driver specified by This.
53 **/
54 EFI_STATUS
55 IScsiIsDevicePathSupported (
56 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
57 )
58 {
59 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
60
61 CurrentDevicePath = RemainingDevicePath;
62 if (CurrentDevicePath != NULL) {
63 while (!IsDevicePathEnd (CurrentDevicePath)) {
64 if ((CurrentDevicePath->Type == MESSAGING_DEVICE_PATH) && (CurrentDevicePath->SubType == MSG_ISCSI_DP)) {
65 return EFI_SUCCESS;
66 }
67
68 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
69 }
70
71 return EFI_UNSUPPORTED;
72 }
73
74 return EFI_SUCCESS;
75 }
76
77 /**
78 Check whether an iSCSI HBA adapter already installs an AIP instance with
79 network boot policy matching the value specified in PcdIScsiAIPNetworkBootPolicy.
80 If yes, return EFI_SUCCESS.
81
82 @retval EFI_SUCCESS Found an AIP with matching network boot policy.
83 @retval EFI_NOT_FOUND AIP is unavailable or the network boot policy
84 not matched.
85 **/
86 EFI_STATUS
87 IScsiCheckAip (
88 )
89 {
90 UINTN AipHandleCount;
91 EFI_HANDLE *AipHandleBuffer;
92 UINTN AipIndex;
93 EFI_ADAPTER_INFORMATION_PROTOCOL *Aip;
94 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
95 EFI_GUID *InfoTypesBuffer;
96 UINTN InfoTypeBufferCount;
97 UINTN TypeIndex;
98 VOID *InfoBlock;
99 UINTN InfoBlockSize;
100 BOOLEAN Supported;
101 EFI_ADAPTER_INFO_NETWORK_BOOT *NetworkBoot;
102 EFI_STATUS Status;
103 UINT8 NetworkBootPolicy;
104
105 //
106 // Check any AIP instances exist in system.
107 //
108 AipHandleCount = 0;
109 AipHandleBuffer = NULL;
110 Status = gBS->LocateHandleBuffer (
111 ByProtocol,
112 &gEfiAdapterInformationProtocolGuid,
113 NULL,
114 &AipHandleCount,
115 &AipHandleBuffer
116 );
117 if (EFI_ERROR (Status) || AipHandleCount == 0) {
118 return EFI_NOT_FOUND;
119 }
120
121 ASSERT (AipHandleBuffer != NULL);
122
123 InfoBlock = NULL;
124
125 for (AipIndex = 0; AipIndex < AipHandleCount; AipIndex++) {
126 Status = gBS->HandleProtocol (
127 AipHandleBuffer[AipIndex],
128 &gEfiAdapterInformationProtocolGuid,
129 (VOID *) &Aip
130 );
131 ASSERT_EFI_ERROR (Status);
132 ASSERT (Aip != NULL);
133
134 Status = gBS->HandleProtocol (
135 AipHandleBuffer[AipIndex],
136 &gEfiExtScsiPassThruProtocolGuid,
137 (VOID *) &ExtScsiPassThru
138 );
139 if (EFI_ERROR (Status) || ExtScsiPassThru == NULL) {
140 continue;
141 }
142
143 InfoTypesBuffer = NULL;
144 InfoTypeBufferCount = 0;
145 Status = Aip->GetSupportedTypes (Aip, &InfoTypesBuffer, &InfoTypeBufferCount);
146 if (EFI_ERROR (Status) || InfoTypesBuffer == NULL) {
147 continue;
148 }
149 //
150 // Check whether the AIP instance has Network boot information block.
151 //
152 Supported = FALSE;
153 for (TypeIndex = 0; TypeIndex < InfoTypeBufferCount; TypeIndex++) {
154 if (CompareGuid (&InfoTypesBuffer[TypeIndex], &gEfiAdapterInfoNetworkBootGuid)) {
155 Supported = TRUE;
156 break;
157 }
158 }
159
160 FreePool (InfoTypesBuffer);
161 if (!Supported) {
162 continue;
163 }
164
165 //
166 // We now have network boot information block.
167 //
168 InfoBlock = NULL;
169 InfoBlockSize = 0;
170 Status = Aip->GetInformation (Aip, &gEfiAdapterInfoNetworkBootGuid, &InfoBlock, &InfoBlockSize);
171 if (EFI_ERROR (Status) || InfoBlock == NULL) {
172 continue;
173 }
174
175 //
176 // Check whether the network boot policy matches.
177 //
178 NetworkBoot = (EFI_ADAPTER_INFO_NETWORK_BOOT *) InfoBlock;
179 NetworkBootPolicy = PcdGet8 (PcdIScsiAIPNetworkBootPolicy);
180
181 if (NetworkBootPolicy == STOP_UEFI_ISCSI_IF_HBA_INSTALL_AIP) {
182 Status = EFI_SUCCESS;
183 goto Exit;
184 }
185 if (((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_SUPPORT_IP4) != 0 &&
186 !NetworkBoot->iScsiIpv4BootCapablity) ||
187 ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_SUPPORT_IP6) != 0 &&
188 !NetworkBoot->iScsiIpv6BootCapablity) ||
189 ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_SUPPORT_OFFLOAD) != 0 &&
190 !NetworkBoot->OffloadCapability) ||
191 ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_SUPPORT_MPIO) != 0 &&
192 !NetworkBoot->iScsiMpioCapability) ||
193 ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_CONFIGURED_IP4) != 0 &&
194 !NetworkBoot->iScsiIpv4Boot) ||
195 ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_CONFIGURED_IP6) != 0 &&
196 !NetworkBoot->iScsiIpv6Boot)) {
197 FreePool (InfoBlock);
198 continue;
199 }
200
201 Status = EFI_SUCCESS;
202 goto Exit;
203 }
204
205 Status = EFI_NOT_FOUND;
206
207 Exit:
208 if (InfoBlock != NULL) {
209 FreePool (InfoBlock);
210 }
211 if (AipHandleBuffer != NULL) {
212 FreePool (AipHandleBuffer);
213 }
214 return Status;
215 }
216
217 /**
218 Tests to see if this driver supports a given controller. This is the worker function for
219 IScsiIp4(6)DriverBindingSupported.
220
221 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
222 @param[in] ControllerHandle The handle of the controller to test. This handle
223 must support a protocol interface that supplies
224 an I/O abstraction to the driver.
225 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
226 parameter is ignored by device drivers, and is optional for bus
227 drivers. For bus drivers, if this parameter is not NULL, then
228 the bus driver must determine if the bus controller specified
229 by ControllerHandle and the child controller specified
230 by RemainingDevicePath are both supported by this
231 bus driver.
232 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
233
234 @retval EFI_SUCCESS The device specified by ControllerHandle and
235 RemainingDevicePath is supported by the driver specified by This.
236 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
237 RemainingDevicePath is already being managed by the driver
238 specified by This.
239 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
240 RemainingDevicePath is not supported by the driver specified by This.
241 **/
242 EFI_STATUS
243 EFIAPI
244 IScsiSupported (
245 IN EFI_DRIVER_BINDING_PROTOCOL *This,
246 IN EFI_HANDLE ControllerHandle,
247 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
248 IN UINT8 IpVersion
249 )
250 {
251 EFI_STATUS Status;
252 EFI_GUID *IScsiServiceBindingGuid;
253 EFI_GUID *TcpServiceBindingGuid;
254 EFI_GUID *DhcpServiceBindingGuid;
255
256 if (IpVersion == IP_VERSION_4) {
257 IScsiServiceBindingGuid = &gIScsiV4PrivateGuid;
258 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
259 DhcpServiceBindingGuid = &gEfiDhcp4ServiceBindingProtocolGuid;
260 } else {
261 IScsiServiceBindingGuid = &gIScsiV6PrivateGuid;
262 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
263 DhcpServiceBindingGuid = &gEfiDhcp6ServiceBindingProtocolGuid;
264 }
265
266 Status = gBS->OpenProtocol (
267 ControllerHandle,
268 IScsiServiceBindingGuid,
269 NULL,
270 This->DriverBindingHandle,
271 ControllerHandle,
272 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
273 );
274 if (!EFI_ERROR (Status)) {
275 return EFI_ALREADY_STARTED;
276 }
277
278 Status = gBS->OpenProtocol (
279 ControllerHandle,
280 TcpServiceBindingGuid,
281 NULL,
282 This->DriverBindingHandle,
283 ControllerHandle,
284 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
285 );
286 if (EFI_ERROR (Status)) {
287 return EFI_UNSUPPORTED;
288 }
289
290 Status = IScsiIsDevicePathSupported (RemainingDevicePath);
291 if (EFI_ERROR (Status)) {
292 return EFI_UNSUPPORTED;
293 }
294
295 if (IScsiDhcpIsConfigured (ControllerHandle, IpVersion)) {
296 Status = gBS->OpenProtocol (
297 ControllerHandle,
298 DhcpServiceBindingGuid,
299 NULL,
300 This->DriverBindingHandle,
301 ControllerHandle,
302 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
303 );
304 if (EFI_ERROR (Status)) {
305 return EFI_UNSUPPORTED;
306 }
307 }
308
309 return EFI_SUCCESS;
310 }
311
312
313 /**
314 Start to manage the controller. This is the worker function for
315 IScsiIp4(6)DriverBindingStart.
316
317 @param[in] Image Handle of the image.
318 @param[in] ControllerHandle Handle of the controller.
319 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
320
321 @retval EFI_SUCCES This driver was started.
322 @retval EFI_ALREADY_STARTED This driver is already running on this device.
323 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
324 @retval EFI_NOT_FOUND There is no sufficient information to establish
325 the iScsi session.
326 @retval EFI_DEVICE_ERROR Failed to get TCP connection device path.
327
328 **/
329 EFI_STATUS
330 IScsiStart (
331 IN EFI_HANDLE Image,
332 IN EFI_HANDLE ControllerHandle,
333 IN UINT8 IpVersion
334 )
335 {
336 EFI_STATUS Status;
337 ISCSI_DRIVER_DATA *Private;
338 LIST_ENTRY *Entry;
339 LIST_ENTRY *NextEntry;
340 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
341 ISCSI_SESSION *Session;
342 UINT8 Index;
343 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExistIScsiExtScsiPassThru;
344 ISCSI_DRIVER_DATA *ExistPrivate;
345 UINT8 *AttemptConfigOrder;
346 UINTN AttemptConfigOrderSize;
347 UINT8 BootSelected;
348 EFI_HANDLE *HandleBuffer;
349 UINTN NumberOfHandles;
350 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
351 EFI_GUID *IScsiPrivateGuid;
352 EFI_GUID *TcpServiceBindingGuid;
353 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];
354 BOOLEAN NeedUpdate;
355 VOID *Interface;
356 EFI_GUID *ProtocolGuid;
357 UINT8 NetworkBootPolicy;
358
359 //
360 // Test to see if iSCSI driver supports the given controller.
361 //
362
363 if (IpVersion == IP_VERSION_4) {
364 IScsiPrivateGuid = &gIScsiV4PrivateGuid;
365 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
366 ProtocolGuid = &gEfiTcp4ProtocolGuid;
367 } else if (IpVersion == IP_VERSION_6) {
368 IScsiPrivateGuid = &gIScsiV6PrivateGuid;
369 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
370 ProtocolGuid = &gEfiTcp6ProtocolGuid;
371 } else {
372 return EFI_INVALID_PARAMETER;
373 }
374
375 Status = gBS->OpenProtocol (
376 ControllerHandle,
377 IScsiPrivateGuid,
378 NULL,
379 Image,
380 ControllerHandle,
381 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
382 );
383 if (!EFI_ERROR (Status)) {
384 return EFI_ALREADY_STARTED;
385 }
386
387 Status = gBS->OpenProtocol (
388 ControllerHandle,
389 TcpServiceBindingGuid,
390 NULL,
391 Image,
392 ControllerHandle,
393 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
394 );
395 if (EFI_ERROR (Status)) {
396 return EFI_UNSUPPORTED;
397 }
398
399 NetworkBootPolicy = PcdGet8 (PcdIScsiAIPNetworkBootPolicy);
400 if (NetworkBootPolicy != ALWAYS_USE_UEFI_ISCSI_AND_IGNORE_AIP) {
401 //
402 // Check existing iSCSI AIP.
403 //
404 Status = IScsiCheckAip ();
405 if (!EFI_ERROR (Status)) {
406 //
407 // Find iSCSI AIP with specified network boot policy. return EFI_ABORTED.
408 //
409 return EFI_ABORTED;
410 }
411 }
412
413 //
414 // Record the incoming NIC info.
415 //
416 Status = IScsiAddNic (ControllerHandle);
417 if (EFI_ERROR (Status)) {
418 return Status;
419 }
420
421 //
422 // Create the instance private data.
423 //
424 Private = IScsiCreateDriverData (Image, ControllerHandle);
425 if (Private == NULL) {
426 return EFI_OUT_OF_RESOURCES;
427 }
428
429 //
430 // Create a underlayer child instance, but not need to configure it. Just open ChildHandle
431 // via BY_DRIVER. That is, establishing the relationship between ControllerHandle and ChildHandle.
432 // Therefore, when DisconnectController(), especially VLAN virtual controller handle,
433 // IScsiDriverBindingStop() will be called.
434 //
435 Status = NetLibCreateServiceChild (
436 ControllerHandle,
437 Image,
438 TcpServiceBindingGuid,
439 &Private->ChildHandle
440 );
441
442 if (EFI_ERROR (Status)) {
443 goto ON_ERROR;
444 }
445
446 Status = gBS->OpenProtocol (
447 Private->ChildHandle, /// Default Tcp child
448 ProtocolGuid,
449 &Interface,
450 Image,
451 ControllerHandle,
452 EFI_OPEN_PROTOCOL_BY_DRIVER
453 );
454
455 if (EFI_ERROR (Status)) {
456 goto ON_ERROR;
457 }
458
459 //
460 // Always install private protocol no matter what happens later. We need to
461 // keep the relationship between ControllerHandle and ChildHandle.
462 //
463 Status = gBS->InstallProtocolInterface (
464 &ControllerHandle,
465 IScsiPrivateGuid,
466 EFI_NATIVE_INTERFACE,
467 &Private->IScsiIdentifier
468 );
469 if (EFI_ERROR (Status)) {
470 goto ON_ERROR;
471 }
472
473 if (IpVersion == IP_VERSION_4) {
474 mPrivate->Ipv6Flag = FALSE;
475 } else {
476 mPrivate->Ipv6Flag = TRUE;
477 }
478
479 //
480 // Get the current iSCSI configuration data.
481 //
482 Status = IScsiGetConfigData (Private);
483 if (EFI_ERROR (Status)) {
484 goto ON_ERROR;
485 }
486
487 //
488 // If there is already a successul attempt, check whether this attempt is the
489 // first "enabled for MPIO" attempt. If not, still try the first attempt.
490 // In single path mode, try all attempts.
491 //
492 ExistPrivate = NULL;
493 Status = EFI_NOT_FOUND;
494
495 if (mPrivate->OneSessionEstablished && mPrivate->EnableMpio) {
496 AttemptConfigData = NULL;
497 NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) {
498 AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
499 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
500 break;
501 }
502 }
503
504 if (AttemptConfigData == NULL) {
505 goto ON_ERROR;
506 }
507
508 if (AttemptConfigData->AttemptConfigIndex == mPrivate->BootSelectedIndex) {
509 goto ON_EXIT;
510 }
511
512 //
513 // Uninstall the original ExtScsiPassThru first.
514 //
515
516 //
517 // Locate all ExtScsiPassThru protocol instances.
518 //
519 Status = gBS->LocateHandleBuffer (
520 ByProtocol,
521 &gEfiExtScsiPassThruProtocolGuid,
522 NULL,
523 &NumberOfHandles,
524 &HandleBuffer
525 );
526 if (EFI_ERROR (Status)) {
527 goto ON_ERROR;
528 }
529
530 //
531 // Find ExtScsiPassThru protocol instance produced by this driver.
532 //
533 ExistIScsiExtScsiPassThru = NULL;
534 for (Index = 0; Index < NumberOfHandles && ExistIScsiExtScsiPassThru == NULL; Index++) {
535 Status = gBS->HandleProtocol (
536 HandleBuffer[Index],
537 &gEfiDevicePathProtocolGuid,
538 (VOID **) &DevicePath
539 );
540 if (EFI_ERROR (Status)) {
541 continue;
542 }
543
544 while (!IsDevicePathEnd (DevicePath)) {
545 if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_MAC_ADDR_DP)) {
546 //
547 // Get the ExtScsiPassThru protocol instance.
548 //
549 Status = gBS->HandleProtocol (
550 HandleBuffer[Index],
551 &gEfiExtScsiPassThruProtocolGuid,
552 (VOID **) &ExistIScsiExtScsiPassThru
553 );
554 ASSERT_EFI_ERROR (Status);
555 break;
556 }
557
558 DevicePath = NextDevicePathNode (DevicePath);
559 }
560 }
561
562 FreePool (HandleBuffer);
563
564 if (ExistIScsiExtScsiPassThru == NULL) {
565 Status = EFI_NOT_FOUND;
566 goto ON_ERROR;
567 }
568
569 ExistPrivate = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (ExistIScsiExtScsiPassThru);
570
571 Status = gBS->UninstallProtocolInterface (
572 ExistPrivate->ExtScsiPassThruHandle,
573 &gEfiExtScsiPassThruProtocolGuid,
574 &ExistPrivate->IScsiExtScsiPassThru
575 );
576 if (EFI_ERROR (Status)) {
577 goto ON_ERROR;
578 }
579 }
580
581 //
582 // Install the Ext SCSI PASS THRU protocol.
583 //
584 Status = gBS->InstallProtocolInterface (
585 &Private->ExtScsiPassThruHandle,
586 &gEfiExtScsiPassThruProtocolGuid,
587 EFI_NATIVE_INTERFACE,
588 &Private->IScsiExtScsiPassThru
589 );
590 if (EFI_ERROR (Status)) {
591 goto ON_ERROR;
592 }
593
594 BootSelected = 0;
595
596 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {
597 AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
598 //
599 // Don't process the attempt that does not associate with the current NIC or
600 // this attempt is disabled or established.
601 //
602 if (AttemptConfigData->NicIndex != mPrivate->CurrentNic ||
603 AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED ||
604 AttemptConfigData->ValidPath) {
605 continue;
606 }
607
608 //
609 // In multipath mode, don't process attempts configured for single path.
610 // In default single path mode, don't process attempts configured for multipath.
611 //
612 if ((mPrivate->EnableMpio &&
613 AttemptConfigData->SessionConfigData.Enabled != ISCSI_ENABLED_FOR_MPIO) ||
614 (!mPrivate->EnableMpio &&
615 AttemptConfigData->SessionConfigData.Enabled != ISCSI_ENABLED)) {
616 continue;
617 }
618
619 //
620 // Don't process the attempt that fails to get the init/target information from DHCP.
621 //
622 if (AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp &&
623 !AttemptConfigData->DhcpSuccess) {
624 if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {
625 mPrivate->ValidSinglePathCount--;
626 }
627 continue;
628 }
629
630 //
631 // Don't process the autoconfigure path if it is already established.
632 //
633 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
634 AttemptConfigData->AutoConfigureSuccess) {
635 continue;
636 }
637
638 //
639 // Don't process the attempt if its IP mode is not in the current IP version.
640 //
641 if (!mPrivate->Ipv6Flag) {
642 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {
643 continue;
644 }
645 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
646 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {
647 continue;
648 }
649 } else {
650 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {
651 continue;
652 }
653 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
654 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {
655 continue;
656 }
657 }
658
659 //
660 // Fill in the Session and init it.
661 //
662 Session = (ISCSI_SESSION *) AllocateZeroPool (sizeof (ISCSI_SESSION));
663 if (Session == NULL) {
664 Status = EFI_OUT_OF_RESOURCES;
665 goto ON_ERROR;
666 }
667
668 Session->Private = Private;
669 Session->ConfigData = AttemptConfigData;
670 Session->AuthType = AttemptConfigData->AuthenticationType;
671
672 AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);
673 UnicodeSPrint (
674 mPrivate->PortString,
675 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
676 L"%s%d",
677 MacString,
678 (UINTN) AttemptConfigData->AttemptConfigIndex
679 );
680
681 if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {
682 Session->AuthData.CHAP.AuthConfig = &AttemptConfigData->AuthConfigData.CHAP;
683 }
684
685 IScsiSessionInit (Session, FALSE);
686
687 //
688 // Try to login and create an iSCSI session according to the configuration.
689 //
690 Status = IScsiSessionLogin (Session);
691 if (Status == EFI_MEDIA_CHANGED) {
692 //
693 // The specified target is not available, and the redirection information is
694 // received. Login the session again with the updated target address.
695 //
696 Status = IScsiSessionLogin (Session);
697 } else if (Status == EFI_NOT_READY) {
698 Status = IScsiSessionReLogin (Session);
699 }
700
701 if (EFI_ERROR (Status)) {
702 //
703 // In Single path mode, only the successful attempt will be recorded in iBFT;
704 // in multi-path mode, all the attempt entries in MPIO will be recorded in iBFT.
705 //
706 if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {
707 mPrivate->ValidSinglePathCount--;
708 }
709
710 FreePool (Session);
711
712 } else {
713 AttemptConfigData->ValidPath = TRUE;
714
715 //
716 // Do not record the attempt in iBFT if it login with KRB5.
717 // TODO: record KRB5 attempt information in the iSCSI device path.
718 //
719 if (Session->AuthType == ISCSI_AUTH_TYPE_KRB) {
720 if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) {
721 mPrivate->ValidSinglePathCount--;
722 }
723
724 AttemptConfigData->ValidiBFTPath = FALSE;
725 } else {
726 AttemptConfigData->ValidiBFTPath = TRUE;
727 }
728
729 //
730 // IScsi session success. Update the attempt state to NVR.
731 //
732 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
733 AttemptConfigData->AutoConfigureSuccess = TRUE;
734 }
735
736 gRT->SetVariable (
737 mPrivate->PortString,
738 &gEfiIScsiInitiatorNameProtocolGuid,
739 ISCSI_CONFIG_VAR_ATTR,
740 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
741 AttemptConfigData
742 );
743
744 //
745 // Select the first login session. Abort others.
746 //
747 if (Private->Session == NULL) {
748 Private->Session = Session;
749 BootSelected = AttemptConfigData->AttemptConfigIndex;
750 //
751 // Don't validate other attempt in multipath mode if one is success.
752 //
753 if (mPrivate->EnableMpio) {
754 break;
755 }
756 } else {
757 IScsiSessionAbort (Session);
758 FreePool (Session);
759 }
760 }
761 }
762
763 //
764 // All attempts configured for this driver instance are not valid.
765 //
766 if (Private->Session == NULL) {
767 Status = gBS->UninstallProtocolInterface (
768 Private->ExtScsiPassThruHandle,
769 &gEfiExtScsiPassThruProtocolGuid,
770 &Private->IScsiExtScsiPassThru
771 );
772 ASSERT_EFI_ERROR (Status);
773 Private->ExtScsiPassThruHandle = NULL;
774
775 //
776 // Reinstall the original ExtScsiPassThru back.
777 //
778 if (mPrivate->OneSessionEstablished && ExistPrivate != NULL) {
779 Status = gBS->InstallProtocolInterface (
780 &ExistPrivate->ExtScsiPassThruHandle,
781 &gEfiExtScsiPassThruProtocolGuid,
782 EFI_NATIVE_INTERFACE,
783 &ExistPrivate->IScsiExtScsiPassThru
784 );
785 if (EFI_ERROR (Status)) {
786 goto ON_ERROR;
787 }
788
789 goto ON_EXIT;
790 }
791
792 Status = EFI_NOT_FOUND;
793
794 goto ON_ERROR;
795 }
796
797 NeedUpdate = TRUE;
798 //
799 // More than one attempt successes.
800 //
801 if (Private->Session != NULL && mPrivate->OneSessionEstablished) {
802
803 AttemptConfigOrder = IScsiGetVariableAndSize (
804 L"AttemptOrder",
805 &gIScsiConfigGuid,
806 &AttemptConfigOrderSize
807 );
808 if (AttemptConfigOrder == NULL) {
809 goto ON_ERROR;
810 }
811 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
812 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex ||
813 AttemptConfigOrder[Index] == BootSelected) {
814 break;
815 }
816 }
817
818 if (mPrivate->EnableMpio) {
819 //
820 // Use the attempt in earlier order. Abort the later one in MPIO.
821 //
822 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {
823 IScsiSessionAbort (Private->Session);
824 FreePool (Private->Session);
825 Private->Session = NULL;
826 gBS->UninstallProtocolInterface (
827 Private->ExtScsiPassThruHandle,
828 &gEfiExtScsiPassThruProtocolGuid,
829 &Private->IScsiExtScsiPassThru
830 );
831 Private->ExtScsiPassThruHandle = NULL;
832
833 //
834 // Reinstall the original ExtScsiPassThru back.
835 //
836 Status = gBS->InstallProtocolInterface (
837 &ExistPrivate->ExtScsiPassThruHandle,
838 &gEfiExtScsiPassThruProtocolGuid,
839 EFI_NATIVE_INTERFACE,
840 &ExistPrivate->IScsiExtScsiPassThru
841 );
842 if (EFI_ERROR (Status)) {
843 goto ON_ERROR;
844 }
845
846 goto ON_EXIT;
847 } else {
848 if (AttemptConfigOrder[Index] != BootSelected) {
849 goto ON_ERROR;
850 }
851 mPrivate->BootSelectedIndex = BootSelected;
852 //
853 // Clear the resource in ExistPrivate.
854 //
855 gBS->UninstallProtocolInterface (
856 ExistPrivate->Controller,
857 IScsiPrivateGuid,
858 &ExistPrivate->IScsiIdentifier
859 );
860
861 IScsiRemoveNic (ExistPrivate->Controller);
862 if (ExistPrivate->Session != NULL) {
863 IScsiSessionAbort (ExistPrivate->Session);
864 }
865
866 IScsiCleanDriverData (ExistPrivate);
867 }
868 } else {
869 //
870 // Use the attempt in earlier order as boot selected in single path mode.
871 //
872 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {
873 NeedUpdate = FALSE;
874 }
875 }
876
877 }
878
879 if (NeedUpdate) {
880 mPrivate->OneSessionEstablished = TRUE;
881 mPrivate->BootSelectedIndex = BootSelected;
882 }
883
884 //
885 // Duplicate the Session's tcp connection device path. The source port field
886 // will be set to zero as one iSCSI session is comprised of several iSCSI
887 // connections.
888 //
889 Private->DevicePath = IScsiGetTcpConnDevicePath (Private->Session);
890 if (Private->DevicePath == NULL) {
891 Status = EFI_DEVICE_ERROR;
892 goto ON_ERROR;
893 }
894 //
895 // Install the updated device path onto the ExtScsiPassThruHandle.
896 //
897 Status = gBS->InstallProtocolInterface (
898 &Private->ExtScsiPassThruHandle,
899 &gEfiDevicePathProtocolGuid,
900 EFI_NATIVE_INTERFACE,
901 Private->DevicePath
902 );
903 if (EFI_ERROR (Status)) {
904 goto ON_ERROR;
905 }
906
907 //
908 // ISCSI children should share the default Tcp child, just open the default Tcp child via BY_CHILD_CONTROLLER.
909 //
910 Status = gBS->OpenProtocol (
911 Private->ChildHandle, /// Default Tcp child
912 ProtocolGuid,
913 &Interface,
914 Image,
915 Private->ExtScsiPassThruHandle,
916 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
917 );
918 if (EFI_ERROR (Status)) {
919 gBS->UninstallMultipleProtocolInterfaces (
920 Private->ExtScsiPassThruHandle,
921 &gEfiExtScsiPassThruProtocolGuid,
922 &Private->IScsiExtScsiPassThru,
923 &gEfiDevicePathProtocolGuid,
924 Private->DevicePath,
925 NULL
926 );
927
928 goto ON_ERROR;
929 }
930
931 ON_EXIT:
932
933 //
934 // Update/Publish the iSCSI Boot Firmware Table.
935 //
936 if (mPrivate->BootSelectedIndex != 0) {
937 IScsiPublishIbft ();
938 }
939
940 return EFI_SUCCESS;
941
942 ON_ERROR:
943
944 if (Private->Session != NULL) {
945 IScsiSessionAbort (Private->Session);
946 }
947
948 return Status;
949 }
950
951 /**
952 Stops a device controller or a bus controller. This is the worker function for
953 IScsiIp4(6)DriverBindingStop.
954
955 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
956 @param[in] ControllerHandle A handle to the device being stopped. The handle must
957 support a bus specific I/O protocol for the driver
958 to use to stop the device.
959 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
960 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
961 if NumberOfChildren is 0.
962 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
963
964 @retval EFI_SUCCESS The device was stopped.
965 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
966
967 **/
968 EFI_STATUS
969 EFIAPI
970 IScsiStop (
971 IN EFI_DRIVER_BINDING_PROTOCOL *This,
972 IN EFI_HANDLE ControllerHandle,
973 IN UINTN NumberOfChildren,
974 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL,
975 IN UINT8 IpVersion
976 )
977 {
978 EFI_HANDLE IScsiController;
979 EFI_STATUS Status;
980 ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier;
981 ISCSI_DRIVER_DATA *Private;
982 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
983 ISCSI_CONNECTION *Conn;
984 EFI_GUID *ProtocolGuid;
985 EFI_GUID *TcpServiceBindingGuid;
986 EFI_GUID *TcpProtocolGuid;
987
988
989 if (NumberOfChildren != 0) {
990 //
991 // We should have only one child.
992 //
993 Status = gBS->OpenProtocol (
994 ChildHandleBuffer[0],
995 &gEfiExtScsiPassThruProtocolGuid,
996 (VOID **) &PassThru,
997 This->DriverBindingHandle,
998 ControllerHandle,
999 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1000 );
1001 if (EFI_ERROR (Status)) {
1002 return EFI_DEVICE_ERROR;
1003 }
1004
1005 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);
1006 Conn = NET_LIST_HEAD (&Private->Session->Conns, ISCSI_CONNECTION, Link);
1007
1008 //
1009 // Previously the TCP protocol is opened BY_CHILD_CONTROLLER. Just close
1010 // the protocol here, but do not uninstall the device path protocol and
1011 // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.
1012 //
1013 if (IpVersion == IP_VERSION_4) {
1014 ProtocolGuid = &gEfiTcp4ProtocolGuid;
1015 } else {
1016 ProtocolGuid = &gEfiTcp6ProtocolGuid;
1017 }
1018
1019 gBS->CloseProtocol (
1020 Private->ChildHandle,
1021 ProtocolGuid,
1022 Private->Image,
1023 Private->ExtScsiPassThruHandle
1024 );
1025
1026 gBS->CloseProtocol (
1027 Conn->TcpIo.Handle,
1028 ProtocolGuid,
1029 Private->Image,
1030 Private->ExtScsiPassThruHandle
1031 );
1032
1033 return EFI_SUCCESS;
1034 }
1035
1036 //
1037 // Get the handle of the controller we are controling.
1038 //
1039 if (IpVersion == IP_VERSION_4) {
1040 ProtocolGuid = &gIScsiV4PrivateGuid;
1041 TcpProtocolGuid = &gEfiTcp4ProtocolGuid;
1042 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
1043 } else {
1044 ProtocolGuid = &gIScsiV6PrivateGuid;
1045 TcpProtocolGuid = &gEfiTcp6ProtocolGuid;
1046 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
1047 }
1048 IScsiController = NetLibGetNicHandle (ControllerHandle, TcpProtocolGuid);
1049 if (IScsiController == NULL) {
1050 return EFI_SUCCESS;
1051 }
1052
1053 Status = gBS->OpenProtocol (
1054 IScsiController,
1055 ProtocolGuid,
1056 (VOID **) &IScsiIdentifier,
1057 This->DriverBindingHandle,
1058 ControllerHandle,
1059 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1060 );
1061 if (EFI_ERROR (Status)) {
1062 return EFI_DEVICE_ERROR;
1063 }
1064
1065 Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);
1066 ASSERT (Private != NULL);
1067
1068 if (Private->ChildHandle != NULL) {
1069 Status = gBS->CloseProtocol (
1070 Private->ChildHandle,
1071 TcpProtocolGuid,
1072 This->DriverBindingHandle,
1073 IScsiController
1074 );
1075
1076 ASSERT (!EFI_ERROR (Status));
1077
1078 Status = NetLibDestroyServiceChild (
1079 IScsiController,
1080 This->DriverBindingHandle,
1081 TcpServiceBindingGuid,
1082 Private->ChildHandle
1083 );
1084
1085 ASSERT (!EFI_ERROR (Status));
1086 }
1087
1088 gBS->UninstallProtocolInterface (
1089 IScsiController,
1090 ProtocolGuid,
1091 &Private->IScsiIdentifier
1092 );
1093
1094 //
1095 // Remove this NIC.
1096 //
1097 IScsiRemoveNic (IScsiController);
1098
1099 //
1100 // Update the iSCSI Boot Firware Table.
1101 //
1102 IScsiPublishIbft ();
1103
1104 if (Private->Session != NULL) {
1105 IScsiSessionAbort (Private->Session);
1106 }
1107
1108 IScsiCleanDriverData (Private);
1109
1110 return EFI_SUCCESS;
1111 }
1112
1113 /**
1114 Tests to see if this driver supports a given controller. If a child device is provided,
1115 it tests to see if this driver supports creating a handle for the specified child device.
1116
1117 This function checks to see if the driver specified by This supports the device specified by
1118 ControllerHandle. Drivers typically use the device path attached to
1119 ControllerHandle and/or the services from the bus I/O abstraction attached to
1120 ControllerHandle to determine if the driver supports ControllerHandle. This function
1121 may be called many times during platform initialization. In order to reduce boot times, the tests
1122 performed by this function must be very small and take as little time as possible to execute. This
1123 function must not change the state of any hardware devices, and this function must be aware that the
1124 device specified by ControllerHandle may already be managed by the same driver or a
1125 different driver. This function must match its calls to AllocatePages() with FreePages(),
1126 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
1127 Since ControllerHandle may have been previously started by the same driver, if a protocol is
1128 already in the opened state, then it must not be closed with CloseProtocol(). This is required
1129 to guarantee the state of ControllerHandle is not modified by this function.
1130
1131 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1132 @param[in] ControllerHandle The handle of the controller to test. This handle
1133 must support a protocol interface that supplies
1134 an I/O abstraction to the driver.
1135 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
1136 parameter is ignored by device drivers, and is optional for bus
1137 drivers. For bus drivers, if this parameter is not NULL, then
1138 the bus driver must determine if the bus controller specified
1139 by ControllerHandle and the child controller specified
1140 by RemainingDevicePath are both supported by this
1141 bus driver.
1142
1143 @retval EFI_SUCCESS The device specified by ControllerHandle and
1144 RemainingDevicePath is supported by the driver specified by This.
1145 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
1146 RemainingDevicePath is already managed by the driver
1147 specified by This.
1148 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
1149 RemainingDevicePath is already managed by a different
1150 driver or an application that requires exclusive access.
1151 Currently not implemented.
1152 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
1153 RemainingDevicePath is not supported by the driver specified by This.
1154 **/
1155 EFI_STATUS
1156 EFIAPI
1157 IScsiIp4DriverBindingSupported (
1158 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1159 IN EFI_HANDLE ControllerHandle,
1160 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1161 )
1162 {
1163 return IScsiSupported (
1164 This,
1165 ControllerHandle,
1166 RemainingDevicePath,
1167 IP_VERSION_4
1168 );
1169 }
1170
1171 /**
1172 Starts a device controller or a bus controller.
1173
1174 The Start() function is designed to be invoked from the EFI boot service ConnectController().
1175 As a result, much of the error checking on the parameters to Start() has been moved into this
1176 common boot service. It is legal to call Start() from other locations,
1177 but the following calling restrictions must be followed or the system behavior will not be deterministic.
1178 1. ControllerHandle must be a valid EFI_HANDLE.
1179 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
1180 EFI_DEVICE_PATH_PROTOCOL.
1181 3. Prior to calling Start(), the Supported() function for the driver specified by This must
1182 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
1183
1184 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1185 @param[in] ControllerHandle The handle of the controller to start. This handle
1186 must support a protocol interface that supplies
1187 an I/O abstraction to the driver.
1188 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
1189 parameter is ignored by device drivers, and is optional for bus
1190 drivers. For a bus driver, if this parameter is NULL, then handles
1191 for all the children of Controller are created by this driver.
1192 If this parameter is not NULL and the first Device Path Node is
1193 not the End of Device Path Node, then only the handle for the
1194 child device specified by the first Device Path Node of
1195 RemainingDevicePath is created by this driver.
1196 If the first Device Path Node of RemainingDevicePath is
1197 the End of Device Path Node, no child handle is created by this
1198 driver.
1199
1200 @retval EFI_SUCCESS The device was started.
1201 @retval EFI_DEVICE_ERROR The device could not be started due to a device error. Currently not implemented.
1202 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1203 @retval Others The driver failed to start the device.
1204
1205 **/
1206 EFI_STATUS
1207 EFIAPI
1208 IScsiIp4DriverBindingStart (
1209 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1210 IN EFI_HANDLE ControllerHandle,
1211 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1212 )
1213 {
1214 EFI_STATUS Status;
1215
1216 Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_4);
1217 if (Status == EFI_ALREADY_STARTED) {
1218 Status = EFI_SUCCESS;
1219 }
1220
1221 return Status;
1222 }
1223
1224 /**
1225 Stops a device controller or a bus controller.
1226
1227 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
1228 As a result, much of the error checking on the parameters to Stop() has been moved
1229 into this common boot service. It is legal to call Stop() from other locations,
1230 but the following calling restrictions must be followed or the system behavior will not be deterministic.
1231 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
1232 same driver's Start() function.
1233 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
1234 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
1235 Start() function, and the Start() function must have called OpenProtocol() on
1236 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
1237
1238 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1239 @param[in] ControllerHandle A handle to the device being stopped. The handle must
1240 support a bus specific I/O protocol for the driver
1241 to use to stop the device.
1242 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
1243 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1244 if NumberOfChildren is 0.
1245
1246 @retval EFI_SUCCESS The device was stopped.
1247 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
1248
1249 **/
1250 EFI_STATUS
1251 EFIAPI
1252 IScsiIp4DriverBindingStop (
1253 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1254 IN EFI_HANDLE ControllerHandle,
1255 IN UINTN NumberOfChildren,
1256 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
1257 )
1258 {
1259 return IScsiStop (
1260 This,
1261 ControllerHandle,
1262 NumberOfChildren,
1263 ChildHandleBuffer,
1264 IP_VERSION_4
1265 );
1266 }
1267
1268 /**
1269 Tests to see if this driver supports a given controller. If a child device is provided,
1270 it tests to see if this driver supports creating a handle for the specified child device.
1271
1272 This function checks to see if the driver specified by This supports the device specified by
1273 ControllerHandle. Drivers typically use the device path attached to
1274 ControllerHandle and/or the services from the bus I/O abstraction attached to
1275 ControllerHandle to determine if the driver supports ControllerHandle. This function
1276 may be called many times during platform initialization. In order to reduce boot times, the tests
1277 performed by this function must be very small and take as little time as possible to execute. This
1278 function must not change the state of any hardware devices, and this function must be aware that the
1279 device specified by ControllerHandle may already be managed by the same driver or a
1280 different driver. This function must match its calls to AllocatePages() with FreePages(),
1281 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
1282 Since ControllerHandle may have been previously started by the same driver, if a protocol is
1283 already in the opened state, then it must not be closed with CloseProtocol(). This is required
1284 to guarantee the state of ControllerHandle is not modified by this function.
1285
1286 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1287 @param[in] ControllerHandle The handle of the controller to test. This handle
1288 must support a protocol interface that supplies
1289 an I/O abstraction to the driver.
1290 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
1291 parameter is ignored by device drivers, and is optional for bus
1292 drivers. For bus drivers, if this parameter is not NULL, then
1293 the bus driver must determine if the bus controller specified
1294 by ControllerHandle and the child controller specified
1295 by RemainingDevicePath are both supported by this
1296 bus driver.
1297
1298 @retval EFI_SUCCESS The device specified by ControllerHandle and
1299 RemainingDevicePath is supported by the driver specified by This.
1300 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
1301 RemainingDevicePath is already managed by the driver
1302 specified by This.
1303 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
1304 RemainingDevicePath is already managed by a different
1305 driver or an application that requires exclusive access.
1306 Currently not implemented.
1307 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
1308 RemainingDevicePath is not supported by the driver specified by This.
1309 **/
1310 EFI_STATUS
1311 EFIAPI
1312 IScsiIp6DriverBindingSupported (
1313 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1314 IN EFI_HANDLE ControllerHandle,
1315 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1316 )
1317 {
1318 return IScsiSupported (
1319 This,
1320 ControllerHandle,
1321 RemainingDevicePath,
1322 IP_VERSION_6
1323 );
1324 }
1325
1326 /**
1327 Starts a device controller or a bus controller.
1328
1329 The Start() function is designed to be invoked from the EFI boot service ConnectController().
1330 As a result, much of the error checking on the parameters to Start() has been moved into this
1331 common boot service. It is legal to call Start() from other locations,
1332 but the following calling restrictions must be followed or the system behavior will not be deterministic.
1333 1. ControllerHandle must be a valid EFI_HANDLE.
1334 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
1335 EFI_DEVICE_PATH_PROTOCOL.
1336 3. Prior to calling Start(), the Supported() function for the driver specified by This must
1337 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
1338
1339 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1340 @param[in] ControllerHandle The handle of the controller to start. This handle
1341 must support a protocol interface that supplies
1342 an I/O abstraction to the driver.
1343 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
1344 parameter is ignored by device drivers, and is optional for bus
1345 drivers. For a bus driver, if this parameter is NULL, then handles
1346 for all the children of Controller are created by this driver.
1347 If this parameter is not NULL and the first Device Path Node is
1348 not the End of Device Path Node, then only the handle for the
1349 child device specified by the first Device Path Node of
1350 RemainingDevicePath is created by this driver.
1351 If the first Device Path Node of RemainingDevicePath is
1352 the End of Device Path Node, no child handle is created by this
1353 driver.
1354
1355 @retval EFI_SUCCESS The device was started.
1356 @retval EFI_DEVICE_ERROR The device could not be started due to a device error. Currently not implemented.
1357 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1358 @retval Others The driver failed to start the device.
1359
1360 **/
1361 EFI_STATUS
1362 EFIAPI
1363 IScsiIp6DriverBindingStart (
1364 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1365 IN EFI_HANDLE ControllerHandle,
1366 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1367 )
1368 {
1369 EFI_STATUS Status;
1370
1371 Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_6);
1372 if (Status == EFI_ALREADY_STARTED) {
1373 Status = EFI_SUCCESS;
1374 }
1375
1376 return Status;
1377 }
1378
1379 /**
1380 Stops a device controller or a bus controller.
1381
1382 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
1383 As a result, much of the error checking on the parameters to Stop() has been moved
1384 into this common boot service. It is legal to call Stop() from other locations,
1385 but the following calling restrictions must be followed or the system behavior will not be deterministic.
1386 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
1387 same driver's Start() function.
1388 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
1389 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
1390 Start() function, and the Start() function must have called OpenProtocol() on
1391 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
1392
1393 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1394 @param[in] ControllerHandle A handle to the device being stopped. The handle must
1395 support a bus specific I/O protocol for the driver
1396 to use to stop the device.
1397 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
1398 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1399 if NumberOfChildren is 0.
1400
1401 @retval EFI_SUCCESS The device was stopped.
1402 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
1403
1404 **/
1405 EFI_STATUS
1406 EFIAPI
1407 IScsiIp6DriverBindingStop (
1408 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1409 IN EFI_HANDLE ControllerHandle,
1410 IN UINTN NumberOfChildren,
1411 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
1412 )
1413 {
1414 return IScsiStop (
1415 This,
1416 ControllerHandle,
1417 NumberOfChildren,
1418 ChildHandleBuffer,
1419 IP_VERSION_6
1420 );
1421 }
1422
1423 /**
1424 Unload the iSCSI driver.
1425
1426 @param[in] ImageHandle The handle of the driver image.
1427
1428 @retval EFI_SUCCESS The driver is unloaded.
1429 @retval EFI_DEVICE_ERROR An unexpected error occurred.
1430
1431 **/
1432 EFI_STATUS
1433 EFIAPI
1434 IScsiUnload (
1435 IN EFI_HANDLE ImageHandle
1436 )
1437 {
1438 EFI_STATUS Status;
1439 UINTN DeviceHandleCount;
1440 EFI_HANDLE *DeviceHandleBuffer;
1441 UINTN Index;
1442 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
1443 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
1444
1445 //
1446 // Try to disonnect the driver from the devices it's controlling.
1447 //
1448 Status = gBS->LocateHandleBuffer (
1449 AllHandles,
1450 NULL,
1451 NULL,
1452 &DeviceHandleCount,
1453 &DeviceHandleBuffer
1454 );
1455 if (EFI_ERROR (Status)) {
1456 return Status;
1457 }
1458
1459 //
1460 // Disconnect the iSCSI4 driver from the controlled device.
1461 //
1462 for (Index = 0; Index < DeviceHandleCount; Index++) {
1463 Status = IScsiTestManagedDevice (
1464 DeviceHandleBuffer[Index],
1465 gIScsiIp4DriverBinding.DriverBindingHandle,
1466 &gEfiTcp4ProtocolGuid)
1467 ;
1468 if (EFI_ERROR (Status)) {
1469 continue;
1470 }
1471 Status = gBS->DisconnectController (
1472 DeviceHandleBuffer[Index],
1473 gIScsiIp4DriverBinding.DriverBindingHandle,
1474 NULL
1475 );
1476 if (EFI_ERROR (Status)) {
1477 goto ON_EXIT;
1478 }
1479 }
1480
1481 //
1482 // Disconnect the iSCSI6 driver from the controlled device.
1483 //
1484 for (Index = 0; Index < DeviceHandleCount; Index++) {
1485 Status = IScsiTestManagedDevice (
1486 DeviceHandleBuffer[Index],
1487 gIScsiIp6DriverBinding.DriverBindingHandle,
1488 &gEfiTcp6ProtocolGuid
1489 );
1490 if (EFI_ERROR (Status)) {
1491 continue;
1492 }
1493 Status = gBS->DisconnectController (
1494 DeviceHandleBuffer[Index],
1495 gIScsiIp6DriverBinding.DriverBindingHandle,
1496 NULL
1497 );
1498 if (EFI_ERROR (Status)) {
1499 goto ON_EXIT;
1500 }
1501 }
1502
1503 //
1504 // Unload the iSCSI configuration form.
1505 //
1506 Status = IScsiConfigFormUnload (gIScsiIp4DriverBinding.DriverBindingHandle);
1507 if (EFI_ERROR (Status)) {
1508 goto ON_EXIT;
1509 }
1510
1511 //
1512 // Uninstall the protocols installed by iSCSI driver.
1513 //
1514 Status = gBS->UninstallMultipleProtocolInterfaces (
1515 ImageHandle,
1516 &gEfiAuthenticationInfoProtocolGuid,
1517 &gIScsiAuthenticationInfo,
1518 NULL
1519 );
1520 if (EFI_ERROR (Status)) {
1521 goto ON_EXIT;
1522 }
1523
1524 if (gIScsiControllerNameTable!= NULL) {
1525 Status = FreeUnicodeStringTable (gIScsiControllerNameTable);
1526 if (EFI_ERROR (Status)) {
1527 goto ON_EXIT;
1528 }
1529 gIScsiControllerNameTable = NULL;
1530 }
1531
1532 //
1533 // Uninstall the ComponentName and ComponentName2 protocol from iSCSI4 driver binding handle
1534 // if it has been installed.
1535 //
1536 Status = gBS->HandleProtocol (
1537 gIScsiIp4DriverBinding.DriverBindingHandle,
1538 &gEfiComponentNameProtocolGuid,
1539 (VOID **) &ComponentName
1540 );
1541 if (!EFI_ERROR (Status)) {
1542 Status = gBS->UninstallMultipleProtocolInterfaces (
1543 gIScsiIp4DriverBinding.DriverBindingHandle,
1544 &gEfiComponentNameProtocolGuid,
1545 ComponentName,
1546 NULL
1547 );
1548 if (EFI_ERROR (Status)) {
1549 goto ON_EXIT;
1550 }
1551 }
1552
1553 Status = gBS->HandleProtocol (
1554 gIScsiIp4DriverBinding.DriverBindingHandle,
1555 &gEfiComponentName2ProtocolGuid,
1556 (VOID **) &ComponentName2
1557 );
1558 if (!EFI_ERROR (Status)) {
1559 gBS->UninstallMultipleProtocolInterfaces (
1560 gIScsiIp4DriverBinding.DriverBindingHandle,
1561 &gEfiComponentName2ProtocolGuid,
1562 ComponentName2,
1563 NULL
1564 );
1565 if (EFI_ERROR (Status)) {
1566 goto ON_EXIT;
1567 }
1568 }
1569
1570 //
1571 // Uninstall the ComponentName and ComponentName2 protocol from iSCSI6 driver binding handle
1572 // if it has been installed.
1573 //
1574 Status = gBS->HandleProtocol (
1575 gIScsiIp6DriverBinding.DriverBindingHandle,
1576 &gEfiComponentNameProtocolGuid,
1577 (VOID **) &ComponentName
1578 );
1579 if (!EFI_ERROR (Status)) {
1580 Status = gBS->UninstallMultipleProtocolInterfaces (
1581 gIScsiIp6DriverBinding.DriverBindingHandle,
1582 &gEfiComponentNameProtocolGuid,
1583 ComponentName,
1584 NULL
1585 );
1586 if (EFI_ERROR (Status)) {
1587 goto ON_EXIT;
1588 }
1589 }
1590
1591 Status = gBS->HandleProtocol (
1592 gIScsiIp6DriverBinding.DriverBindingHandle,
1593 &gEfiComponentName2ProtocolGuid,
1594 (VOID **) &ComponentName2
1595 );
1596 if (!EFI_ERROR (Status)) {
1597 gBS->UninstallMultipleProtocolInterfaces (
1598 gIScsiIp6DriverBinding.DriverBindingHandle,
1599 &gEfiComponentName2ProtocolGuid,
1600 ComponentName2,
1601 NULL
1602 );
1603 if (EFI_ERROR (Status)) {
1604 goto ON_EXIT;
1605 }
1606 }
1607
1608 //
1609 // Uninstall the IScsiInitiatorNameProtocol and all the driver binding protocols.
1610 //
1611 Status = gBS->UninstallMultipleProtocolInterfaces (
1612 gIScsiIp4DriverBinding.DriverBindingHandle,
1613 &gEfiDriverBindingProtocolGuid,
1614 &gIScsiIp4DriverBinding,
1615 &gEfiIScsiInitiatorNameProtocolGuid,
1616 &gIScsiInitiatorName,
1617 NULL
1618 );
1619 if (EFI_ERROR (Status)) {
1620 goto ON_EXIT;
1621 }
1622
1623 Status = gBS->UninstallMultipleProtocolInterfaces (
1624 gIScsiIp6DriverBinding.DriverBindingHandle,
1625 &gEfiDriverBindingProtocolGuid,
1626 &gIScsiIp6DriverBinding,
1627 NULL
1628 );
1629
1630 ON_EXIT:
1631
1632 if (DeviceHandleBuffer != NULL) {
1633 FreePool (DeviceHandleBuffer);
1634 }
1635
1636 return Status;
1637 }
1638
1639 /**
1640 This is the declaration of an EFI image entry point. This entry point is
1641 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
1642 both device drivers and bus drivers.
1643
1644 The entry point for iSCSI driver which initializes the global variables and
1645 installs the driver binding, component name protocol, iSCSI initiator name
1646 protocol and Authentication Info protocol on its image.
1647
1648 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
1649 @param[in] SystemTable A pointer to the EFI System Table.
1650
1651 @retval EFI_SUCCESS The operation completed successfully.
1652 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1653
1654 **/
1655 EFI_STATUS
1656 EFIAPI
1657 IScsiDriverEntryPoint (
1658 IN EFI_HANDLE ImageHandle,
1659 IN EFI_SYSTEM_TABLE *SystemTable
1660 )
1661 {
1662 EFI_STATUS Status;
1663 EFI_ISCSI_INITIATOR_NAME_PROTOCOL *IScsiInitiatorName;
1664 EFI_AUTHENTICATION_INFO_PROTOCOL *AuthenticationInfo;
1665
1666 //
1667 // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.
1668 //
1669 Status = gBS->LocateProtocol (
1670 &gEfiIScsiInitiatorNameProtocolGuid,
1671 NULL,
1672 (VOID **) &IScsiInitiatorName
1673 );
1674 if (!EFI_ERROR (Status)) {
1675 return EFI_ACCESS_DENIED;
1676 }
1677
1678 //
1679 // Initialize the EFI Driver Library.
1680 //
1681 Status = EfiLibInstallDriverBindingComponentName2 (
1682 ImageHandle,
1683 SystemTable,
1684 &gIScsiIp4DriverBinding,
1685 ImageHandle,
1686 &gIScsiComponentName,
1687 &gIScsiComponentName2
1688 );
1689 if (EFI_ERROR (Status)) {
1690 return Status;
1691 }
1692
1693 Status = EfiLibInstallDriverBindingComponentName2 (
1694 ImageHandle,
1695 SystemTable,
1696 &gIScsiIp6DriverBinding,
1697 NULL,
1698 &gIScsiComponentName,
1699 &gIScsiComponentName2
1700 );
1701 if (EFI_ERROR (Status)) {
1702 goto Error1;
1703 }
1704
1705 //
1706 // Install the iSCSI Initiator Name Protocol.
1707 //
1708 Status = gBS->InstallProtocolInterface (
1709 &ImageHandle,
1710 &gEfiIScsiInitiatorNameProtocolGuid,
1711 EFI_NATIVE_INTERFACE,
1712 &gIScsiInitiatorName
1713 );
1714 if (EFI_ERROR (Status)) {
1715 goto Error2;
1716 }
1717
1718 //
1719 // Create the private data structures.
1720 //
1721 mPrivate = AllocateZeroPool (sizeof (ISCSI_PRIVATE_DATA));
1722 if (mPrivate == NULL) {
1723 Status = EFI_OUT_OF_RESOURCES;
1724 goto Error3;
1725 }
1726
1727 InitializeListHead (&mPrivate->NicInfoList);
1728 InitializeListHead (&mPrivate->AttemptConfigs);
1729
1730 //
1731 // Initialize the configuration form of iSCSI.
1732 //
1733 Status = IScsiConfigFormInit (gIScsiIp4DriverBinding.DriverBindingHandle);
1734 if (EFI_ERROR (Status)) {
1735 goto Error4;
1736 }
1737
1738 //
1739 // There should be only one EFI_AUTHENTICATION_INFO_PROTOCOL. If already exists,
1740 // do not produce the protocol instance.
1741 //
1742 Status = gBS->LocateProtocol (
1743 &gEfiAuthenticationInfoProtocolGuid,
1744 NULL,
1745 (VOID **) &AuthenticationInfo
1746 );
1747 if (Status == EFI_NOT_FOUND) {
1748 Status = gBS->InstallProtocolInterface (
1749 &ImageHandle,
1750 &gEfiAuthenticationInfoProtocolGuid,
1751 EFI_NATIVE_INTERFACE,
1752 &gIScsiAuthenticationInfo
1753 );
1754 if (EFI_ERROR (Status)) {
1755 goto Error5;
1756 }
1757 }
1758
1759 return EFI_SUCCESS;
1760
1761 Error5:
1762 IScsiConfigFormUnload (gIScsiIp4DriverBinding.DriverBindingHandle);
1763
1764 Error4:
1765 FreePool (mPrivate);
1766
1767 Error3:
1768 gBS->UninstallMultipleProtocolInterfaces (
1769 ImageHandle,
1770 &gEfiIScsiInitiatorNameProtocolGuid,
1771 &gIScsiInitiatorName,
1772 NULL
1773 );
1774
1775 Error2:
1776 gBS->UninstallMultipleProtocolInterfaces (
1777 gIScsiIp6DriverBinding.DriverBindingHandle,
1778 &gEfiDriverBindingProtocolGuid,
1779 &gIScsiIp6DriverBinding,
1780 &gEfiComponentName2ProtocolGuid,
1781 &gIScsiComponentName2,
1782 &gEfiComponentNameProtocolGuid,
1783 &gIScsiComponentName,
1784 NULL
1785 );
1786
1787 Error1:
1788 gBS->UninstallMultipleProtocolInterfaces (
1789 ImageHandle,
1790 &gEfiDriverBindingProtocolGuid,
1791 &gIScsiIp4DriverBinding,
1792 &gEfiComponentName2ProtocolGuid,
1793 &gIScsiComponentName2,
1794 &gEfiComponentNameProtocolGuid,
1795 &gIScsiComponentName,
1796 NULL
1797 );
1798
1799 return Status;
1800 }
1801