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