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