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