2 The entry point of IScsi driver.
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
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.
15 #include "IScsiImpl.h"
17 EFI_DRIVER_BINDING_PROTOCOL gIScsiIp4DriverBinding
= {
18 IScsiIp4DriverBindingSupported
,
19 IScsiIp4DriverBindingStart
,
20 IScsiIp4DriverBindingStop
,
26 EFI_DRIVER_BINDING_PROTOCOL gIScsiIp6DriverBinding
= {
27 IScsiIp6DriverBindingSupported
,
28 IScsiIp6DriverBindingStart
,
29 IScsiIp6DriverBindingStop
,
35 EFI_GUID gIScsiV4PrivateGuid
= ISCSI_V4_PRIVATE_GUID
;
36 EFI_GUID gIScsiV6PrivateGuid
= ISCSI_V6_PRIVATE_GUID
;
37 ISCSI_PRIVATE_DATA
*mPrivate
= NULL
;
40 Tests to see if this driver supports the RemainingDevicePath.
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
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.
55 IScsiIsDevicePathSupported (
56 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
59 EFI_DEVICE_PATH_PROTOCOL
*CurrentDevicePath
;
61 CurrentDevicePath
= RemainingDevicePath
;
62 if (CurrentDevicePath
!= NULL
) {
63 while (!IsDevicePathEnd (CurrentDevicePath
)) {
64 if ((CurrentDevicePath
->Type
== MESSAGING_DEVICE_PATH
) && (CurrentDevicePath
->SubType
== MSG_ISCSI_DP
)) {
68 CurrentDevicePath
= NextDevicePathNode (CurrentDevicePath
);
71 return EFI_UNSUPPORTED
;
79 Tests to see if this driver supports a given controller. This is the worker function for
80 IScsiIp4(6)DriverBindingSupported.
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
93 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
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
100 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
101 RemainingDevicePath is not supported by the driver specified by This.
106 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
107 IN EFI_HANDLE ControllerHandle
,
108 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
,
113 EFI_GUID
*IScsiServiceBindingGuid
;
114 EFI_GUID
*TcpServiceBindingGuid
;
115 EFI_GUID
*DhcpServiceBindingGuid
;
117 if (IpVersion
== IP_VERSION_4
) {
118 IScsiServiceBindingGuid
= &gIScsiV4PrivateGuid
;
119 TcpServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
120 DhcpServiceBindingGuid
= &gEfiDhcp4ServiceBindingProtocolGuid
;
122 IScsiServiceBindingGuid
= &gIScsiV6PrivateGuid
;
123 TcpServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
124 DhcpServiceBindingGuid
= &gEfiDhcp6ServiceBindingProtocolGuid
;
127 Status
= gBS
->OpenProtocol (
129 IScsiServiceBindingGuid
,
131 This
->DriverBindingHandle
,
133 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
135 if (!EFI_ERROR (Status
)) {
136 return EFI_ALREADY_STARTED
;
139 Status
= gBS
->OpenProtocol (
141 TcpServiceBindingGuid
,
143 This
->DriverBindingHandle
,
145 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
147 if (EFI_ERROR (Status
)) {
148 return EFI_UNSUPPORTED
;
151 Status
= IScsiIsDevicePathSupported (RemainingDevicePath
);
152 if (EFI_ERROR (Status
)) {
153 return EFI_UNSUPPORTED
;
156 if (IScsiDhcpIsConfigured (ControllerHandle
, IpVersion
)) {
157 Status
= gBS
->OpenProtocol (
159 DhcpServiceBindingGuid
,
161 This
->DriverBindingHandle
,
163 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
165 if (EFI_ERROR (Status
)) {
166 return EFI_UNSUPPORTED
;
175 Start to manage the controller. This is the worker function for
176 IScsiIp4(6)DriverBindingStart.
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.
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
187 @retval EFI_DEVICE_ERROR Failed to get TCP connection device path.
193 IN EFI_HANDLE ControllerHandle
,
198 ISCSI_DRIVER_DATA
*Private
;
200 LIST_ENTRY
*NextEntry
;
201 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptConfigData
;
202 ISCSI_SESSION
*Session
;
204 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExistIScsiExtScsiPassThru
;
205 ISCSI_DRIVER_DATA
*ExistPrivate
;
206 UINT8
*AttemptConfigOrder
;
207 UINTN AttemptConfigOrderSize
;
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
];
217 EFI_GUID
*ProtocolGuid
;
220 // Test to see if iSCSI driver supports the given controller.
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
;
232 return EFI_INVALID_PARAMETER
;
235 Status
= gBS
->OpenProtocol (
241 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
243 if (!EFI_ERROR (Status
)) {
244 return EFI_ALREADY_STARTED
;
247 Status
= gBS
->OpenProtocol (
249 TcpServiceBindingGuid
,
253 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
255 if (EFI_ERROR (Status
)) {
256 return EFI_UNSUPPORTED
;
260 // Record the incoming NIC info.
262 Status
= IScsiAddNic (ControllerHandle
);
263 if (EFI_ERROR (Status
)) {
268 // Create the instance private data.
270 Private
= IScsiCreateDriverData (Image
, ControllerHandle
);
271 if (Private
== NULL
) {
272 return EFI_OUT_OF_RESOURCES
;
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.
281 Status
= NetLibCreateServiceChild (
284 TcpServiceBindingGuid
,
285 &Private
->ChildHandle
288 if (EFI_ERROR (Status
)) {
292 Status
= gBS
->OpenProtocol (
293 Private
->ChildHandle
,
298 EFI_OPEN_PROTOCOL_BY_DRIVER
301 if (EFI_ERROR (Status
)) {
306 // Always install private protocol no matter what happens later. We need to
307 // keep the relationship between ControllerHandle and ChildHandle.
309 Status
= gBS
->InstallProtocolInterface (
312 EFI_NATIVE_INTERFACE
,
313 &Private
->IScsiIdentifier
315 if (EFI_ERROR (Status
)) {
319 if (IpVersion
== IP_VERSION_4
) {
320 mPrivate
->Ipv6Flag
= FALSE
;
322 mPrivate
->Ipv6Flag
= TRUE
;
326 // Get the current iSCSI configuration data.
328 Status
= IScsiGetConfigData (Private
);
329 if (EFI_ERROR (Status
)) {
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.
339 Status
= EFI_NOT_FOUND
;
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
) {
350 if (AttemptConfigData
== NULL
) {
354 if (AttemptConfigData
->AttemptConfigIndex
== mPrivate
->BootSelectedIndex
) {
359 // Uninstall the original ExtScsiPassThru first.
363 // Locate all ExtScsiPassThru protocol instances.
365 Status
= gBS
->LocateHandleBuffer (
367 &gEfiExtScsiPassThruProtocolGuid
,
372 if (EFI_ERROR (Status
)) {
377 // Find ExtScsiPassThru protocol instance produced by this driver.
379 ExistIScsiExtScsiPassThru
= NULL
;
380 for (Index
= 0; Index
< NumberOfHandles
&& ExistIScsiExtScsiPassThru
== NULL
; Index
++) {
381 Status
= gBS
->HandleProtocol (
383 &gEfiDevicePathProtocolGuid
,
384 (VOID
**) &DevicePath
386 if (EFI_ERROR (Status
)) {
390 while (!IsDevicePathEnd (DevicePath
)) {
391 if ((DevicePath
->Type
== MESSAGING_DEVICE_PATH
) && (DevicePath
->SubType
== MSG_MAC_ADDR_DP
)) {
393 // Get the ExtScsiPassThru protocol instance.
395 Status
= gBS
->HandleProtocol (
397 &gEfiExtScsiPassThruProtocolGuid
,
398 (VOID
**) &ExistIScsiExtScsiPassThru
400 ASSERT_EFI_ERROR (Status
);
404 DevicePath
= NextDevicePathNode (DevicePath
);
408 FreePool (HandleBuffer
);
410 if (ExistIScsiExtScsiPassThru
== NULL
) {
411 Status
= EFI_NOT_FOUND
;
415 ExistPrivate
= ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (ExistIScsiExtScsiPassThru
);
417 Status
= gBS
->UninstallProtocolInterface (
418 ExistPrivate
->ExtScsiPassThruHandle
,
419 &gEfiExtScsiPassThruProtocolGuid
,
420 &ExistPrivate
->IScsiExtScsiPassThru
422 if (EFI_ERROR (Status
)) {
428 // Install the Ext SCSI PASS THRU protocol.
430 Status
= gBS
->InstallProtocolInterface (
431 &Private
->ExtScsiPassThruHandle
,
432 &gEfiExtScsiPassThruProtocolGuid
,
433 EFI_NATIVE_INTERFACE
,
434 &Private
->IScsiExtScsiPassThru
436 if (EFI_ERROR (Status
)) {
442 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &mPrivate
->AttemptConfigs
) {
443 AttemptConfigData
= NET_LIST_USER_STRUCT (Entry
, ISCSI_ATTEMPT_CONFIG_NVDATA
, Link
);
445 // Don't process the attempt that does not associate with the current NIC or
446 // this attempt is disabled or established.
448 if (AttemptConfigData
->NicIndex
!= mPrivate
->CurrentNic
||
449 AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_DISABLED
||
450 AttemptConfigData
->ValidPath
) {
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.
458 if ((mPrivate
->EnableMpio
&&
459 AttemptConfigData
->SessionConfigData
.Enabled
!= ISCSI_ENABLED_FOR_MPIO
) ||
460 (!mPrivate
->EnableMpio
&&
461 AttemptConfigData
->SessionConfigData
.Enabled
!= ISCSI_ENABLED
)) {
466 // Don't process the attempt that fails to get the init/target information from DHCP.
468 if (AttemptConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
&&
469 !AttemptConfigData
->DhcpSuccess
) {
470 if (!mPrivate
->EnableMpio
&& mPrivate
->ValidSinglePathCount
> 0) {
471 mPrivate
->ValidSinglePathCount
--;
477 // Don't process the autoconfigure path if it is already established.
479 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
&&
480 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_SUCCESS
) {
485 // Don't process the attempt if its IP mode is not in the current IP version.
487 if (!mPrivate
->Ipv6Flag
) {
488 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP6
) {
491 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
&&
492 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP6
) {
496 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP4
) {
499 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
&&
500 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP4
) {
506 // Fill in the Session and init it.
508 Session
= (ISCSI_SESSION
*) AllocateZeroPool (sizeof (ISCSI_SESSION
));
509 if (Session
== NULL
) {
510 Status
= EFI_OUT_OF_RESOURCES
;
514 Session
->Private
= Private
;
515 Session
->ConfigData
= AttemptConfigData
;
516 Session
->AuthType
= AttemptConfigData
->AuthenticationType
;
518 AsciiStrToUnicodeStr (AttemptConfigData
->MacString
, MacString
);
520 mPrivate
->PortString
,
521 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
524 (UINTN
) AttemptConfigData
->AttemptConfigIndex
527 if (Session
->AuthType
== ISCSI_AUTH_TYPE_CHAP
) {
528 Session
->AuthData
.CHAP
.AuthConfig
= &AttemptConfigData
->AuthConfigData
.CHAP
;
531 IScsiSessionInit (Session
, FALSE
);
534 // Try to login and create an iSCSI session according to the configuration.
536 Status
= IScsiSessionLogin (Session
);
537 if (Status
== EFI_MEDIA_CHANGED
) {
539 // The specified target is not available, and the redirection information is
540 // received. Login the session again with the updated target address.
542 Status
= IScsiSessionLogin (Session
);
543 } else if (Status
== EFI_NOT_READY
) {
544 Status
= IScsiSessionReLogin (Session
);
547 if (EFI_ERROR (Status
)) {
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.
552 if (!mPrivate
->EnableMpio
&& mPrivate
->ValidSinglePathCount
> 0) {
553 mPrivate
->ValidSinglePathCount
--;
559 AttemptConfigData
->ValidPath
= TRUE
;
562 // Do not record the attempt in iBFT if it login with KRB5.
563 // TODO: record KRB5 attempt information in the iSCSI device path.
565 if (Session
->AuthType
== ISCSI_AUTH_TYPE_KRB
) {
566 if (!mPrivate
->EnableMpio
&& mPrivate
->ValidSinglePathCount
> 0) {
567 mPrivate
->ValidSinglePathCount
--;
570 AttemptConfigData
->ValidiBFTPath
= FALSE
;
572 AttemptConfigData
->ValidiBFTPath
= TRUE
;
576 // IScsi session success. Update the attempt state to NVR.
578 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
) {
579 AttemptConfigData
->AutoConfigureMode
= IP_MODE_AUTOCONFIG_SUCCESS
;
583 mPrivate
->PortString
,
584 &gEfiIScsiInitiatorNameProtocolGuid
,
585 ISCSI_CONFIG_VAR_ATTR
,
586 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
591 // Select the first login session. Abort others.
593 if (Private
->Session
== NULL
) {
594 Private
->Session
= Session
;
595 BootSelected
= AttemptConfigData
->AttemptConfigIndex
;
597 // Don't validate other attempt in multipath mode if one is success.
599 if (mPrivate
->EnableMpio
) {
603 IScsiSessionAbort (Session
);
610 // All attempts configured for this driver instance are not valid.
612 if (Private
->Session
== NULL
) {
613 Status
= gBS
->UninstallProtocolInterface (
614 Private
->ExtScsiPassThruHandle
,
615 &gEfiExtScsiPassThruProtocolGuid
,
616 &Private
->IScsiExtScsiPassThru
618 ASSERT_EFI_ERROR (Status
);
619 Private
->ExtScsiPassThruHandle
= NULL
;
622 // Reinstall the original ExtScsiPassThru back.
624 if (mPrivate
->OneSessionEstablished
&& ExistPrivate
!= NULL
) {
625 Status
= gBS
->InstallProtocolInterface (
626 &ExistPrivate
->ExtScsiPassThruHandle
,
627 &gEfiExtScsiPassThruProtocolGuid
,
628 EFI_NATIVE_INTERFACE
,
629 &ExistPrivate
->IScsiExtScsiPassThru
631 if (EFI_ERROR (Status
)) {
638 Status
= EFI_NOT_FOUND
;
645 // More than one attempt successes.
647 if (Private
->Session
!= NULL
&& mPrivate
->OneSessionEstablished
) {
649 AttemptConfigOrder
= IScsiGetVariableAndSize (
652 &AttemptConfigOrderSize
654 ASSERT (AttemptConfigOrder
!= NULL
);
655 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
656 if (AttemptConfigOrder
[Index
] == mPrivate
->BootSelectedIndex
||
657 AttemptConfigOrder
[Index
] == BootSelected
) {
662 if (mPrivate
->EnableMpio
) {
664 // Use the attempt in earlier order. Abort the later one in MPIO.
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
675 Private
->ExtScsiPassThruHandle
= NULL
;
678 // Reinstall the original ExtScsiPassThru back.
680 Status
= gBS
->InstallProtocolInterface (
681 &ExistPrivate
->ExtScsiPassThruHandle
,
682 &gEfiExtScsiPassThruProtocolGuid
,
683 EFI_NATIVE_INTERFACE
,
684 &ExistPrivate
->IScsiExtScsiPassThru
686 if (EFI_ERROR (Status
)) {
692 ASSERT (AttemptConfigOrder
[Index
] == BootSelected
);
693 mPrivate
->BootSelectedIndex
= BootSelected
;
695 // Clear the resource in ExistPrivate.
697 gBS
->UninstallProtocolInterface (
698 ExistPrivate
->Controller
,
700 &ExistPrivate
->IScsiIdentifier
703 IScsiRemoveNic (ExistPrivate
->Controller
);
704 if (ExistPrivate
->Session
!= NULL
) {
705 IScsiSessionAbort (ExistPrivate
->Session
);
708 IScsiCleanDriverData (ExistPrivate
);
712 // Use the attempt in earlier order as boot selected in single path mode.
714 if (AttemptConfigOrder
[Index
] == mPrivate
->BootSelectedIndex
) {
722 mPrivate
->OneSessionEstablished
= TRUE
;
723 mPrivate
->BootSelectedIndex
= BootSelected
;
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
731 Private
->DevicePath
= IScsiGetTcpConnDevicePath (Private
->Session
);
732 if (Private
->DevicePath
== NULL
) {
733 Status
= EFI_DEVICE_ERROR
;
737 // Install the updated device path onto the ExtScsiPassThruHandle.
739 Status
= gBS
->InstallProtocolInterface (
740 &Private
->ExtScsiPassThruHandle
,
741 &gEfiDevicePathProtocolGuid
,
742 EFI_NATIVE_INTERFACE
,
745 if (EFI_ERROR (Status
)) {
752 // Update/Publish the iSCSI Boot Firmware Table.
754 if (mPrivate
->BootSelectedIndex
!= 0) {
762 if (Private
->Session
!= NULL
) {
763 IScsiSessionAbort (Private
->Session
);
770 Stops a device controller or a bus controller. This is the worker function for
771 IScsiIp4(6)DriverBindingStop.
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.
782 @retval EFI_SUCCESS The device was stopped.
783 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
789 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
790 IN EFI_HANDLE ControllerHandle
,
791 IN UINTN NumberOfChildren
,
792 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
,
796 EFI_HANDLE IScsiController
;
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
;
807 if (NumberOfChildren
!= 0) {
809 // We should have only one child.
811 Status
= gBS
->OpenProtocol (
812 ChildHandleBuffer
[0],
813 &gEfiExtScsiPassThruProtocolGuid
,
815 This
->DriverBindingHandle
,
817 EFI_OPEN_PROTOCOL_GET_PROTOCOL
819 if (EFI_ERROR (Status
)) {
820 return EFI_DEVICE_ERROR
;
823 Private
= ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru
);
824 Conn
= NET_LIST_HEAD (&Private
->Session
->Conns
, ISCSI_CONNECTION
, Link
);
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.
831 if (IpVersion
== IP_VERSION_4
) {
832 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
834 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
841 Private
->ExtScsiPassThruHandle
847 // Get the handle of the controller we are controling.
849 if (IpVersion
== IP_VERSION_4
) {
850 ProtocolGuid
= &gIScsiV4PrivateGuid
;
851 TcpProtocolGuid
= &gEfiTcp4ProtocolGuid
;
852 TcpServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
854 ProtocolGuid
= &gIScsiV6PrivateGuid
;
855 TcpProtocolGuid
= &gEfiTcp6ProtocolGuid
;
856 TcpServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
858 IScsiController
= NetLibGetNicHandle (ControllerHandle
, TcpProtocolGuid
);
859 if (IScsiController
== NULL
) {
863 Status
= gBS
->OpenProtocol (
866 (VOID
**) &IScsiIdentifier
,
867 This
->DriverBindingHandle
,
869 EFI_OPEN_PROTOCOL_GET_PROTOCOL
871 if (EFI_ERROR (Status
)) {
872 return EFI_DEVICE_ERROR
;
875 Private
= ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier
);
876 ASSERT (Private
!= NULL
);
878 if (Private
->ChildHandle
!= NULL
) {
879 Status
= gBS
->CloseProtocol (
880 Private
->ChildHandle
,
882 This
->DriverBindingHandle
,
886 ASSERT (!EFI_ERROR (Status
));
888 Status
= NetLibDestroyServiceChild (
890 This
->DriverBindingHandle
,
891 TcpServiceBindingGuid
,
895 ASSERT (!EFI_ERROR (Status
));
898 gBS
->UninstallProtocolInterface (
901 &Private
->IScsiIdentifier
907 IScsiRemoveNic (IScsiController
);
910 // Update the iSCSI Boot Firware Table.
914 if (Private
->Session
!= NULL
) {
915 IScsiSessionAbort (Private
->Session
);
918 IScsiCleanDriverData (Private
);
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.
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.
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
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
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.
967 IScsiIp4DriverBindingSupported (
968 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
969 IN EFI_HANDLE ControllerHandle
,
970 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
973 return IScsiSupported (
982 Starts a device controller or a bus controller.
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.
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
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.
1018 IScsiIp4DriverBindingStart (
1019 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1020 IN EFI_HANDLE ControllerHandle
,
1021 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
1026 Status
= IScsiStart (This
->DriverBindingHandle
, ControllerHandle
, IP_VERSION_4
);
1027 if (Status
== EFI_ALREADY_STARTED
) {
1028 Status
= EFI_SUCCESS
;
1035 Stops a device controller or a bus controller.
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.
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.
1056 @retval EFI_SUCCESS The device was stopped.
1057 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
1062 IScsiIp4DriverBindingStop (
1063 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1064 IN EFI_HANDLE ControllerHandle
,
1065 IN UINTN NumberOfChildren
,
1066 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
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.
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.
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
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
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.
1122 IScsiIp6DriverBindingSupported (
1123 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1124 IN EFI_HANDLE ControllerHandle
,
1125 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
1128 return IScsiSupported (
1131 RemainingDevicePath
,
1137 Starts a device controller or a bus controller.
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.
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
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.
1173 IScsiIp6DriverBindingStart (
1174 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1175 IN EFI_HANDLE ControllerHandle
,
1176 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
1181 Status
= IScsiStart (This
->DriverBindingHandle
, ControllerHandle
, IP_VERSION_6
);
1182 if (Status
== EFI_ALREADY_STARTED
) {
1183 Status
= EFI_SUCCESS
;
1190 Stops a device controller or a bus controller.
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.
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.
1211 @retval EFI_SUCCESS The device was stopped.
1212 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
1217 IScsiIp6DriverBindingStop (
1218 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1219 IN EFI_HANDLE ControllerHandle
,
1220 IN UINTN NumberOfChildren
,
1221 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
1234 Unload the iSCSI driver.
1236 @param[in] ImageHandle The handle of the driver image.
1238 @retval EFI_SUCCESS The driver is unloaded.
1239 @retval EFI_DEVICE_ERROR An unexpected error occurred.
1245 IN EFI_HANDLE ImageHandle
1249 UINTN DeviceHandleCount
;
1250 EFI_HANDLE
*DeviceHandleBuffer
;
1254 // Try to disonnect the driver from the devices it's controlling.
1256 Status
= gBS
->LocateHandleBuffer (
1263 if (EFI_ERROR (Status
)) {
1267 for (Index
= 0; Index
< DeviceHandleCount
; Index
++) {
1268 gBS
->DisconnectController (
1269 DeviceHandleBuffer
[Index
],
1270 gIScsiIp4DriverBinding
.DriverBindingHandle
,
1273 gBS
->DisconnectController (
1274 DeviceHandleBuffer
[Index
],
1275 gIScsiIp6DriverBinding
.DriverBindingHandle
,
1281 // Unload the iSCSI configuration form.
1283 IScsiConfigFormUnload (gIScsiIp4DriverBinding
.DriverBindingHandle
);
1286 // Uninstall the protocols installed by iSCSI driver.
1288 gBS
->UninstallMultipleProtocolInterfaces (
1290 &gEfiAuthenticationInfoProtocolGuid
,
1291 &gIScsiAuthenticationInfo
,
1295 if (gIScsiControllerNameTable
!= NULL
) {
1296 FreeUnicodeStringTable (gIScsiControllerNameTable
);
1297 gIScsiControllerNameTable
= NULL
;
1300 gBS
->UninstallMultipleProtocolInterfaces (
1301 gIScsiIp4DriverBinding
.DriverBindingHandle
,
1302 &gEfiDriverBindingProtocolGuid
,
1303 &gIScsiIp4DriverBinding
,
1304 &gEfiComponentName2ProtocolGuid
,
1305 &gIScsiComponentName2
,
1306 &gEfiComponentNameProtocolGuid
,
1307 &gIScsiComponentName
,
1308 &gEfiIScsiInitiatorNameProtocolGuid
,
1309 &gIScsiInitiatorName
,
1313 gBS
->UninstallMultipleProtocolInterfaces (
1314 gIScsiIp6DriverBinding
.DriverBindingHandle
,
1315 &gEfiDriverBindingProtocolGuid
,
1316 &gIScsiIp6DriverBinding
,
1317 &gEfiComponentName2ProtocolGuid
,
1318 &gIScsiComponentName2
,
1319 &gEfiComponentNameProtocolGuid
,
1320 &gIScsiComponentName
,
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.
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.
1336 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
1337 @param[in] SystemTable A pointer to the EFI System Table.
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.
1345 IScsiDriverEntryPoint (
1346 IN EFI_HANDLE ImageHandle
,
1347 IN EFI_SYSTEM_TABLE
*SystemTable
1351 EFI_ISCSI_INITIATOR_NAME_PROTOCOL
*IScsiInitiatorName
;
1352 EFI_AUTHENTICATION_INFO_PROTOCOL
*AuthenticationInfo
;
1355 // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.
1357 Status
= gBS
->LocateProtocol (
1358 &gEfiIScsiInitiatorNameProtocolGuid
,
1360 (VOID
**) &IScsiInitiatorName
1362 if (!EFI_ERROR (Status
)) {
1363 return EFI_ACCESS_DENIED
;
1367 // Initialize the EFI Driver Library.
1369 Status
= EfiLibInstallDriverBindingComponentName2 (
1372 &gIScsiIp4DriverBinding
,
1374 &gIScsiComponentName
,
1375 &gIScsiComponentName2
1377 if (EFI_ERROR (Status
)) {
1381 Status
= EfiLibInstallDriverBindingComponentName2 (
1384 &gIScsiIp6DriverBinding
,
1386 &gIScsiComponentName
,
1387 &gIScsiComponentName2
1389 if (EFI_ERROR (Status
)) {
1394 // Install the iSCSI Initiator Name Protocol.
1396 Status
= gBS
->InstallProtocolInterface (
1398 &gEfiIScsiInitiatorNameProtocolGuid
,
1399 EFI_NATIVE_INTERFACE
,
1400 &gIScsiInitiatorName
1402 if (EFI_ERROR (Status
)) {
1407 // Create the private data structures.
1409 mPrivate
= AllocateZeroPool (sizeof (ISCSI_PRIVATE_DATA
));
1410 if (mPrivate
== NULL
) {
1411 Status
= EFI_OUT_OF_RESOURCES
;
1415 InitializeListHead (&mPrivate
->NicInfoList
);
1416 InitializeListHead (&mPrivate
->AttemptConfigs
);
1419 // Initialize the configuration form of iSCSI.
1421 Status
= IScsiConfigFormInit (gIScsiIp4DriverBinding
.DriverBindingHandle
);
1422 if (EFI_ERROR (Status
)) {
1427 // There should be only one EFI_AUTHENTICATION_INFO_PROTOCOL. If already exists,
1428 // do not produce the protocol instance.
1430 Status
= gBS
->LocateProtocol (
1431 &gEfiAuthenticationInfoProtocolGuid
,
1433 (VOID
**) &AuthenticationInfo
1435 if (Status
== EFI_NOT_FOUND
) {
1436 Status
= gBS
->InstallProtocolInterface (
1438 &gEfiAuthenticationInfoProtocolGuid
,
1439 EFI_NATIVE_INTERFACE
,
1440 &gIScsiAuthenticationInfo
1442 if (EFI_ERROR (Status
)) {
1450 IScsiConfigFormUnload (gIScsiIp4DriverBinding
.DriverBindingHandle
);
1453 FreePool (mPrivate
);
1456 gBS
->UninstallMultipleProtocolInterfaces (
1458 &gEfiIScsiInitiatorNameProtocolGuid
,
1459 &gIScsiInitiatorName
,
1464 gBS
->UninstallMultipleProtocolInterfaces (
1465 gIScsiIp6DriverBinding
.DriverBindingHandle
,
1466 &gEfiDriverBindingProtocolGuid
,
1467 &gIScsiIp6DriverBinding
,
1468 &gEfiComponentName2ProtocolGuid
,
1469 &gIScsiComponentName2
,
1470 &gEfiComponentNameProtocolGuid
,
1471 &gIScsiComponentName
,
1476 gBS
->UninstallMultipleProtocolInterfaces (
1478 &gEfiDriverBindingProtocolGuid
,
1479 &gIScsiIp4DriverBinding
,
1480 &gEfiComponentName2ProtocolGuid
,
1481 &gIScsiComponentName2
,
1482 &gEfiComponentNameProtocolGuid
,
1483 &gIScsiComponentName
,