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