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