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