]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/IScsiDxe/IScsiDriver.c
Update network drivers to use FreePool() instead of gBS->FreePool().
[mirror_edk2.git] / MdeModulePkg / Universal / Network / IScsiDxe / IScsiDriver.c
1 /** @file
2 The entry point of IScsi driver.
3
4 Copyright (c) 2004 - 2009, Intel Corporation.<BR>
5 All rights reserved. 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 gIScsiDriverBinding = {
18 IScsiDriverBindingSupported,
19 IScsiDriverBindingStart,
20 IScsiDriverBindingStop,
21 0xa,
22 NULL,
23 NULL
24 };
25
26 EFI_GUID gIScsiPrivateGuid = ISCSI_PRIVATE_GUID;
27
28
29 /**
30 Tests to see if this driver supports a given controller. If a child device is provided,
31 it further tests to see if this driver supports creating a handle for the specified child device.
32
33 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
34 @param[in] ControllerHandle The handle of the controller to test. This handle
35 must support a protocol interface that supplies
36 an I/O abstraction to the driver.
37 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
38 This parameter is ignored by device drivers, and is optional for bus drivers.
39
40
41 @retval EFI_SUCCESS The device specified by ControllerHandle and
42 RemainingDevicePath is supported by the driver specified by This.
43 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
44 RemainingDevicePath is already being managed by the driver
45 specified by This.
46 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
47 RemainingDevicePath is already being managed by a different
48 driver or an application that requires exclusive acces.
49 Currently not implemented.
50 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
51 RemainingDevicePath is not supported by the driver specified by This.
52 **/
53 EFI_STATUS
54 EFIAPI
55 IScsiDriverBindingSupported (
56 IN EFI_DRIVER_BINDING_PROTOCOL *This,
57 IN EFI_HANDLE ControllerHandle,
58 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
59 )
60 {
61 EFI_STATUS Status;
62 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
63
64 Status = gBS->OpenProtocol (
65 ControllerHandle,
66 &gIScsiPrivateGuid,
67 NULL,
68 This->DriverBindingHandle,
69 ControllerHandle,
70 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
71 );
72 if (!EFI_ERROR (Status)) {
73 return EFI_ALREADY_STARTED;
74 }
75
76 Status = gBS->OpenProtocol (
77 ControllerHandle,
78 &gEfiTcp4ServiceBindingProtocolGuid,
79 NULL,
80 This->DriverBindingHandle,
81 ControllerHandle,
82 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
83 );
84 if (EFI_ERROR (Status)) {
85 return EFI_UNSUPPORTED;
86 }
87
88 CurrentDevicePath = RemainingDevicePath;
89 if (CurrentDevicePath != NULL) {
90 while (!IsDevicePathEnd (CurrentDevicePath)) {
91 if ((CurrentDevicePath->Type == MESSAGING_DEVICE_PATH) && (CurrentDevicePath->SubType == MSG_ISCSI_DP)) {
92 return EFI_SUCCESS;
93 }
94
95 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
96 }
97
98 return EFI_UNSUPPORTED;
99 }
100
101 return EFI_SUCCESS;
102 }
103
104 /**
105 Start this driver on ControllerHandle.
106
107 The Start() function is designed to be invoked from the EFI boot service ConnectController().
108 As a result, much of the error checking on the parameters to Start() has been moved into this
109 common boot service. It is legal to call Start() from other locations, but the following calling
110 restrictions must be followed or the system behavior will not be deterministic.
111 1. ControllerHandle must be a valid EFI_HANDLE.
112 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
113 EFI_DEVICE_PATH_PROTOCOL.
114 3. Prior to calling Start(), the Supported() function for the driver specified by This must
115 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
116
117 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
118 @param[in] ControllerHandle The handle of the controller to start. This handle
119 must support a protocol interface that supplies
120 an I/O abstraction to the driver.
121 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
122 This parameter is ignored by device drivers, and is optional for bus drivers.
123
124 @retval EFI_SUCCESS The device was started.
125 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.
126 Currently not implemented.
127 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
128 @retval Others The driver failded to start the device.
129 **/
130 EFI_STATUS
131 EFIAPI
132 IScsiDriverBindingStart (
133 IN EFI_DRIVER_BINDING_PROTOCOL *This,
134 IN EFI_HANDLE ControllerHandle,
135 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
136 )
137 {
138 EFI_STATUS Status;
139 ISCSI_DRIVER_DATA *Private;
140
141 //
142 // Try to add a port configuration page for this controller.
143 //
144 IScsiConfigUpdateForm (This->DriverBindingHandle, ControllerHandle, TRUE);
145
146 Private = IScsiCreateDriverData (This->DriverBindingHandle, ControllerHandle);
147 if (Private == NULL) {
148 return EFI_OUT_OF_RESOURCES;
149 }
150 //
151 // Get the iSCSI configuration data of this controller.
152 //
153 Status = IScsiGetConfigData (Private);
154 if (EFI_ERROR (Status)) {
155 goto ON_ERROR;
156 }
157 //
158 // Try to login and create an iSCSI session according to the configuration.
159 //
160 Status = IScsiSessionLogin (Private);
161 if (Status == EFI_MEDIA_CHANGED) {
162 //
163 // The specified target is not available and the redirection information is
164 // got, login the session again with the updated target address.
165 //
166 Status = IScsiSessionLogin (Private);
167 }
168
169 if (EFI_ERROR (Status)) {
170 goto ON_ERROR;
171 }
172 //
173 // Duplicate the Session's tcp connection device path. The source port field
174 // will be set to zero as one iSCSI session is comprised of several iSCSI
175 // connections.
176 //
177 Private->DevicePath = IScsiGetTcpConnDevicePath (Private);
178 if (Private->DevicePath == NULL) {
179 goto ON_ERROR;
180 }
181 //
182 // Install the updated device path onto the ExtScsiPassThruHandle.
183 //
184 Status = gBS->InstallProtocolInterface (
185 &Private->ExtScsiPassThruHandle,
186 &gEfiDevicePathProtocolGuid,
187 EFI_NATIVE_INTERFACE,
188 Private->DevicePath
189 );
190 if (EFI_ERROR (Status)) {
191 goto ON_ERROR;
192 }
193 //
194 // Install the iSCSI private stuff as a flag to indicate this controller
195 // is already controlled by iSCSI driver.
196 //
197 Status = gBS->InstallProtocolInterface (
198 &ControllerHandle,
199 &gIScsiPrivateGuid,
200 EFI_NATIVE_INTERFACE,
201 &Private->IScsiIdentifier
202 );
203 if (EFI_ERROR (Status)) {
204 goto ON_ERROR;
205 }
206 //
207 // Update/Publish the iSCSI Boot Firmware Table.
208 //
209 IScsiPublishIbft ();
210
211 return EFI_SUCCESS;
212
213 ON_ERROR:
214
215 IScsiSessionAbort (&Private->Session);
216 IScsiCleanDriverData (Private);
217
218 return Status;
219 }
220
221 /**
222 Stop this driver on ControllerHandle.
223
224 Release the control of this controller and remove the IScsi functions. The Stop()
225 function is designed to be invoked from the EFI boot service DisconnectController().
226 As a result, much of the error checking on the parameters to Stop() has been moved
227 into this common boot service. It is legal to call Stop() from other locations,
228 but the following calling restrictions must be followed or the system behavior will not be deterministic.
229 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
230 same driver's Start() function.
231 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
232 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
233 Start() function, and the Start() function must have called OpenProtocol() on
234 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
235
236 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
237 @param[in] ControllerHandle A handle to the device being stopped. The handle must
238 support a bus specific I/O protocol for the driver
239 to use to stop the device.
240 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.Not used.
241 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
242 if NumberOfChildren is 0.Not used.
243
244 @retval EFI_SUCCESS The device was stopped.
245 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
246 **/
247 EFI_STATUS
248 EFIAPI
249 IScsiDriverBindingStop (
250 IN EFI_DRIVER_BINDING_PROTOCOL *This,
251 IN EFI_HANDLE ControllerHandle,
252 IN UINTN NumberOfChildren,
253 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
254 )
255 {
256 EFI_HANDLE IScsiController;
257 EFI_STATUS Status;
258 ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier;
259 ISCSI_DRIVER_DATA *Private;
260 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
261 ISCSI_CONNECTION *Conn;
262
263 if (NumberOfChildren != 0) {
264 //
265 // We should have only one child.
266 //
267 Status = gBS->OpenProtocol (
268 ChildHandleBuffer[0],
269 &gEfiExtScsiPassThruProtocolGuid,
270 (VOID **) &PassThru,
271 This->DriverBindingHandle,
272 ControllerHandle,
273 EFI_OPEN_PROTOCOL_GET_PROTOCOL
274 );
275 if (EFI_ERROR (Status)) {
276 return EFI_DEVICE_ERROR;
277 }
278
279 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);
280 Conn = NET_LIST_HEAD (&Private->Session.Conns, ISCSI_CONNECTION, Link);
281
282 //
283 // Previously the TCP4 protocol is opened BY_CHILD_CONTROLLER. Just close
284 // the protocol here but not uninstall the device path protocol and
285 // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.
286 //
287 gBS->CloseProtocol (
288 Conn->Tcp4Io.Handle,
289 &gEfiTcp4ProtocolGuid,
290 Private->Image,
291 Private->ExtScsiPassThruHandle
292 );
293
294 return EFI_SUCCESS;
295 }
296 //
297 // Get the handle of the controller we are controling.
298 //
299 IScsiController = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid);
300
301 Status = gBS->OpenProtocol (
302 IScsiController,
303 &gIScsiPrivateGuid,
304 (VOID **)&IScsiIdentifier,
305 This->DriverBindingHandle,
306 ControllerHandle,
307 EFI_OPEN_PROTOCOL_GET_PROTOCOL
308 );
309 if (EFI_ERROR (Status)) {
310 return EFI_DEVICE_ERROR;
311 }
312
313 Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);
314
315 //
316 // Uninstall the private protocol.
317 //
318 gBS->UninstallProtocolInterface (
319 IScsiController,
320 &gIScsiPrivateGuid,
321 &Private->IScsiIdentifier
322 );
323
324 //
325 // Update the iSCSI Boot Firware Table.
326 //
327 IScsiPublishIbft ();
328
329 IScsiSessionAbort (&Private->Session);
330 IScsiCleanDriverData (Private);
331
332 return EFI_SUCCESS;
333 }
334
335 /**
336 Unloads an image(the iSCSI driver).
337
338 @param[in] ImageHandle Handle that identifies the image to be unloaded.
339
340 @retval EFI_SUCCESS The image has been unloaded.
341 @retval Others Other errors as indicated.
342 **/
343 EFI_STATUS
344 EFIAPI
345 EfiIScsiUnload (
346 IN EFI_HANDLE ImageHandle
347 )
348 {
349 EFI_STATUS Status;
350 UINTN DeviceHandleCount;
351 EFI_HANDLE *DeviceHandleBuffer;
352 UINTN Index;
353
354 //
355 // Try to disonnect the driver from the devices it's controlling.
356 //
357 Status = gBS->LocateHandleBuffer (
358 AllHandles,
359 NULL,
360 NULL,
361 &DeviceHandleCount,
362 &DeviceHandleBuffer
363 );
364 if (!EFI_ERROR (Status)) {
365 for (Index = 0; Index < DeviceHandleCount; Index++) {
366 Status = gBS->DisconnectController (
367 DeviceHandleBuffer[Index],
368 ImageHandle,
369 NULL
370 );
371 }
372
373 if (DeviceHandleBuffer != NULL) {
374 FreePool (DeviceHandleBuffer);
375 }
376 }
377 //
378 // Unload the iSCSI configuration form.
379 //
380 IScsiConfigFormUnload (gIScsiDriverBinding.DriverBindingHandle);
381
382 //
383 // Uninstall the protocols installed by iSCSI driver.
384 //
385 Status = gBS->UninstallMultipleProtocolInterfaces (
386 ImageHandle,
387 &gEfiDriverBindingProtocolGuid,
388 &gIScsiDriverBinding,
389 &gEfiComponentName2ProtocolGuid,
390 &gIScsiComponentName2,
391 &gEfiComponentNameProtocolGuid,
392 &gIScsiComponentName,
393 &gEfiIScsiInitiatorNameProtocolGuid,
394 &gIScsiInitiatorName,
395 NULL
396 );
397
398 return Status;
399 }
400
401 /**
402 This is the declaration of an EFI image entry point. This entry point is
403 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
404 both device drivers and bus drivers. It initialize the global variables and
405 publish the driver binding protocol.
406
407 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
408 @param[in] SystemTable A pointer to the EFI System Table.
409
410 @retval EFI_SUCCESS The operation completed successfully.
411 @retval EFI_ACCESS_DENIED EFI_ISCSI_INITIATOR_NAME_PROTOCOL was installed unexpectedly.
412 @retval Others Other errors as indicated.
413 **/
414 EFI_STATUS
415 EFIAPI
416 IScsiDriverEntryPoint (
417 IN EFI_HANDLE ImageHandle,
418 IN EFI_SYSTEM_TABLE *SystemTable
419 )
420 {
421 EFI_STATUS Status;
422 EFI_ISCSI_INITIATOR_NAME_PROTOCOL *IScsiInitiatorName;
423
424 //
425 // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.
426 //
427 Status = gBS->LocateProtocol (
428 &gEfiIScsiInitiatorNameProtocolGuid,
429 NULL,
430 (VOID**) &IScsiInitiatorName
431 );
432
433 if (!EFI_ERROR (Status)) {
434 return EFI_ACCESS_DENIED;
435 }
436
437 //
438 // Initialize the EFI Driver Library
439 //
440 Status = EfiLibInstallDriverBindingComponentName2 (
441 ImageHandle,
442 SystemTable,
443 &gIScsiDriverBinding,
444 ImageHandle,
445 &gIScsiComponentName,
446 &gIScsiComponentName2
447 );
448
449 if (!EFI_ERROR (Status)) {
450 //
451 // Install the iSCSI Initiator Name Protocol.
452 //
453 Status = gBS->InstallProtocolInterface (
454 &ImageHandle,
455 &gEfiIScsiInitiatorNameProtocolGuid,
456 EFI_NATIVE_INTERFACE,
457 &gIScsiInitiatorName
458 );
459 if (EFI_ERROR (Status)) {
460 gBS->UninstallMultipleProtocolInterfaces (
461 ImageHandle,
462 &gEfiDriverBindingProtocolGuid,
463 &gIScsiDriverBinding,
464 &gEfiComponentName2ProtocolGuid,
465 &gIScsiComponentName2,
466 &gEfiComponentNameProtocolGuid,
467 &gIScsiComponentName,
468 NULL
469 );
470 return Status;
471 }
472
473 //
474 // Initialize the configuration form of iSCSI.
475 //
476 Status = IScsiConfigFormInit ();
477 if (EFI_ERROR (Status)) {
478 gBS->UninstallMultipleProtocolInterfaces (
479 ImageHandle,
480 &gEfiDriverBindingProtocolGuid,
481 &gIScsiDriverBinding,
482 &gEfiComponentName2ProtocolGuid,
483 &gIScsiComponentName2,
484 &gEfiComponentNameProtocolGuid,
485 &gIScsiComponentName,
486 &gEfiIScsiInitiatorNameProtocolGuid,
487 &gIScsiInitiatorName,
488 NULL
489 );
490 }
491 }
492 return Status;
493 }
494