2 The entry point of IScsi driver.
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
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
,
27 Tests to see if this driver supports the RemainingDevicePath.
29 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
30 parameter is ignored by device drivers, and is optional for bus
31 drivers. For bus drivers, if this parameter is not NULL, then
32 the bus driver must determine if the bus controller specified
33 by ControllerHandle and the child controller specified
34 by RemainingDevicePath are both supported by this
37 @retval EFI_SUCCESS The RemainingDevicePath is supported or NULL.
38 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
39 RemainingDevicePath is not supported by the driver specified by This.
42 IScsiIsDevicePathSupported (
43 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
46 EFI_DEVICE_PATH_PROTOCOL
*CurrentDevicePath
;
48 CurrentDevicePath
= RemainingDevicePath
;
49 if (CurrentDevicePath
!= NULL
) {
50 while (!IsDevicePathEnd (CurrentDevicePath
)) {
51 if ((CurrentDevicePath
->Type
== MESSAGING_DEVICE_PATH
) && (CurrentDevicePath
->SubType
== MSG_ISCSI_DP
)) {
55 CurrentDevicePath
= NextDevicePathNode (CurrentDevicePath
);
58 return EFI_UNSUPPORTED
;
65 Tests to see if this driver supports a given controller. If a child device is provided,
66 it further tests to see if this driver supports creating a handle for the specified child device.
68 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
69 @param[in] ControllerHandle The handle of the controller to test. This handle
70 must support a protocol interface that supplies
71 an I/O abstraction to the driver.
72 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
73 This parameter is ignored by device drivers, and is optional for bus drivers.
76 @retval EFI_SUCCESS The device specified by ControllerHandle and
77 RemainingDevicePath is supported by the driver specified by This.
78 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
79 RemainingDevicePath is already being managed by the driver
81 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
82 RemainingDevicePath is already being managed by a different
83 driver or an application that requires exclusive acces.
84 Currently not implemented.
85 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
86 RemainingDevicePath is not supported by the driver specified by This.
90 IScsiDriverBindingSupported (
91 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
92 IN EFI_HANDLE ControllerHandle
,
93 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
98 Status
= gBS
->OpenProtocol (
102 This
->DriverBindingHandle
,
104 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
106 if (!EFI_ERROR (Status
)) {
107 return EFI_ALREADY_STARTED
;
110 Status
= gBS
->OpenProtocol (
112 &gEfiTcp4ServiceBindingProtocolGuid
,
114 This
->DriverBindingHandle
,
116 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
118 if (EFI_ERROR (Status
)) {
119 return EFI_UNSUPPORTED
;
122 Status
= IScsiIsDevicePathSupported (RemainingDevicePath
);
123 if (EFI_ERROR (Status
)) {
124 return EFI_UNSUPPORTED
;
127 if (IScsiDhcpIsConfigured (ControllerHandle
)) {
128 Status
= gBS
->OpenProtocol (
130 &gEfiDhcp4ServiceBindingProtocolGuid
,
132 This
->DriverBindingHandle
,
134 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
136 if (EFI_ERROR (Status
)) {
137 return EFI_UNSUPPORTED
;
145 Start this driver on ControllerHandle.
147 The Start() function is designed to be invoked from the EFI boot service ConnectController().
148 As a result, much of the error checking on the parameters to Start() has been moved into this
149 common boot service. It is legal to call Start() from other locations, but the following calling
150 restrictions must be followed or the system behavior will not be deterministic.
151 1. ControllerHandle must be a valid EFI_HANDLE.
152 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
153 EFI_DEVICE_PATH_PROTOCOL.
154 3. Prior to calling Start(), the Supported() function for the driver specified by This must
155 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
157 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
158 @param[in] ControllerHandle The handle of the controller to start. This handle
159 must support a protocol interface that supplies
160 an I/O abstraction to the driver.
161 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
162 This parameter is ignored by device drivers, and is optional for bus drivers.
164 @retval EFI_SUCCESS The device was started.
165 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.
166 Currently not implemented.
167 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
168 @retval Others The driver failded to start the device.
172 IScsiDriverBindingStart (
173 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
174 IN EFI_HANDLE ControllerHandle
,
175 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
179 ISCSI_DRIVER_DATA
*Private
;
182 Private
= IScsiCreateDriverData (This
->DriverBindingHandle
, ControllerHandle
);
183 if (Private
== NULL
) {
184 return EFI_OUT_OF_RESOURCES
;
188 // Create a underlayer child instance, but not need to configure it. Just open ChildHandle
189 // via BY_DRIVER. That is, establishing the relationship between ControllerHandle and ChildHandle.
190 // Therefore, when DisconnectController(), especially VLAN virtual controller handle,
191 // IScsiDriverBindingStop() will be called.
193 Status
= NetLibCreateServiceChild (
195 This
->DriverBindingHandle
,
196 &gEfiTcp4ServiceBindingProtocolGuid
,
197 &Private
->ChildHandle
200 if (EFI_ERROR (Status
)) {
204 Status
= gBS
->OpenProtocol (
205 Private
->ChildHandle
,
206 &gEfiTcp4ProtocolGuid
,
208 This
->DriverBindingHandle
,
210 EFI_OPEN_PROTOCOL_BY_DRIVER
212 if (EFI_ERROR (Status
)) {
217 // Always install private protocol no matter what happens later. We need to
218 // keep the relationship between ControllerHandle and ChildHandle.
220 Status
= gBS
->InstallProtocolInterface (
223 EFI_NATIVE_INTERFACE
,
224 &Private
->IScsiIdentifier
226 if (EFI_ERROR (Status
)) {
231 // Try to add a port configuration page for this controller.
233 IScsiConfigUpdateForm (This
->DriverBindingHandle
, ControllerHandle
, TRUE
);
236 // Get the iSCSI configuration data of this controller.
238 Status
= IScsiGetConfigData (Private
);
239 if (EFI_ERROR (Status
)) {
243 // Try to login and create an iSCSI session according to the configuration.
245 Status
= IScsiSessionLogin (Private
);
246 if (Status
== EFI_MEDIA_CHANGED
) {
248 // The specified target is not available and the redirection information is
249 // got, login the session again with the updated target address.
251 Status
= IScsiSessionLogin (Private
);
254 if (EFI_ERROR (Status
)) {
258 // Duplicate the Session's tcp connection device path. The source port field
259 // will be set to zero as one iSCSI session is comprised of several iSCSI
262 Private
->DevicePath
= IScsiGetTcpConnDevicePath (Private
);
263 if (Private
->DevicePath
== NULL
) {
267 // Install the updated device path onto the ExtScsiPassThruHandle.
269 Status
= gBS
->InstallProtocolInterface (
270 &Private
->ExtScsiPassThruHandle
,
271 &gEfiDevicePathProtocolGuid
,
272 EFI_NATIVE_INTERFACE
,
275 if (EFI_ERROR (Status
)) {
280 // Update/Publish the iSCSI Boot Firmware Table.
288 IScsiSessionAbort (&Private
->Session
);
294 Stop this driver on ControllerHandle.
296 Release the control of this controller and remove the IScsi functions. The Stop()
297 function is designed to be invoked from the EFI boot service DisconnectController().
298 As a result, much of the error checking on the parameters to Stop() has been moved
299 into this common boot service. It is legal to call Stop() from other locations,
300 but the following calling restrictions must be followed or the system behavior will not be deterministic.
301 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
302 same driver's Start() function.
303 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
304 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
305 Start() function, and the Start() function must have called OpenProtocol() on
306 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
308 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
309 @param[in] ControllerHandle A handle to the device being stopped. The handle must
310 support a bus specific I/O protocol for the driver
311 to use to stop the device.
312 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.Not used.
313 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
314 if NumberOfChildren is 0.Not used.
316 @retval EFI_SUCCESS The device was stopped.
317 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
321 IScsiDriverBindingStop (
322 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
323 IN EFI_HANDLE ControllerHandle
,
324 IN UINTN NumberOfChildren
,
325 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
328 EFI_HANDLE IScsiController
;
330 ISCSI_PRIVATE_PROTOCOL
*IScsiIdentifier
;
331 ISCSI_DRIVER_DATA
*Private
;
332 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*PassThru
;
333 ISCSI_CONNECTION
*Conn
;
335 if (NumberOfChildren
!= 0) {
337 // We should have only one child.
339 Status
= gBS
->OpenProtocol (
340 ChildHandleBuffer
[0],
341 &gEfiExtScsiPassThruProtocolGuid
,
343 This
->DriverBindingHandle
,
345 EFI_OPEN_PROTOCOL_GET_PROTOCOL
347 if (EFI_ERROR (Status
)) {
348 return EFI_DEVICE_ERROR
;
351 Private
= ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru
);
352 Conn
= NET_LIST_HEAD (&Private
->Session
.Conns
, ISCSI_CONNECTION
, Link
);
355 // Previously the TCP4 protocol is opened BY_CHILD_CONTROLLER. Just close
356 // the protocol here but not uninstall the device path protocol and
357 // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.
361 &gEfiTcp4ProtocolGuid
,
363 Private
->ExtScsiPassThruHandle
369 // Get the handle of the controller we are controling.
371 IScsiController
= NetLibGetNicHandle (ControllerHandle
, &gEfiTcp4ProtocolGuid
);
373 Status
= gBS
->OpenProtocol (
376 (VOID
**)&IScsiIdentifier
,
377 This
->DriverBindingHandle
,
379 EFI_OPEN_PROTOCOL_GET_PROTOCOL
381 if (EFI_ERROR (Status
)) {
382 return EFI_DEVICE_ERROR
;
385 Private
= ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier
);
387 if (Private
->ChildHandle
!= NULL
) {
388 Status
= gBS
->CloseProtocol (
389 Private
->ChildHandle
,
390 &gEfiTcp4ProtocolGuid
,
391 This
->DriverBindingHandle
,
395 ASSERT (!EFI_ERROR (Status
));
397 Status
= NetLibDestroyServiceChild (
399 This
->DriverBindingHandle
,
400 &gEfiTcp4ServiceBindingProtocolGuid
,
403 ASSERT (!EFI_ERROR (Status
));
406 IScsiConfigUpdateForm (This
->DriverBindingHandle
, IScsiController
, FALSE
);
409 // Uninstall the private protocol.
411 gBS
->UninstallProtocolInterface (
414 &Private
->IScsiIdentifier
418 // Update the iSCSI Boot Firware Table.
422 IScsiSessionAbort (&Private
->Session
);
423 IScsiCleanDriverData (Private
);
429 Unloads an image(the iSCSI driver).
431 @param[in] ImageHandle Handle that identifies the image to be unloaded.
433 @retval EFI_SUCCESS The image has been unloaded.
434 @retval Others Other errors as indicated.
439 IN EFI_HANDLE ImageHandle
443 UINTN DeviceHandleCount
;
444 EFI_HANDLE
*DeviceHandleBuffer
;
446 EFI_COMPONENT_NAME_PROTOCOL
*ComponentName
;
447 EFI_COMPONENT_NAME2_PROTOCOL
*ComponentName2
;
450 // Try to disonnect the driver from the devices it's controlling.
452 Status
= gBS
->LocateHandleBuffer (
459 if (EFI_ERROR (Status
)) {
463 for (Index
= 0; Index
< DeviceHandleCount
; Index
++) {
464 Status
= IScsiTestManagedDevice (
465 DeviceHandleBuffer
[Index
],
466 gIScsiDriverBinding
.DriverBindingHandle
,
467 &gEfiTcp4ProtocolGuid
469 if (EFI_ERROR (Status
)) {
472 Status
= gBS
->DisconnectController (
473 DeviceHandleBuffer
[Index
],
474 gIScsiDriverBinding
.DriverBindingHandle
,
477 if (EFI_ERROR (Status
)) {
483 // Unload the iSCSI configuration form.
485 Status
= IScsiConfigFormUnload (gIScsiDriverBinding
.DriverBindingHandle
);
486 if (EFI_ERROR (Status
)) {
491 // Uninstall the ComponentName and ComponentName2 protocol from iSCSI4 driver binding handle
492 // if it has been installed.
494 Status
= gBS
->HandleProtocol (
495 gIScsiDriverBinding
.DriverBindingHandle
,
496 &gEfiComponentNameProtocolGuid
,
497 (VOID
**) &ComponentName
499 if (!EFI_ERROR (Status
)) {
500 Status
= gBS
->UninstallMultipleProtocolInterfaces (
501 gIScsiDriverBinding
.DriverBindingHandle
,
502 &gEfiComponentNameProtocolGuid
,
506 if (EFI_ERROR (Status
)) {
511 Status
= gBS
->HandleProtocol (
512 gIScsiDriverBinding
.DriverBindingHandle
,
513 &gEfiComponentName2ProtocolGuid
,
514 (VOID
**) &ComponentName2
516 if (!EFI_ERROR (Status
)) {
517 gBS
->UninstallMultipleProtocolInterfaces (
518 gIScsiDriverBinding
.DriverBindingHandle
,
519 &gEfiComponentName2ProtocolGuid
,
523 if (EFI_ERROR (Status
)) {
528 Status
= gBS
->UninstallMultipleProtocolInterfaces (
530 &gEfiDriverBindingProtocolGuid
,
531 &gIScsiDriverBinding
,
532 &gEfiIScsiInitiatorNameProtocolGuid
,
533 &gIScsiInitiatorName
,
538 if (DeviceHandleBuffer
!= NULL
) {
539 FreePool (DeviceHandleBuffer
);
546 This is the declaration of an EFI image entry point. This entry point is
547 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
548 both device drivers and bus drivers. It initialize the global variables and
549 publish the driver binding protocol.
551 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
552 @param[in] SystemTable A pointer to the EFI System Table.
554 @retval EFI_SUCCESS The operation completed successfully.
555 @retval EFI_ACCESS_DENIED EFI_ISCSI_INITIATOR_NAME_PROTOCOL was installed unexpectedly.
556 @retval Others Other errors as indicated.
560 IScsiDriverEntryPoint (
561 IN EFI_HANDLE ImageHandle
,
562 IN EFI_SYSTEM_TABLE
*SystemTable
566 EFI_ISCSI_INITIATOR_NAME_PROTOCOL
*IScsiInitiatorName
;
569 // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.
571 Status
= gBS
->LocateProtocol (
572 &gEfiIScsiInitiatorNameProtocolGuid
,
574 (VOID
**) &IScsiInitiatorName
577 if (!EFI_ERROR (Status
)) {
578 return EFI_ACCESS_DENIED
;
582 // Initialize the EFI Driver Library
584 Status
= EfiLibInstallDriverBindingComponentName2 (
587 &gIScsiDriverBinding
,
589 &gIScsiComponentName
,
590 &gIScsiComponentName2
593 if (!EFI_ERROR (Status
)) {
595 // Install the iSCSI Initiator Name Protocol.
597 Status
= gBS
->InstallProtocolInterface (
599 &gEfiIScsiInitiatorNameProtocolGuid
,
600 EFI_NATIVE_INTERFACE
,
603 if (EFI_ERROR (Status
)) {
604 gBS
->UninstallMultipleProtocolInterfaces (
606 &gEfiDriverBindingProtocolGuid
,
607 &gIScsiDriverBinding
,
608 &gEfiComponentName2ProtocolGuid
,
609 &gIScsiComponentName2
,
610 &gEfiComponentNameProtocolGuid
,
611 &gIScsiComponentName
,
618 // Initialize the configuration form of iSCSI.
620 Status
= IScsiConfigFormInit ();
621 if (EFI_ERROR (Status
)) {
622 gBS
->UninstallMultipleProtocolInterfaces (
624 &gEfiDriverBindingProtocolGuid
,
625 &gIScsiDriverBinding
,
626 &gEfiComponentName2ProtocolGuid
,
627 &gIScsiComponentName2
,
628 &gEfiComponentNameProtocolGuid
,
629 &gIScsiComponentName
,
630 &gEfiIScsiInitiatorNameProtocolGuid
,
631 &gIScsiInitiatorName
,