2 The entry point of IScsi driver.
4 Copyright (c) 2004 - 2011, 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 gIScsiDriverBinding
= {
18 IScsiDriverBindingSupported
,
19 IScsiDriverBindingStart
,
20 IScsiDriverBindingStop
,
26 EFI_GUID mIScsiV4PrivateGuid
= ISCSI_V4_PRIVATE_GUID
;
27 EFI_GUID mIScsiV6PrivateGuid
= ISCSI_V6_PRIVATE_GUID
;
28 ISCSI_PRIVATE_DATA
*mPrivate
= NULL
;
31 Tests to see if this driver supports the RemainingDevicePath.
33 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
34 parameter is ignored by device drivers, and is optional for bus
35 drivers. For bus drivers, if this parameter is not NULL, then
36 the bus driver must determine if the bus controller specified
37 by ControllerHandle and the child controller specified
38 by RemainingDevicePath are both supported by this
41 @retval EFI_SUCCESS The RemainingDevicePath is supported or NULL.
42 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
43 RemainingDevicePath is not supported by the driver specified by This.
46 IScsiIsDevicePathSupported (
47 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
50 EFI_DEVICE_PATH_PROTOCOL
*CurrentDevicePath
;
52 CurrentDevicePath
= RemainingDevicePath
;
53 if (CurrentDevicePath
!= NULL
) {
54 while (!IsDevicePathEnd (CurrentDevicePath
)) {
55 if ((CurrentDevicePath
->Type
== MESSAGING_DEVICE_PATH
) && (CurrentDevicePath
->SubType
== MSG_ISCSI_DP
)) {
59 CurrentDevicePath
= NextDevicePathNode (CurrentDevicePath
);
62 return EFI_UNSUPPORTED
;
70 Tests to see if this driver supports a given controller. If a child device is provided,
71 it further tests to see if this driver supports creating a handle for the specified child device.
73 This function checks to see if the driver specified by This supports the device specified by
74 ControllerHandle. Drivers typically use the device path attached to
75 ControllerHandle and/or the services from the bus I/O abstraction attached to
76 ControllerHandle to determine if the driver supports ControllerHandle. This function
77 may be called many times during platform initialization. In order to reduce boot times, the tests
78 performed by this function must be very small and take as little time as possible to execute. This
79 function must not change the state of any hardware devices, and this function must be aware that the
80 device specified by ControllerHandle may already be managed by the same driver or a
81 different driver. This function must match its calls to AllocatePages() with FreePages(),
82 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
83 Since ControllerHandle may have been previously started by the same driver, if a protocol is
84 already in the opened state, then it must not be closed with CloseProtocol(). This is required
85 to guarantee the state of ControllerHandle is not modified by this function.
87 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
88 @param[in] ControllerHandle The handle of the controller to test. This handle
89 must support a protocol interface that supplies
90 an I/O abstraction to the driver.
91 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
92 parameter is ignored by device drivers, and is optional for bus
93 drivers. For bus drivers, if this parameter is not NULL, then
94 the bus driver must determine if the bus controller specified
95 by ControllerHandle and the child controller specified
96 by RemainingDevicePath are both supported by this
99 @retval EFI_SUCCESS The device specified by ControllerHandle and
100 RemainingDevicePath is supported by the driver specified by This.
101 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
102 RemainingDevicePath is already being managed by the driver
104 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
105 RemainingDevicePath is already being managed by a different
106 driver or an application that requires exclusive access.
107 Currently not implemented.
108 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
109 RemainingDevicePath is not supported by the driver specified by This.
113 IScsiDriverBindingSupported (
114 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
115 IN EFI_HANDLE ControllerHandle
,
116 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
120 BOOLEAN IsIscsi4Started
;
122 Status
= gBS
->OpenProtocol (
124 &mIScsiV4PrivateGuid
,
126 This
->DriverBindingHandle
,
128 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
130 if (!EFI_ERROR (Status
)) {
131 IsIscsi4Started
= TRUE
;
133 Status
= gBS
->OpenProtocol (
135 &gEfiTcp4ServiceBindingProtocolGuid
,
137 This
->DriverBindingHandle
,
139 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
141 if (!EFI_ERROR (Status
)) {
142 Status
= IScsiIsDevicePathSupported (RemainingDevicePath
);
143 if (!EFI_ERROR (Status
)) {
148 IsIscsi4Started
= FALSE
;
151 Status
= gBS
->OpenProtocol (
153 &mIScsiV6PrivateGuid
,
155 This
->DriverBindingHandle
,
157 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
159 if (!EFI_ERROR (Status
)) {
160 if (IsIscsi4Started
) {
161 return EFI_ALREADY_STARTED
;
164 Status
= gBS
->OpenProtocol (
166 &gEfiTcp6ServiceBindingProtocolGuid
,
168 This
->DriverBindingHandle
,
170 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
172 if (!EFI_ERROR (Status
)) {
173 Status
= IScsiIsDevicePathSupported (RemainingDevicePath
);
174 if (!EFI_ERROR (Status
)) {
180 return EFI_UNSUPPORTED
;
185 Start to manage the controller. This is the worker function for
186 IScsiDriverBindingStart.
188 @param[in] Image Handle of the image.
189 @param[in] ControllerHandle Handle of the controller.
190 @param[in] IpVersion Ip4 or Ip6
192 @retval EFI_SUCCES This driver supports this device.
193 @retval EFI_ALREADY_STARTED This driver is already running on this device.
194 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
195 @retval EFI_NOT_FOUND There is no sufficient information to establish
197 @retval EFI_DEVICE_ERROR Failed to get TCP connection device path.
203 IN EFI_HANDLE ControllerHandle
,
208 ISCSI_DRIVER_DATA
*Private
;
210 LIST_ENTRY
*NextEntry
;
211 ISCSI_ATTEMPT_CONFIG_NVDATA
*AttemptConfigData
;
212 ISCSI_SESSION
*Session
;
214 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExistIScsiExtScsiPassThru
;
215 ISCSI_DRIVER_DATA
*ExistPrivate
;
216 UINT8
*AttemptConfigOrder
;
217 UINTN AttemptConfigOrderSize
;
219 EFI_HANDLE
*HandleBuffer
;
220 UINTN NumberOfHandles
;
221 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
222 EFI_GUID
*IScsiPrivateGuid
;
223 EFI_GUID
*TcpServiceBindingGuid
;
224 CHAR16 MacString
[ISCSI_MAX_MAC_STRING_LEN
];
227 EFI_GUID
*ProtocolGuid
;
230 // Test to see if iSCSI driver supports the given controller.
233 if (IpVersion
== IP_VERSION_4
) {
234 IScsiPrivateGuid
= &mIScsiV4PrivateGuid
;
235 TcpServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
236 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
237 } else if (IpVersion
== IP_VERSION_6
) {
238 IScsiPrivateGuid
= &mIScsiV6PrivateGuid
;
239 TcpServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
240 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
242 return EFI_INVALID_PARAMETER
;
245 Status
= gBS
->OpenProtocol (
251 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
253 if (!EFI_ERROR (Status
)) {
254 return EFI_ALREADY_STARTED
;
257 Status
= gBS
->OpenProtocol (
259 TcpServiceBindingGuid
,
263 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
265 if (EFI_ERROR (Status
)) {
266 return EFI_UNSUPPORTED
;
270 // Record the incoming NIC info.
272 Status
= IScsiAddNic (ControllerHandle
);
273 if (EFI_ERROR (Status
)) {
278 // Create the instance private data.
280 Private
= IScsiCreateDriverData (Image
, ControllerHandle
);
281 if (Private
== NULL
) {
282 return EFI_OUT_OF_RESOURCES
;
286 // Create a underlayer child instance, but not need to configure it. Just open ChildHandle
287 // via BY_DRIVER. That is, establishing the relationship between ControllerHandle and ChildHandle.
288 // Therefore, when DisconnectController(), especially VLAN virtual controller handle,
289 // IScsiDriverBindingStop() will be called.
291 Status
= NetLibCreateServiceChild (
294 TcpServiceBindingGuid
,
295 &Private
->ChildHandle
298 if (EFI_ERROR (Status
)) {
302 Status
= gBS
->OpenProtocol (
303 Private
->ChildHandle
,
308 EFI_OPEN_PROTOCOL_BY_DRIVER
311 if (EFI_ERROR (Status
)) {
316 // Always install private protocol no matter what happens later. We need to
317 // keep the relationship between ControllerHandle and ChildHandle.
319 Status
= gBS
->InstallProtocolInterface (
322 EFI_NATIVE_INTERFACE
,
323 &Private
->IScsiIdentifier
325 if (EFI_ERROR (Status
)) {
329 if (IpVersion
== IP_VERSION_4
) {
330 mPrivate
->Ipv6Flag
= FALSE
;
332 mPrivate
->Ipv6Flag
= TRUE
;
336 // Get the current iSCSI configuration data.
338 Status
= IScsiGetConfigData (Private
);
339 if (EFI_ERROR (Status
)) {
344 // If there is already a successul attempt, check whether this attempt is the
345 // first "enabled for MPIO" attempt. If not, still try the first attempt.
346 // In single path mode, try all attempts.
349 Status
= EFI_NOT_FOUND
;
351 if (mPrivate
->OneSessionEstablished
&& mPrivate
->EnableMpio
) {
352 AttemptConfigData
= NULL
;
353 NET_LIST_FOR_EACH (Entry
, &mPrivate
->AttemptConfigs
) {
354 AttemptConfigData
= NET_LIST_USER_STRUCT (Entry
, ISCSI_ATTEMPT_CONFIG_NVDATA
, Link
);
355 if (AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_ENABLED_FOR_MPIO
) {
360 if (AttemptConfigData
== NULL
) {
364 if (AttemptConfigData
->AttemptConfigIndex
== mPrivate
->BootSelectedIndex
) {
369 // Uninstall the original ExtScsiPassThru first.
373 // Locate all ExtScsiPassThru protocol instances.
375 Status
= gBS
->LocateHandleBuffer (
377 &gEfiExtScsiPassThruProtocolGuid
,
382 if (EFI_ERROR (Status
)) {
387 // Find ExtScsiPassThru protocol instance produced by this driver.
389 ExistIScsiExtScsiPassThru
= NULL
;
390 for (Index
= 0; Index
< NumberOfHandles
&& ExistIScsiExtScsiPassThru
== NULL
; Index
++) {
391 Status
= gBS
->HandleProtocol (
393 &gEfiDevicePathProtocolGuid
,
394 (VOID
**) &DevicePath
396 if (EFI_ERROR (Status
)) {
400 while (!IsDevicePathEnd (DevicePath
)) {
401 if ((DevicePath
->Type
== MESSAGING_DEVICE_PATH
) && (DevicePath
->SubType
== MSG_MAC_ADDR_DP
)) {
403 // Get the ExtScsiPassThru protocol instance.
405 Status
= gBS
->HandleProtocol (
407 &gEfiExtScsiPassThruProtocolGuid
,
408 (VOID
**) &ExistIScsiExtScsiPassThru
410 ASSERT_EFI_ERROR (Status
);
414 DevicePath
= NextDevicePathNode (DevicePath
);
418 FreePool (HandleBuffer
);
420 if (ExistIScsiExtScsiPassThru
== NULL
) {
421 Status
= EFI_NOT_FOUND
;
425 ExistPrivate
= ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (ExistIScsiExtScsiPassThru
);
427 Status
= gBS
->UninstallProtocolInterface (
428 ExistPrivate
->ExtScsiPassThruHandle
,
429 &gEfiExtScsiPassThruProtocolGuid
,
430 &ExistPrivate
->IScsiExtScsiPassThru
432 if (EFI_ERROR (Status
)) {
438 // Install the Ext SCSI PASS THRU protocol.
440 Status
= gBS
->InstallProtocolInterface (
441 &Private
->ExtScsiPassThruHandle
,
442 &gEfiExtScsiPassThruProtocolGuid
,
443 EFI_NATIVE_INTERFACE
,
444 &Private
->IScsiExtScsiPassThru
446 if (EFI_ERROR (Status
)) {
452 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &mPrivate
->AttemptConfigs
) {
453 AttemptConfigData
= NET_LIST_USER_STRUCT (Entry
, ISCSI_ATTEMPT_CONFIG_NVDATA
, Link
);
455 // Don't process the attempt that does not associate with the current NIC or
456 // this attempt is disabled or established.
458 if (AttemptConfigData
->NicIndex
!= mPrivate
->CurrentNic
||
459 AttemptConfigData
->SessionConfigData
.Enabled
== ISCSI_DISABLED
||
460 AttemptConfigData
->ValidPath
) {
465 // In multipath mode, don't process attempts configured for single path.
466 // In default single path mode, don't process attempts configured for multipath.
468 if ((mPrivate
->EnableMpio
&&
469 AttemptConfigData
->SessionConfigData
.Enabled
!= ISCSI_ENABLED_FOR_MPIO
) ||
470 (!mPrivate
->EnableMpio
&&
471 AttemptConfigData
->SessionConfigData
.Enabled
!= ISCSI_ENABLED
)) {
476 // Don't process the attempt that fails to get the init/target information from DHCP.
478 if (AttemptConfigData
->SessionConfigData
.InitiatorInfoFromDhcp
&&
479 !AttemptConfigData
->DhcpSuccess
) {
480 if (!mPrivate
->EnableMpio
&& mPrivate
->ValidSinglePathCount
> 0) {
481 mPrivate
->ValidSinglePathCount
--;
487 // Don't process the autoconfigure path if it is already established.
489 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
&&
490 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_SUCCESS
) {
495 // Don't process the attempt if its IP mode is not in the current IP version.
497 if (!mPrivate
->Ipv6Flag
) {
498 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP6
) {
501 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
&&
502 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP6
) {
506 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_IP4
) {
509 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
&&
510 AttemptConfigData
->AutoConfigureMode
== IP_MODE_AUTOCONFIG_IP4
) {
516 // Fill in the Session and init it.
518 Session
= (ISCSI_SESSION
*) AllocateZeroPool (sizeof (ISCSI_SESSION
));
519 if (Session
== NULL
) {
520 Status
= EFI_OUT_OF_RESOURCES
;
524 Session
->Private
= Private
;
525 Session
->ConfigData
= AttemptConfigData
;
526 Session
->AuthType
= AttemptConfigData
->AuthenticationType
;
528 AsciiStrToUnicodeStr (AttemptConfigData
->MacString
, MacString
);
530 mPrivate
->PortString
,
531 (UINTN
) ISCSI_NAME_IFR_MAX_SIZE
,
534 (UINTN
) AttemptConfigData
->AttemptConfigIndex
537 if (Session
->AuthType
== ISCSI_AUTH_TYPE_CHAP
) {
538 Session
->AuthData
.CHAP
.AuthConfig
= &AttemptConfigData
->AuthConfigData
.CHAP
;
541 IScsiSessionInit (Session
, FALSE
);
544 // Try to login and create an iSCSI session according to the configuration.
546 Status
= IScsiSessionLogin (Session
);
547 if (Status
== EFI_MEDIA_CHANGED
) {
549 // The specified target is not available, and the redirection information is
550 // received. Login the session again with the updated target address.
552 Status
= IScsiSessionLogin (Session
);
553 } else if (Status
== EFI_NOT_READY
) {
554 Status
= IScsiSessionReLogin (Session
);
557 if (EFI_ERROR (Status
)) {
559 // In Single path mode, only the successful attempt will be recorded in iBFT;
560 // in multi-path mode, all the attempt entries in MPIO will be recorded in iBFT.
562 if (!mPrivate
->EnableMpio
&& mPrivate
->ValidSinglePathCount
> 0) {
563 mPrivate
->ValidSinglePathCount
--;
569 AttemptConfigData
->ValidPath
= TRUE
;
572 // Do not record the attempt in iBFT if it login with KRB5.
573 // TODO: record KRB5 attempt information in the iSCSI device path.
575 if (Session
->AuthType
== ISCSI_AUTH_TYPE_KRB
) {
576 if (!mPrivate
->EnableMpio
&& mPrivate
->ValidSinglePathCount
> 0) {
577 mPrivate
->ValidSinglePathCount
--;
580 AttemptConfigData
->ValidiBFTPath
= FALSE
;
582 AttemptConfigData
->ValidiBFTPath
= TRUE
;
586 // IScsi session success. Update the attempt state to NVR.
588 if (AttemptConfigData
->SessionConfigData
.IpMode
== IP_MODE_AUTOCONFIG
) {
589 AttemptConfigData
->AutoConfigureMode
= IP_MODE_AUTOCONFIG_SUCCESS
;
593 mPrivate
->PortString
,
594 &gEfiIScsiInitiatorNameProtocolGuid
,
595 ISCSI_CONFIG_VAR_ATTR
,
596 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA
),
601 // Select the first login session. Abort others.
603 if (Private
->Session
== NULL
) {
604 Private
->Session
= Session
;
605 BootSelected
= AttemptConfigData
->AttemptConfigIndex
;
607 // Don't validate other attempt in multipath mode if one is success.
609 if (mPrivate
->EnableMpio
) {
613 IScsiSessionAbort (Session
);
620 // All attempts configured for this driver instance are not valid.
622 if (Private
->Session
== NULL
) {
623 Status
= gBS
->UninstallProtocolInterface (
624 Private
->ExtScsiPassThruHandle
,
625 &gEfiExtScsiPassThruProtocolGuid
,
626 &Private
->IScsiExtScsiPassThru
628 ASSERT_EFI_ERROR (Status
);
629 Private
->ExtScsiPassThruHandle
= NULL
;
632 // Reinstall the original ExtScsiPassThru back.
634 if (mPrivate
->OneSessionEstablished
&& ExistPrivate
!= NULL
) {
635 Status
= gBS
->InstallProtocolInterface (
636 &ExistPrivate
->ExtScsiPassThruHandle
,
637 &gEfiExtScsiPassThruProtocolGuid
,
638 EFI_NATIVE_INTERFACE
,
639 &ExistPrivate
->IScsiExtScsiPassThru
641 if (EFI_ERROR (Status
)) {
648 Status
= EFI_NOT_FOUND
;
655 // More than one attempt successes.
657 if (Private
->Session
!= NULL
&& mPrivate
->OneSessionEstablished
) {
659 AttemptConfigOrder
= IScsiGetVariableAndSize (
662 &AttemptConfigOrderSize
664 ASSERT (AttemptConfigOrder
!= NULL
);
665 for (Index
= 0; Index
< AttemptConfigOrderSize
/ sizeof (UINT8
); Index
++) {
666 if (AttemptConfigOrder
[Index
] == mPrivate
->BootSelectedIndex
||
667 AttemptConfigOrder
[Index
] == BootSelected
) {
672 if (mPrivate
->EnableMpio
) {
674 // Use the attempt in earlier order. Abort the later one in MPIO.
676 if (AttemptConfigOrder
[Index
] == mPrivate
->BootSelectedIndex
) {
677 IScsiSessionAbort (Private
->Session
);
678 FreePool (Private
->Session
);
679 Private
->Session
= NULL
;
680 gBS
->UninstallProtocolInterface (
681 Private
->ExtScsiPassThruHandle
,
682 &gEfiExtScsiPassThruProtocolGuid
,
683 &Private
->IScsiExtScsiPassThru
685 Private
->ExtScsiPassThruHandle
= NULL
;
688 // Reinstall the original ExtScsiPassThru back.
690 Status
= gBS
->InstallProtocolInterface (
691 &ExistPrivate
->ExtScsiPassThruHandle
,
692 &gEfiExtScsiPassThruProtocolGuid
,
693 EFI_NATIVE_INTERFACE
,
694 &ExistPrivate
->IScsiExtScsiPassThru
696 if (EFI_ERROR (Status
)) {
702 ASSERT (AttemptConfigOrder
[Index
] == BootSelected
);
703 mPrivate
->BootSelectedIndex
= BootSelected
;
705 // Clear the resource in ExistPrivate.
707 gBS
->UninstallProtocolInterface (
708 ExistPrivate
->Controller
,
710 &ExistPrivate
->IScsiIdentifier
713 IScsiRemoveNic (ExistPrivate
->Controller
);
714 if (ExistPrivate
->Session
!= NULL
) {
715 IScsiSessionAbort (ExistPrivate
->Session
);
718 IScsiCleanDriverData (ExistPrivate
);
722 // Use the attempt in earlier order as boot selected in single path mode.
724 if (AttemptConfigOrder
[Index
] == mPrivate
->BootSelectedIndex
) {
732 mPrivate
->OneSessionEstablished
= TRUE
;
733 mPrivate
->BootSelectedIndex
= BootSelected
;
737 // Duplicate the Session's tcp connection device path. The source port field
738 // will be set to zero as one iSCSI session is comprised of several iSCSI
741 Private
->DevicePath
= IScsiGetTcpConnDevicePath (Private
->Session
);
742 if (Private
->DevicePath
== NULL
) {
743 Status
= EFI_DEVICE_ERROR
;
747 // Install the updated device path onto the ExtScsiPassThruHandle.
749 Status
= gBS
->InstallProtocolInterface (
750 &Private
->ExtScsiPassThruHandle
,
751 &gEfiDevicePathProtocolGuid
,
752 EFI_NATIVE_INTERFACE
,
755 if (EFI_ERROR (Status
)) {
762 // Update/Publish the iSCSI Boot Firmware Table.
764 if (mPrivate
->BootSelectedIndex
!= 0) {
772 if (Private
->Session
!= NULL
) {
773 IScsiSessionAbort (Private
->Session
);
780 Starts a device controller or a bus controller.
782 The Start() function is designed to be invoked from the EFI boot service ConnectController().
783 As a result, much of the error checking on the parameters to Start() has been moved into this
784 common boot service. It is legal to call Start() from other locations,
785 but the following calling restrictions must be followed or the system behavior will not be deterministic.
786 1. ControllerHandle must be a valid EFI_HANDLE.
787 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
788 EFI_DEVICE_PATH_PROTOCOL.
789 3. Prior to calling Start(), the Supported() function for the driver specified by This must
790 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
792 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
793 @param[in] ControllerHandle The handle of the controller to start. This handle
794 must support a protocol interface that supplies
795 an I/O abstraction to the driver.
796 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
797 parameter is ignored by device drivers, and is optional for bus
798 drivers. For a bus driver, if this parameter is NULL, then handles
799 for all the children of Controller are created by this driver.
800 If this parameter is not NULL and the first Device Path Node is
801 not the End of Device Path Node, then only the handle for the
802 child device specified by the first Device Path Node of
803 RemainingDevicePath is created by this driver.
804 If the first Device Path Node of RemainingDevicePath is
805 the End of Device Path Node, no child handle is created by this
808 @retval EFI_SUCCESS The device was started.
809 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
810 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
811 @retval Others The driver failed to start the device.
816 IScsiDriverBindingStart (
817 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
818 IN EFI_HANDLE ControllerHandle
,
819 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
825 V4Status
= IScsiStart (This
->DriverBindingHandle
, ControllerHandle
, IP_VERSION_4
);
826 if (V4Status
== EFI_ALREADY_STARTED
) {
827 V4Status
= EFI_SUCCESS
;
830 V6Status
= IScsiStart (This
->DriverBindingHandle
, ControllerHandle
, IP_VERSION_6
);
831 if (V6Status
== EFI_ALREADY_STARTED
) {
832 V6Status
= EFI_SUCCESS
;
835 if (!EFI_ERROR (V4Status
) || !EFI_ERROR (V6Status
)) {
837 } else if (EFI_ERROR (V4Status
)) {
845 Stops a device controller or a bus controller.
847 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
848 As a result, much of the error checking on the parameters to Stop() has been moved
849 into this common boot service. It is legal to call Stop() from other locations,
850 but the following calling restrictions must be followed or the system behavior will not be deterministic.
851 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
852 same driver's Start() function.
853 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
854 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
855 Start() function, and the Start() function must have called OpenProtocol() on
856 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
858 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
859 @param[in] ControllerHandle A handle to the device being stopped. The handle must
860 support a bus specific I/O protocol for the driver
861 to use to stop the device.
862 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
863 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
864 if NumberOfChildren is 0.
866 @retval EFI_SUCCESS The device was stopped.
867 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
872 IScsiDriverBindingStop (
873 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
874 IN EFI_HANDLE ControllerHandle
,
875 IN UINTN NumberOfChildren
,
876 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
879 EFI_HANDLE IScsiController
;
881 ISCSI_PRIVATE_PROTOCOL
*IScsiIdentifier
;
882 ISCSI_DRIVER_DATA
*Private
;
883 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
884 ISCSI_CONNECTION
*Conn
;
885 EFI_GUID
*ProtocolGuid
;
886 EFI_GUID
*TcpServiceBindingGuid
;
887 EFI_GUID
*TcpProtocolGuid
;
890 if (NumberOfChildren
!= 0) {
892 // We should have only one child.
894 Status
= gBS
->OpenProtocol (
895 ChildHandleBuffer
[0],
896 &gEfiExtScsiPassThruProtocolGuid
,
898 This
->DriverBindingHandle
,
900 EFI_OPEN_PROTOCOL_GET_PROTOCOL
902 if (EFI_ERROR (Status
)) {
903 return EFI_DEVICE_ERROR
;
906 Private
= ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru
);
907 Conn
= NET_LIST_HEAD (&Private
->Session
->Conns
, ISCSI_CONNECTION
, Link
);
910 // Previously the TCP protocol is opened BY_CHILD_CONTROLLER. Just close
911 // the protocol here, but do not uninstall the device path protocol and
912 // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.
914 if (!Conn
->Ipv6Flag
) {
915 ProtocolGuid
= &gEfiTcp4ProtocolGuid
;
917 ProtocolGuid
= &gEfiTcp6ProtocolGuid
;
924 Private
->ExtScsiPassThruHandle
930 // Get the handle of the controller we are controling.
932 IScsiController
= NetLibGetNicHandle (ControllerHandle
, &gEfiTcp4ProtocolGuid
);
933 if (IScsiController
!= NULL
) {
934 ProtocolGuid
= &mIScsiV4PrivateGuid
;
935 TcpProtocolGuid
= &gEfiTcp4ProtocolGuid
;
936 TcpServiceBindingGuid
= &gEfiTcp4ServiceBindingProtocolGuid
;
938 IScsiController
= NetLibGetNicHandle (ControllerHandle
, &gEfiTcp6ProtocolGuid
);
939 ASSERT (IScsiController
!= NULL
);
940 ProtocolGuid
= &mIScsiV6PrivateGuid
;
941 TcpProtocolGuid
= &gEfiTcp6ProtocolGuid
;
942 TcpServiceBindingGuid
= &gEfiTcp6ServiceBindingProtocolGuid
;
945 Status
= gBS
->OpenProtocol (
948 (VOID
**) &IScsiIdentifier
,
949 This
->DriverBindingHandle
,
951 EFI_OPEN_PROTOCOL_GET_PROTOCOL
953 if (EFI_ERROR (Status
)) {
954 return EFI_DEVICE_ERROR
;
957 Private
= ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier
);
958 ASSERT (Private
!= NULL
);
960 if (Private
->ChildHandle
!= NULL
) {
961 Status
= gBS
->CloseProtocol (
962 Private
->ChildHandle
,
964 This
->DriverBindingHandle
,
968 ASSERT (!EFI_ERROR (Status
));
970 Status
= NetLibDestroyServiceChild (
972 This
->DriverBindingHandle
,
973 TcpServiceBindingGuid
,
977 ASSERT (!EFI_ERROR (Status
));
980 gBS
->UninstallProtocolInterface (
983 &Private
->IScsiIdentifier
989 IScsiRemoveNic (IScsiController
);
992 // Update the iSCSI Boot Firware Table.
996 if (Private
->Session
!= NULL
) {
997 IScsiSessionAbort (Private
->Session
);
1000 IScsiCleanDriverData (Private
);
1007 Unload the iSCSI driver.
1009 @param[in] ImageHandle The handle of the driver image.
1011 @retval EFI_SUCCESS The driver is unloaded.
1012 @retval EFI_DEVICE_ERROR An unexpected error occurred.
1018 IN EFI_HANDLE ImageHandle
1022 UINTN DeviceHandleCount
;
1023 EFI_HANDLE
*DeviceHandleBuffer
;
1027 // Try to disonnect the driver from the devices it's controlling.
1029 Status
= gBS
->LocateHandleBuffer (
1036 if (!EFI_ERROR (Status
)) {
1037 for (Index
= 0; Index
< DeviceHandleCount
; Index
++) {
1038 Status
= gBS
->DisconnectController (
1039 DeviceHandleBuffer
[Index
],
1045 if (DeviceHandleBuffer
!= NULL
) {
1046 FreePool (DeviceHandleBuffer
);
1050 // Unload the iSCSI configuration form.
1052 IScsiConfigFormUnload (gIScsiDriverBinding
.DriverBindingHandle
);
1055 // Uninstall the protocols installed by iSCSI driver.
1057 gBS
->UninstallMultipleProtocolInterfaces (
1059 &gEfiAuthenticationInfoProtocolGuid
,
1060 &gIScsiAuthenticationInfo
,
1064 return gBS
->UninstallMultipleProtocolInterfaces (
1066 &gEfiDriverBindingProtocolGuid
,
1067 &gIScsiDriverBinding
,
1068 &gEfiComponentName2ProtocolGuid
,
1069 &gIScsiComponentName2
,
1070 &gEfiComponentNameProtocolGuid
,
1071 &gIScsiComponentName
,
1072 &gEfiIScsiInitiatorNameProtocolGuid
,
1073 &gIScsiInitiatorName
,
1079 This is the declaration of an EFI image entry point. This entry point is
1080 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
1081 both device drivers and bus drivers.
1083 The entry point for iSCSI driver which initializes the global variables and
1084 installs the driver binding, component name protocol, iSCSI initiator name
1085 protocol and Authentication Info protocol on its image.
1087 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
1088 @param[in] SystemTable A pointer to the EFI System Table.
1090 @retval EFI_SUCCESS The operation completed successfully.
1091 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1096 IScsiDriverEntryPoint (
1097 IN EFI_HANDLE ImageHandle
,
1098 IN EFI_SYSTEM_TABLE
*SystemTable
1102 EFI_ISCSI_INITIATOR_NAME_PROTOCOL
*IScsiInitiatorName
;
1103 EFI_AUTHENTICATION_INFO_PROTOCOL
*AuthenticationInfo
;
1106 // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.
1108 Status
= gBS
->LocateProtocol (
1109 &gEfiIScsiInitiatorNameProtocolGuid
,
1111 (VOID
**) &IScsiInitiatorName
1113 if (!EFI_ERROR (Status
)) {
1114 return EFI_ACCESS_DENIED
;
1118 // Initialize the EFI Driver Library.
1120 Status
= EfiLibInstallDriverBindingComponentName2 (
1123 &gIScsiDriverBinding
,
1125 &gIScsiComponentName
,
1126 &gIScsiComponentName2
1128 if (EFI_ERROR (Status
)) {
1133 // Install the iSCSI Initiator Name Protocol.
1135 Status
= gBS
->InstallProtocolInterface (
1137 &gEfiIScsiInitiatorNameProtocolGuid
,
1138 EFI_NATIVE_INTERFACE
,
1139 &gIScsiInitiatorName
1141 if (EFI_ERROR (Status
)) {
1146 // Create the private data structures.
1148 mPrivate
= AllocateZeroPool (sizeof (ISCSI_PRIVATE_DATA
));
1149 if (mPrivate
== NULL
) {
1150 Status
= EFI_OUT_OF_RESOURCES
;
1154 InitializeListHead (&mPrivate
->NicInfoList
);
1155 InitializeListHead (&mPrivate
->AttemptConfigs
);
1158 // Initialize the configuration form of iSCSI.
1160 Status
= IScsiConfigFormInit (gIScsiDriverBinding
.DriverBindingHandle
);
1161 if (EFI_ERROR (Status
)) {
1166 // There should be only one EFI_AUTHENTICATION_INFO_PROTOCOL. If already exists,
1167 // do not produce the protocol instance.
1169 Status
= gBS
->LocateProtocol (
1170 &gEfiAuthenticationInfoProtocolGuid
,
1172 (VOID
**) &AuthenticationInfo
1174 if (Status
== EFI_NOT_FOUND
) {
1175 Status
= gBS
->InstallProtocolInterface (
1177 &gEfiAuthenticationInfoProtocolGuid
,
1178 EFI_NATIVE_INTERFACE
,
1179 &gIScsiAuthenticationInfo
1181 if (EFI_ERROR (Status
)) {
1189 IScsiConfigFormUnload (gIScsiDriverBinding
.DriverBindingHandle
);
1192 FreePool (mPrivate
);
1195 gBS
->UninstallMultipleProtocolInterfaces (
1197 &gEfiIScsiInitiatorNameProtocolGuid
,
1198 &gIScsiInitiatorName
,
1203 gBS
->UninstallMultipleProtocolInterfaces (
1205 &gEfiDriverBindingProtocolGuid
,
1206 &gIScsiDriverBinding
,
1207 &gEfiComponentName2ProtocolGuid
,
1208 &gIScsiComponentName2
,
1209 &gEfiComponentNameProtocolGuid
,
1210 &gIScsiComponentName
,