]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/IScsiDxe/IScsiDriver.c
MdeModulePkg: Update DSC file to fix build failure in EBC.
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiDriver.c
1 /** @file
2 The entry point of IScsi driver.
3
4 Copyright (c) 2004 - 2014, 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 if (AttemptConfigOrder == NULL) {
655 goto ON_ERROR;
656 }
657 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
658 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex ||
659 AttemptConfigOrder[Index] == BootSelected) {
660 break;
661 }
662 }
663
664 if (mPrivate->EnableMpio) {
665 //
666 // Use the attempt in earlier order. Abort the later one in MPIO.
667 //
668 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {
669 IScsiSessionAbort (Private->Session);
670 FreePool (Private->Session);
671 Private->Session = NULL;
672 gBS->UninstallProtocolInterface (
673 Private->ExtScsiPassThruHandle,
674 &gEfiExtScsiPassThruProtocolGuid,
675 &Private->IScsiExtScsiPassThru
676 );
677 Private->ExtScsiPassThruHandle = NULL;
678
679 //
680 // Reinstall the original ExtScsiPassThru back.
681 //
682 Status = gBS->InstallProtocolInterface (
683 &ExistPrivate->ExtScsiPassThruHandle,
684 &gEfiExtScsiPassThruProtocolGuid,
685 EFI_NATIVE_INTERFACE,
686 &ExistPrivate->IScsiExtScsiPassThru
687 );
688 if (EFI_ERROR (Status)) {
689 goto ON_ERROR;
690 }
691
692 goto ON_EXIT;
693 } else {
694 if (AttemptConfigOrder[Index] != BootSelected) {
695 goto ON_ERROR;
696 }
697 mPrivate->BootSelectedIndex = BootSelected;
698 //
699 // Clear the resource in ExistPrivate.
700 //
701 gBS->UninstallProtocolInterface (
702 ExistPrivate->Controller,
703 IScsiPrivateGuid,
704 &ExistPrivate->IScsiIdentifier
705 );
706
707 IScsiRemoveNic (ExistPrivate->Controller);
708 if (ExistPrivate->Session != NULL) {
709 IScsiSessionAbort (ExistPrivate->Session);
710 }
711
712 IScsiCleanDriverData (ExistPrivate);
713 }
714 } else {
715 //
716 // Use the attempt in earlier order as boot selected in single path mode.
717 //
718 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) {
719 NeedUpdate = FALSE;
720 }
721 }
722
723 }
724
725 if (NeedUpdate) {
726 mPrivate->OneSessionEstablished = TRUE;
727 mPrivate->BootSelectedIndex = BootSelected;
728 }
729
730 //
731 // Duplicate the Session's tcp connection device path. The source port field
732 // will be set to zero as one iSCSI session is comprised of several iSCSI
733 // connections.
734 //
735 Private->DevicePath = IScsiGetTcpConnDevicePath (Private->Session);
736 if (Private->DevicePath == NULL) {
737 Status = EFI_DEVICE_ERROR;
738 goto ON_ERROR;
739 }
740 //
741 // Install the updated device path onto the ExtScsiPassThruHandle.
742 //
743 Status = gBS->InstallProtocolInterface (
744 &Private->ExtScsiPassThruHandle,
745 &gEfiDevicePathProtocolGuid,
746 EFI_NATIVE_INTERFACE,
747 Private->DevicePath
748 );
749 if (EFI_ERROR (Status)) {
750 goto ON_ERROR;
751 }
752
753 ON_EXIT:
754
755 //
756 // Update/Publish the iSCSI Boot Firmware Table.
757 //
758 if (mPrivate->BootSelectedIndex != 0) {
759 IScsiPublishIbft ();
760 }
761
762 return EFI_SUCCESS;
763
764 ON_ERROR:
765
766 if (Private->Session != NULL) {
767 IScsiSessionAbort (Private->Session);
768 }
769
770 return Status;
771 }
772
773 /**
774 Stops a device controller or a bus controller. This is the worker function for
775 IScsiIp4(6)DriverBindingStop.
776
777 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
778 @param[in] ControllerHandle A handle to the device being stopped. The handle must
779 support a bus specific I/O protocol for the driver
780 to use to stop the device.
781 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
782 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
783 if NumberOfChildren is 0.
784 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
785
786 @retval EFI_SUCCESS The device was stopped.
787 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
788
789 **/
790 EFI_STATUS
791 EFIAPI
792 IScsiStop (
793 IN EFI_DRIVER_BINDING_PROTOCOL *This,
794 IN EFI_HANDLE ControllerHandle,
795 IN UINTN NumberOfChildren,
796 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL,
797 IN UINT8 IpVersion
798 )
799 {
800 EFI_HANDLE IScsiController;
801 EFI_STATUS Status;
802 ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier;
803 ISCSI_DRIVER_DATA *Private;
804 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
805 ISCSI_CONNECTION *Conn;
806 EFI_GUID *ProtocolGuid;
807 EFI_GUID *TcpServiceBindingGuid;
808 EFI_GUID *TcpProtocolGuid;
809
810
811 if (NumberOfChildren != 0) {
812 //
813 // We should have only one child.
814 //
815 Status = gBS->OpenProtocol (
816 ChildHandleBuffer[0],
817 &gEfiExtScsiPassThruProtocolGuid,
818 (VOID **) &PassThru,
819 This->DriverBindingHandle,
820 ControllerHandle,
821 EFI_OPEN_PROTOCOL_GET_PROTOCOL
822 );
823 if (EFI_ERROR (Status)) {
824 return EFI_DEVICE_ERROR;
825 }
826
827 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);
828 Conn = NET_LIST_HEAD (&Private->Session->Conns, ISCSI_CONNECTION, Link);
829
830 //
831 // Previously the TCP protocol is opened BY_CHILD_CONTROLLER. Just close
832 // the protocol here, but do not uninstall the device path protocol and
833 // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.
834 //
835 if (IpVersion == IP_VERSION_4) {
836 ProtocolGuid = &gEfiTcp4ProtocolGuid;
837 } else {
838 ProtocolGuid = &gEfiTcp6ProtocolGuid;
839 }
840
841 gBS->CloseProtocol (
842 Conn->TcpIo.Handle,
843 ProtocolGuid,
844 Private->Image,
845 Private->ExtScsiPassThruHandle
846 );
847
848 return EFI_SUCCESS;
849 }
850 //
851 // Get the handle of the controller we are controling.
852 //
853 if (IpVersion == IP_VERSION_4) {
854 ProtocolGuid = &gIScsiV4PrivateGuid;
855 TcpProtocolGuid = &gEfiTcp4ProtocolGuid;
856 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
857 } else {
858 ProtocolGuid = &gIScsiV6PrivateGuid;
859 TcpProtocolGuid = &gEfiTcp6ProtocolGuid;
860 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
861 }
862 IScsiController = NetLibGetNicHandle (ControllerHandle, TcpProtocolGuid);
863 if (IScsiController == NULL) {
864 return EFI_SUCCESS;
865 }
866
867 Status = gBS->OpenProtocol (
868 IScsiController,
869 ProtocolGuid,
870 (VOID **) &IScsiIdentifier,
871 This->DriverBindingHandle,
872 ControllerHandle,
873 EFI_OPEN_PROTOCOL_GET_PROTOCOL
874 );
875 if (EFI_ERROR (Status)) {
876 return EFI_DEVICE_ERROR;
877 }
878
879 Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);
880 ASSERT (Private != NULL);
881
882 if (Private->ChildHandle != NULL) {
883 Status = gBS->CloseProtocol (
884 Private->ChildHandle,
885 TcpProtocolGuid,
886 This->DriverBindingHandle,
887 IScsiController
888 );
889
890 ASSERT (!EFI_ERROR (Status));
891
892 Status = NetLibDestroyServiceChild (
893 IScsiController,
894 This->DriverBindingHandle,
895 TcpServiceBindingGuid,
896 Private->ChildHandle
897 );
898
899 ASSERT (!EFI_ERROR (Status));
900 }
901
902 gBS->UninstallProtocolInterface (
903 IScsiController,
904 ProtocolGuid,
905 &Private->IScsiIdentifier
906 );
907
908 //
909 // Remove this NIC.
910 //
911 IScsiRemoveNic (IScsiController);
912
913 //
914 // Update the iSCSI Boot Firware Table.
915 //
916 IScsiPublishIbft ();
917
918 if (Private->Session != NULL) {
919 IScsiSessionAbort (Private->Session);
920 }
921
922 IScsiCleanDriverData (Private);
923
924 return EFI_SUCCESS;
925 }
926
927 /**
928 Tests to see if this driver supports a given controller. If a child device is provided,
929 it tests to see if this driver supports creating a handle for the specified child device.
930
931 This function checks to see if the driver specified by This supports the device specified by
932 ControllerHandle. Drivers typically use the device path attached to
933 ControllerHandle and/or the services from the bus I/O abstraction attached to
934 ControllerHandle to determine if the driver supports ControllerHandle. This function
935 may be called many times during platform initialization. In order to reduce boot times, the tests
936 performed by this function must be very small and take as little time as possible to execute. This
937 function must not change the state of any hardware devices, and this function must be aware that the
938 device specified by ControllerHandle may already be managed by the same driver or a
939 different driver. This function must match its calls to AllocatePages() with FreePages(),
940 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
941 Since ControllerHandle may have been previously started by the same driver, if a protocol is
942 already in the opened state, then it must not be closed with CloseProtocol(). This is required
943 to guarantee the state of ControllerHandle is not modified by this function.
944
945 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
946 @param[in] ControllerHandle The handle of the controller to test. This handle
947 must support a protocol interface that supplies
948 an I/O abstraction to the driver.
949 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
950 parameter is ignored by device drivers, and is optional for bus
951 drivers. For bus drivers, if this parameter is not NULL, then
952 the bus driver must determine if the bus controller specified
953 by ControllerHandle and the child controller specified
954 by RemainingDevicePath are both supported by this
955 bus driver.
956
957 @retval EFI_SUCCESS The device specified by ControllerHandle and
958 RemainingDevicePath is supported by the driver specified by This.
959 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
960 RemainingDevicePath is already managed by the driver
961 specified by This.
962 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
963 RemainingDevicePath is already managed by a different
964 driver or an application that requires exclusive access.
965 Currently not implemented.
966 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
967 RemainingDevicePath is not supported by the driver specified by This.
968 **/
969 EFI_STATUS
970 EFIAPI
971 IScsiIp4DriverBindingSupported (
972 IN EFI_DRIVER_BINDING_PROTOCOL *This,
973 IN EFI_HANDLE ControllerHandle,
974 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
975 )
976 {
977 return IScsiSupported (
978 This,
979 ControllerHandle,
980 RemainingDevicePath,
981 IP_VERSION_4
982 );
983 }
984
985 /**
986 Starts a device controller or a bus controller.
987
988 The Start() function is designed to be invoked from the EFI boot service ConnectController().
989 As a result, much of the error checking on the parameters to Start() has been moved into this
990 common boot service. It is legal to call Start() from other locations,
991 but the following calling restrictions must be followed or the system behavior will not be deterministic.
992 1. ControllerHandle must be a valid EFI_HANDLE.
993 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
994 EFI_DEVICE_PATH_PROTOCOL.
995 3. Prior to calling Start(), the Supported() function for the driver specified by This must
996 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
997
998 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
999 @param[in] ControllerHandle The handle of the controller to start. This handle
1000 must support a protocol interface that supplies
1001 an I/O abstraction to the driver.
1002 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
1003 parameter is ignored by device drivers, and is optional for bus
1004 drivers. For a bus driver, if this parameter is NULL, then handles
1005 for all the children of Controller are created by this driver.
1006 If this parameter is not NULL and the first Device Path Node is
1007 not the End of Device Path Node, then only the handle for the
1008 child device specified by the first Device Path Node of
1009 RemainingDevicePath is created by this driver.
1010 If the first Device Path Node of RemainingDevicePath is
1011 the End of Device Path Node, no child handle is created by this
1012 driver.
1013
1014 @retval EFI_SUCCESS The device was started.
1015 @retval EFI_DEVICE_ERROR The device could not be started due to a device error. Currently not implemented.
1016 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1017 @retval Others The driver failed to start the device.
1018
1019 **/
1020 EFI_STATUS
1021 EFIAPI
1022 IScsiIp4DriverBindingStart (
1023 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1024 IN EFI_HANDLE ControllerHandle,
1025 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1026 )
1027 {
1028 EFI_STATUS Status;
1029
1030 Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_4);
1031 if (Status == EFI_ALREADY_STARTED) {
1032 Status = EFI_SUCCESS;
1033 }
1034
1035 return Status;
1036 }
1037
1038 /**
1039 Stops a device controller or a bus controller.
1040
1041 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
1042 As a result, much of the error checking on the parameters to Stop() has been moved
1043 into this common boot service. It is legal to call Stop() from other locations,
1044 but the following calling restrictions must be followed or the system behavior will not be deterministic.
1045 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
1046 same driver's Start() function.
1047 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
1048 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
1049 Start() function, and the Start() function must have called OpenProtocol() on
1050 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
1051
1052 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1053 @param[in] ControllerHandle A handle to the device being stopped. The handle must
1054 support a bus specific I/O protocol for the driver
1055 to use to stop the device.
1056 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
1057 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1058 if NumberOfChildren is 0.
1059
1060 @retval EFI_SUCCESS The device was stopped.
1061 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
1062
1063 **/
1064 EFI_STATUS
1065 EFIAPI
1066 IScsiIp4DriverBindingStop (
1067 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1068 IN EFI_HANDLE ControllerHandle,
1069 IN UINTN NumberOfChildren,
1070 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
1071 )
1072 {
1073 return IScsiStop (
1074 This,
1075 ControllerHandle,
1076 NumberOfChildren,
1077 ChildHandleBuffer,
1078 IP_VERSION_4
1079 );
1080 }
1081
1082 /**
1083 Tests to see if this driver supports a given controller. If a child device is provided,
1084 it tests to see if this driver supports creating a handle for the specified child device.
1085
1086 This function checks to see if the driver specified by This supports the device specified by
1087 ControllerHandle. Drivers typically use the device path attached to
1088 ControllerHandle and/or the services from the bus I/O abstraction attached to
1089 ControllerHandle to determine if the driver supports ControllerHandle. This function
1090 may be called many times during platform initialization. In order to reduce boot times, the tests
1091 performed by this function must be very small and take as little time as possible to execute. This
1092 function must not change the state of any hardware devices, and this function must be aware that the
1093 device specified by ControllerHandle may already be managed by the same driver or a
1094 different driver. This function must match its calls to AllocatePages() with FreePages(),
1095 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
1096 Since ControllerHandle may have been previously started by the same driver, if a protocol is
1097 already in the opened state, then it must not be closed with CloseProtocol(). This is required
1098 to guarantee the state of ControllerHandle is not modified by this function.
1099
1100 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1101 @param[in] ControllerHandle The handle of the controller to test. This handle
1102 must support a protocol interface that supplies
1103 an I/O abstraction to the driver.
1104 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
1105 parameter is ignored by device drivers, and is optional for bus
1106 drivers. For bus drivers, if this parameter is not NULL, then
1107 the bus driver must determine if the bus controller specified
1108 by ControllerHandle and the child controller specified
1109 by RemainingDevicePath are both supported by this
1110 bus driver.
1111
1112 @retval EFI_SUCCESS The device specified by ControllerHandle and
1113 RemainingDevicePath is supported by the driver specified by This.
1114 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
1115 RemainingDevicePath is already managed by the driver
1116 specified by This.
1117 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
1118 RemainingDevicePath is already managed by a different
1119 driver or an application that requires exclusive access.
1120 Currently not implemented.
1121 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
1122 RemainingDevicePath is not supported by the driver specified by This.
1123 **/
1124 EFI_STATUS
1125 EFIAPI
1126 IScsiIp6DriverBindingSupported (
1127 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1128 IN EFI_HANDLE ControllerHandle,
1129 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1130 )
1131 {
1132 return IScsiSupported (
1133 This,
1134 ControllerHandle,
1135 RemainingDevicePath,
1136 IP_VERSION_6
1137 );
1138 }
1139
1140 /**
1141 Starts a device controller or a bus controller.
1142
1143 The Start() function is designed to be invoked from the EFI boot service ConnectController().
1144 As a result, much of the error checking on the parameters to Start() has been moved into this
1145 common boot service. It is legal to call Start() from other locations,
1146 but the following calling restrictions must be followed or the system behavior will not be deterministic.
1147 1. ControllerHandle must be a valid EFI_HANDLE.
1148 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
1149 EFI_DEVICE_PATH_PROTOCOL.
1150 3. Prior to calling Start(), the Supported() function for the driver specified by This must
1151 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
1152
1153 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1154 @param[in] ControllerHandle The handle of the controller to start. This handle
1155 must support a protocol interface that supplies
1156 an I/O abstraction to the driver.
1157 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
1158 parameter is ignored by device drivers, and is optional for bus
1159 drivers. For a bus driver, if this parameter is NULL, then handles
1160 for all the children of Controller are created by this driver.
1161 If this parameter is not NULL and the first Device Path Node is
1162 not the End of Device Path Node, then only the handle for the
1163 child device specified by the first Device Path Node of
1164 RemainingDevicePath is created by this driver.
1165 If the first Device Path Node of RemainingDevicePath is
1166 the End of Device Path Node, no child handle is created by this
1167 driver.
1168
1169 @retval EFI_SUCCESS The device was started.
1170 @retval EFI_DEVICE_ERROR The device could not be started due to a device error. Currently not implemented.
1171 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1172 @retval Others The driver failed to start the device.
1173
1174 **/
1175 EFI_STATUS
1176 EFIAPI
1177 IScsiIp6DriverBindingStart (
1178 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1179 IN EFI_HANDLE ControllerHandle,
1180 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1181 )
1182 {
1183 EFI_STATUS Status;
1184
1185 Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_6);
1186 if (Status == EFI_ALREADY_STARTED) {
1187 Status = EFI_SUCCESS;
1188 }
1189
1190 return Status;
1191 }
1192
1193 /**
1194 Stops a device controller or a bus controller.
1195
1196 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
1197 As a result, much of the error checking on the parameters to Stop() has been moved
1198 into this common boot service. It is legal to call Stop() from other locations,
1199 but the following calling restrictions must be followed or the system behavior will not be deterministic.
1200 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
1201 same driver's Start() function.
1202 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
1203 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
1204 Start() function, and the Start() function must have called OpenProtocol() on
1205 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
1206
1207 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1208 @param[in] ControllerHandle A handle to the device being stopped. The handle must
1209 support a bus specific I/O protocol for the driver
1210 to use to stop the device.
1211 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
1212 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1213 if NumberOfChildren is 0.
1214
1215 @retval EFI_SUCCESS The device was stopped.
1216 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
1217
1218 **/
1219 EFI_STATUS
1220 EFIAPI
1221 IScsiIp6DriverBindingStop (
1222 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1223 IN EFI_HANDLE ControllerHandle,
1224 IN UINTN NumberOfChildren,
1225 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
1226 )
1227 {
1228 return IScsiStop (
1229 This,
1230 ControllerHandle,
1231 NumberOfChildren,
1232 ChildHandleBuffer,
1233 IP_VERSION_6
1234 );
1235 }
1236
1237 /**
1238 Unload the iSCSI driver.
1239
1240 @param[in] ImageHandle The handle of the driver image.
1241
1242 @retval EFI_SUCCESS The driver is unloaded.
1243 @retval EFI_DEVICE_ERROR An unexpected error occurred.
1244
1245 **/
1246 EFI_STATUS
1247 EFIAPI
1248 IScsiUnload (
1249 IN EFI_HANDLE ImageHandle
1250 )
1251 {
1252 EFI_STATUS Status;
1253 UINTN DeviceHandleCount;
1254 EFI_HANDLE *DeviceHandleBuffer;
1255 UINTN Index;
1256 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
1257 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
1258
1259 //
1260 // Try to disonnect the driver from the devices it's controlling.
1261 //
1262 Status = gBS->LocateHandleBuffer (
1263 AllHandles,
1264 NULL,
1265 NULL,
1266 &DeviceHandleCount,
1267 &DeviceHandleBuffer
1268 );
1269 if (EFI_ERROR (Status)) {
1270 return Status;
1271 }
1272
1273 //
1274 // Disconnect the iSCSI4 driver from the controlled device.
1275 //
1276 for (Index = 0; Index < DeviceHandleCount; Index++) {
1277 Status = IScsiTestManagedDevice (
1278 DeviceHandleBuffer[Index],
1279 gIScsiIp4DriverBinding.DriverBindingHandle,
1280 &gEfiTcp4ProtocolGuid)
1281 ;
1282 if (EFI_ERROR (Status)) {
1283 continue;
1284 }
1285 Status = gBS->DisconnectController (
1286 DeviceHandleBuffer[Index],
1287 gIScsiIp4DriverBinding.DriverBindingHandle,
1288 NULL
1289 );
1290 if (EFI_ERROR (Status)) {
1291 goto ON_EXIT;
1292 }
1293 }
1294
1295 //
1296 // Disconnect the iSCSI6 driver from the controlled device.
1297 //
1298 for (Index = 0; Index < DeviceHandleCount; Index++) {
1299 Status = IScsiTestManagedDevice (
1300 DeviceHandleBuffer[Index],
1301 gIScsiIp6DriverBinding.DriverBindingHandle,
1302 &gEfiTcp6ProtocolGuid
1303 );
1304 if (EFI_ERROR (Status)) {
1305 continue;
1306 }
1307 Status = gBS->DisconnectController (
1308 DeviceHandleBuffer[Index],
1309 gIScsiIp6DriverBinding.DriverBindingHandle,
1310 NULL
1311 );
1312 if (EFI_ERROR (Status)) {
1313 goto ON_EXIT;
1314 }
1315 }
1316
1317 //
1318 // Unload the iSCSI configuration form.
1319 //
1320 Status = IScsiConfigFormUnload (gIScsiIp4DriverBinding.DriverBindingHandle);
1321 if (EFI_ERROR (Status)) {
1322 goto ON_EXIT;
1323 }
1324
1325 //
1326 // Uninstall the protocols installed by iSCSI driver.
1327 //
1328 Status = gBS->UninstallMultipleProtocolInterfaces (
1329 ImageHandle,
1330 &gEfiAuthenticationInfoProtocolGuid,
1331 &gIScsiAuthenticationInfo,
1332 NULL
1333 );
1334 if (EFI_ERROR (Status)) {
1335 goto ON_EXIT;
1336 }
1337
1338 if (gIScsiControllerNameTable!= NULL) {
1339 Status = FreeUnicodeStringTable (gIScsiControllerNameTable);
1340 if (EFI_ERROR (Status)) {
1341 goto ON_EXIT;
1342 }
1343 gIScsiControllerNameTable = NULL;
1344 }
1345
1346 //
1347 // Uninstall the ComponentName and ComponentName2 protocol from iSCSI4 driver binding handle
1348 // if it has been installed.
1349 //
1350 Status = gBS->HandleProtocol (
1351 gIScsiIp4DriverBinding.DriverBindingHandle,
1352 &gEfiComponentNameProtocolGuid,
1353 (VOID **) &ComponentName
1354 );
1355 if (!EFI_ERROR (Status)) {
1356 Status = gBS->UninstallMultipleProtocolInterfaces (
1357 gIScsiIp4DriverBinding.DriverBindingHandle,
1358 &gEfiComponentNameProtocolGuid,
1359 ComponentName,
1360 NULL
1361 );
1362 if (EFI_ERROR (Status)) {
1363 goto ON_EXIT;
1364 }
1365 }
1366
1367 Status = gBS->HandleProtocol (
1368 gIScsiIp4DriverBinding.DriverBindingHandle,
1369 &gEfiComponentName2ProtocolGuid,
1370 (VOID **) &ComponentName2
1371 );
1372 if (!EFI_ERROR (Status)) {
1373 gBS->UninstallMultipleProtocolInterfaces (
1374 gIScsiIp4DriverBinding.DriverBindingHandle,
1375 &gEfiComponentName2ProtocolGuid,
1376 ComponentName2,
1377 NULL
1378 );
1379 if (EFI_ERROR (Status)) {
1380 goto ON_EXIT;
1381 }
1382 }
1383
1384 //
1385 // Uninstall the ComponentName and ComponentName2 protocol from iSCSI6 driver binding handle
1386 // if it has been installed.
1387 //
1388 Status = gBS->HandleProtocol (
1389 gIScsiIp6DriverBinding.DriverBindingHandle,
1390 &gEfiComponentNameProtocolGuid,
1391 (VOID **) &ComponentName
1392 );
1393 if (!EFI_ERROR (Status)) {
1394 Status = gBS->UninstallMultipleProtocolInterfaces (
1395 gIScsiIp6DriverBinding.DriverBindingHandle,
1396 &gEfiComponentNameProtocolGuid,
1397 ComponentName,
1398 NULL
1399 );
1400 if (EFI_ERROR (Status)) {
1401 goto ON_EXIT;
1402 }
1403 }
1404
1405 Status = gBS->HandleProtocol (
1406 gIScsiIp6DriverBinding.DriverBindingHandle,
1407 &gEfiComponentName2ProtocolGuid,
1408 (VOID **) &ComponentName2
1409 );
1410 if (!EFI_ERROR (Status)) {
1411 gBS->UninstallMultipleProtocolInterfaces (
1412 gIScsiIp6DriverBinding.DriverBindingHandle,
1413 &gEfiComponentName2ProtocolGuid,
1414 ComponentName2,
1415 NULL
1416 );
1417 if (EFI_ERROR (Status)) {
1418 goto ON_EXIT;
1419 }
1420 }
1421
1422 //
1423 // Uninstall the IScsiInitiatorNameProtocol and all the driver binding protocols.
1424 //
1425 Status = gBS->UninstallMultipleProtocolInterfaces (
1426 gIScsiIp4DriverBinding.DriverBindingHandle,
1427 &gEfiDriverBindingProtocolGuid,
1428 &gIScsiIp4DriverBinding,
1429 &gEfiIScsiInitiatorNameProtocolGuid,
1430 &gIScsiInitiatorName,
1431 NULL
1432 );
1433 if (EFI_ERROR (Status)) {
1434 goto ON_EXIT;
1435 }
1436
1437 Status = gBS->UninstallMultipleProtocolInterfaces (
1438 gIScsiIp6DriverBinding.DriverBindingHandle,
1439 &gEfiDriverBindingProtocolGuid,
1440 &gIScsiIp6DriverBinding,
1441 NULL
1442 );
1443
1444 ON_EXIT:
1445
1446 if (DeviceHandleBuffer != NULL) {
1447 FreePool (DeviceHandleBuffer);
1448 }
1449
1450 return Status;
1451 }
1452
1453 /**
1454 This is the declaration of an EFI image entry point. This entry point is
1455 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
1456 both device drivers and bus drivers.
1457
1458 The entry point for iSCSI driver which initializes the global variables and
1459 installs the driver binding, component name protocol, iSCSI initiator name
1460 protocol and Authentication Info protocol on its image.
1461
1462 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
1463 @param[in] SystemTable A pointer to the EFI System Table.
1464
1465 @retval EFI_SUCCESS The operation completed successfully.
1466 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1467
1468 **/
1469 EFI_STATUS
1470 EFIAPI
1471 IScsiDriverEntryPoint (
1472 IN EFI_HANDLE ImageHandle,
1473 IN EFI_SYSTEM_TABLE *SystemTable
1474 )
1475 {
1476 EFI_STATUS Status;
1477 EFI_ISCSI_INITIATOR_NAME_PROTOCOL *IScsiInitiatorName;
1478 EFI_AUTHENTICATION_INFO_PROTOCOL *AuthenticationInfo;
1479
1480 //
1481 // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.
1482 //
1483 Status = gBS->LocateProtocol (
1484 &gEfiIScsiInitiatorNameProtocolGuid,
1485 NULL,
1486 (VOID **) &IScsiInitiatorName
1487 );
1488 if (!EFI_ERROR (Status)) {
1489 return EFI_ACCESS_DENIED;
1490 }
1491
1492 //
1493 // Initialize the EFI Driver Library.
1494 //
1495 Status = EfiLibInstallDriverBindingComponentName2 (
1496 ImageHandle,
1497 SystemTable,
1498 &gIScsiIp4DriverBinding,
1499 ImageHandle,
1500 &gIScsiComponentName,
1501 &gIScsiComponentName2
1502 );
1503 if (EFI_ERROR (Status)) {
1504 return Status;
1505 }
1506
1507 Status = EfiLibInstallDriverBindingComponentName2 (
1508 ImageHandle,
1509 SystemTable,
1510 &gIScsiIp6DriverBinding,
1511 NULL,
1512 &gIScsiComponentName,
1513 &gIScsiComponentName2
1514 );
1515 if (EFI_ERROR (Status)) {
1516 goto Error1;
1517 }
1518
1519 //
1520 // Install the iSCSI Initiator Name Protocol.
1521 //
1522 Status = gBS->InstallProtocolInterface (
1523 &ImageHandle,
1524 &gEfiIScsiInitiatorNameProtocolGuid,
1525 EFI_NATIVE_INTERFACE,
1526 &gIScsiInitiatorName
1527 );
1528 if (EFI_ERROR (Status)) {
1529 goto Error2;
1530 }
1531
1532 //
1533 // Create the private data structures.
1534 //
1535 mPrivate = AllocateZeroPool (sizeof (ISCSI_PRIVATE_DATA));
1536 if (mPrivate == NULL) {
1537 Status = EFI_OUT_OF_RESOURCES;
1538 goto Error3;
1539 }
1540
1541 InitializeListHead (&mPrivate->NicInfoList);
1542 InitializeListHead (&mPrivate->AttemptConfigs);
1543
1544 //
1545 // Initialize the configuration form of iSCSI.
1546 //
1547 Status = IScsiConfigFormInit (gIScsiIp4DriverBinding.DriverBindingHandle);
1548 if (EFI_ERROR (Status)) {
1549 goto Error4;
1550 }
1551
1552 //
1553 // There should be only one EFI_AUTHENTICATION_INFO_PROTOCOL. If already exists,
1554 // do not produce the protocol instance.
1555 //
1556 Status = gBS->LocateProtocol (
1557 &gEfiAuthenticationInfoProtocolGuid,
1558 NULL,
1559 (VOID **) &AuthenticationInfo
1560 );
1561 if (Status == EFI_NOT_FOUND) {
1562 Status = gBS->InstallProtocolInterface (
1563 &ImageHandle,
1564 &gEfiAuthenticationInfoProtocolGuid,
1565 EFI_NATIVE_INTERFACE,
1566 &gIScsiAuthenticationInfo
1567 );
1568 if (EFI_ERROR (Status)) {
1569 goto Error5;
1570 }
1571 }
1572
1573 return EFI_SUCCESS;
1574
1575 Error5:
1576 IScsiConfigFormUnload (gIScsiIp4DriverBinding.DriverBindingHandle);
1577
1578 Error4:
1579 FreePool (mPrivate);
1580
1581 Error3:
1582 gBS->UninstallMultipleProtocolInterfaces (
1583 ImageHandle,
1584 &gEfiIScsiInitiatorNameProtocolGuid,
1585 &gIScsiInitiatorName,
1586 NULL
1587 );
1588
1589 Error2:
1590 gBS->UninstallMultipleProtocolInterfaces (
1591 gIScsiIp6DriverBinding.DriverBindingHandle,
1592 &gEfiDriverBindingProtocolGuid,
1593 &gIScsiIp6DriverBinding,
1594 &gEfiComponentName2ProtocolGuid,
1595 &gIScsiComponentName2,
1596 &gEfiComponentNameProtocolGuid,
1597 &gIScsiComponentName,
1598 NULL
1599 );
1600
1601 Error1:
1602 gBS->UninstallMultipleProtocolInterfaces (
1603 ImageHandle,
1604 &gEfiDriverBindingProtocolGuid,
1605 &gIScsiIp4DriverBinding,
1606 &gEfiComponentName2ProtocolGuid,
1607 &gIScsiComponentName2,
1608 &gEfiComponentNameProtocolGuid,
1609 &gIScsiComponentName,
1610 NULL
1611 );
1612
1613 return Status;
1614 }
1615