]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/IScsiDxe/IScsiDriver.c
Open default Tcp child via BY_CHILD_CONTROLLER.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / IScsiDxe / IScsiDriver.c
1 /** @file
2 The entry point of IScsi driver.
3
4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "IScsiImpl.h"
16
17 EFI_DRIVER_BINDING_PROTOCOL gIScsiDriverBinding = {
18 IScsiDriverBindingSupported,
19 IScsiDriverBindingStart,
20 IScsiDriverBindingStop,
21 0xa,
22 NULL,
23 NULL
24 };
25
26 /**
27 Tests to see if this driver supports the RemainingDevicePath.
28
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
35 bus driver.
36
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.
40 **/
41 EFI_STATUS
42 IScsiIsDevicePathSupported (
43 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
44 )
45 {
46 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
47
48 CurrentDevicePath = RemainingDevicePath;
49 if (CurrentDevicePath != NULL) {
50 while (!IsDevicePathEnd (CurrentDevicePath)) {
51 if ((CurrentDevicePath->Type == MESSAGING_DEVICE_PATH) && (CurrentDevicePath->SubType == MSG_ISCSI_DP)) {
52 return EFI_SUCCESS;
53 }
54
55 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
56 }
57
58 return EFI_UNSUPPORTED;
59 }
60
61 return EFI_SUCCESS;
62 }
63
64 /**
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.
67
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.
74
75
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
80 specified by This.
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.
87 **/
88 EFI_STATUS
89 EFIAPI
90 IScsiDriverBindingSupported (
91 IN EFI_DRIVER_BINDING_PROTOCOL *This,
92 IN EFI_HANDLE ControllerHandle,
93 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
94 )
95 {
96 EFI_STATUS Status;
97
98 Status = gBS->OpenProtocol (
99 ControllerHandle,
100 &gEfiCallerIdGuid,
101 NULL,
102 This->DriverBindingHandle,
103 ControllerHandle,
104 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
105 );
106 if (!EFI_ERROR (Status)) {
107 return EFI_ALREADY_STARTED;
108 }
109
110 Status = gBS->OpenProtocol (
111 ControllerHandle,
112 &gEfiTcp4ServiceBindingProtocolGuid,
113 NULL,
114 This->DriverBindingHandle,
115 ControllerHandle,
116 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
117 );
118 if (EFI_ERROR (Status)) {
119 return EFI_UNSUPPORTED;
120 }
121
122 Status = IScsiIsDevicePathSupported (RemainingDevicePath);
123 if (EFI_ERROR (Status)) {
124 return EFI_UNSUPPORTED;
125 }
126
127 if (IScsiDhcpIsConfigured (ControllerHandle)) {
128 Status = gBS->OpenProtocol (
129 ControllerHandle,
130 &gEfiDhcp4ServiceBindingProtocolGuid,
131 NULL,
132 This->DriverBindingHandle,
133 ControllerHandle,
134 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
135 );
136 if (EFI_ERROR (Status)) {
137 return EFI_UNSUPPORTED;
138 }
139 }
140
141 return EFI_SUCCESS;
142 }
143
144 /**
145 Start this driver on ControllerHandle.
146
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.
156
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.
163
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.
169 **/
170 EFI_STATUS
171 EFIAPI
172 IScsiDriverBindingStart (
173 IN EFI_DRIVER_BINDING_PROTOCOL *This,
174 IN EFI_HANDLE ControllerHandle,
175 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
176 )
177 {
178 EFI_STATUS Status;
179 ISCSI_DRIVER_DATA *Private;
180 VOID *Interface;
181
182 Private = IScsiCreateDriverData (This->DriverBindingHandle, ControllerHandle);
183 if (Private == NULL) {
184 return EFI_OUT_OF_RESOURCES;
185 }
186
187 //
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.
192 //
193 Status = NetLibCreateServiceChild (
194 ControllerHandle,
195 This->DriverBindingHandle,
196 &gEfiTcp4ServiceBindingProtocolGuid,
197 &Private->ChildHandle
198 );
199
200 if (EFI_ERROR (Status)) {
201 goto ON_ERROR;
202 }
203
204 Status = gBS->OpenProtocol (
205 Private->ChildHandle,
206 &gEfiTcp4ProtocolGuid,
207 &Interface,
208 This->DriverBindingHandle,
209 ControllerHandle,
210 EFI_OPEN_PROTOCOL_BY_DRIVER
211 );
212 if (EFI_ERROR (Status)) {
213 goto ON_ERROR;
214 }
215
216 //
217 // Always install private protocol no matter what happens later. We need to
218 // keep the relationship between ControllerHandle and ChildHandle.
219 //
220 Status = gBS->InstallProtocolInterface (
221 &ControllerHandle,
222 &gEfiCallerIdGuid,
223 EFI_NATIVE_INTERFACE,
224 &Private->IScsiIdentifier
225 );
226 if (EFI_ERROR (Status)) {
227 goto ON_ERROR;
228 }
229
230 //
231 // Try to add a port configuration page for this controller.
232 //
233 IScsiConfigUpdateForm (This->DriverBindingHandle, ControllerHandle, TRUE);
234
235 //
236 // Get the iSCSI configuration data of this controller.
237 //
238 Status = IScsiGetConfigData (Private);
239 if (EFI_ERROR (Status)) {
240 goto ON_ERROR;
241 }
242 //
243 // Try to login and create an iSCSI session according to the configuration.
244 //
245 Status = IScsiSessionLogin (Private);
246 if (Status == EFI_MEDIA_CHANGED) {
247 //
248 // The specified target is not available and the redirection information is
249 // got, login the session again with the updated target address.
250 //
251 Status = IScsiSessionLogin (Private);
252 }
253
254 if (EFI_ERROR (Status)) {
255 goto ON_ERROR;
256 }
257 //
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
260 // connections.
261 //
262 Private->DevicePath = IScsiGetTcpConnDevicePath (Private);
263 if (Private->DevicePath == NULL) {
264 goto ON_ERROR;
265 }
266 //
267 // Install the updated device path onto the ExtScsiPassThruHandle.
268 //
269 Status = gBS->InstallProtocolInterface (
270 &Private->ExtScsiPassThruHandle,
271 &gEfiDevicePathProtocolGuid,
272 EFI_NATIVE_INTERFACE,
273 Private->DevicePath
274 );
275 if (EFI_ERROR (Status)) {
276 goto ON_ERROR;
277 }
278
279 //
280 // ISCSI children should share the default Tcp child, just open the default Tcp child via BY_CHILD_CONTROLLER.
281 //
282 Status = gBS->OpenProtocol (
283 Private->ChildHandle, /// Default Tcp child
284 &gEfiTcp4ProtocolGuid,
285 &Interface,
286 This->DriverBindingHandle,
287 Private->ExtScsiPassThruHandle,
288 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
289 );
290 if (EFI_ERROR (Status)) {
291 gBS->UninstallMultipleProtocolInterfaces (
292 Private->ExtScsiPassThruHandle,
293 &gEfiExtScsiPassThruProtocolGuid,
294 &Private->IScsiExtScsiPassThru,
295 &gEfiDevicePathProtocolGuid,
296 Private->DevicePath,
297 NULL
298 );
299
300 goto ON_ERROR;
301 }
302
303 //
304 // Update/Publish the iSCSI Boot Firmware Table.
305 //
306 IScsiPublishIbft ();
307
308 return EFI_SUCCESS;
309
310 ON_ERROR:
311
312 IScsiSessionAbort (&Private->Session);
313
314 return Status;
315 }
316
317 /**
318 Stop this driver on ControllerHandle.
319
320 Release the control of this controller and remove the IScsi functions. The Stop()
321 function is designed to be invoked from the EFI boot service DisconnectController().
322 As a result, much of the error checking on the parameters to Stop() has been moved
323 into this common boot service. It is legal to call Stop() from other locations,
324 but the following calling restrictions must be followed or the system behavior will not be deterministic.
325 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
326 same driver's Start() function.
327 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
328 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
329 Start() function, and the Start() function must have called OpenProtocol() on
330 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
331
332 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
333 @param[in] ControllerHandle A handle to the device being stopped. The handle must
334 support a bus specific I/O protocol for the driver
335 to use to stop the device.
336 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.Not used.
337 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
338 if NumberOfChildren is 0.Not used.
339
340 @retval EFI_SUCCESS The device was stopped.
341 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
342 **/
343 EFI_STATUS
344 EFIAPI
345 IScsiDriverBindingStop (
346 IN EFI_DRIVER_BINDING_PROTOCOL *This,
347 IN EFI_HANDLE ControllerHandle,
348 IN UINTN NumberOfChildren,
349 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
350 )
351 {
352 EFI_HANDLE IScsiController;
353 EFI_STATUS Status;
354 ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier;
355 ISCSI_DRIVER_DATA *Private;
356 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
357 ISCSI_CONNECTION *Conn;
358
359 if (NumberOfChildren != 0) {
360 //
361 // We should have only one child.
362 //
363 Status = gBS->OpenProtocol (
364 ChildHandleBuffer[0],
365 &gEfiExtScsiPassThruProtocolGuid,
366 (VOID **) &PassThru,
367 This->DriverBindingHandle,
368 ControllerHandle,
369 EFI_OPEN_PROTOCOL_GET_PROTOCOL
370 );
371 if (EFI_ERROR (Status)) {
372 return EFI_DEVICE_ERROR;
373 }
374
375 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);
376 Conn = NET_LIST_HEAD (&Private->Session.Conns, ISCSI_CONNECTION, Link);
377
378 //
379 // Previously the TCP4 protocol is opened BY_CHILD_CONTROLLER. Just close
380 // the protocol here but not uninstall the device path protocol and
381 // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.
382 //
383 gBS->CloseProtocol (
384 Private->ChildHandle,
385 &gEfiTcp4ProtocolGuid,
386 Private->Image,
387 Private->ExtScsiPassThruHandle
388 );
389
390 gBS->CloseProtocol (
391 Conn->Tcp4Io.Handle,
392 &gEfiTcp4ProtocolGuid,
393 Private->Image,
394 Private->ExtScsiPassThruHandle
395 );
396
397 return EFI_SUCCESS;
398 }
399 //
400 // Get the handle of the controller we are controling.
401 //
402 IScsiController = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid);
403
404 Status = gBS->OpenProtocol (
405 IScsiController,
406 &gEfiCallerIdGuid,
407 (VOID **)&IScsiIdentifier,
408 This->DriverBindingHandle,
409 ControllerHandle,
410 EFI_OPEN_PROTOCOL_GET_PROTOCOL
411 );
412 if (EFI_ERROR (Status)) {
413 return EFI_DEVICE_ERROR;
414 }
415
416 Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);
417
418 if (Private->ChildHandle != NULL) {
419 Status = gBS->CloseProtocol (
420 Private->ChildHandle,
421 &gEfiTcp4ProtocolGuid,
422 This->DriverBindingHandle,
423 IScsiController
424 );
425
426 ASSERT (!EFI_ERROR (Status));
427
428 Status = NetLibDestroyServiceChild (
429 IScsiController,
430 This->DriverBindingHandle,
431 &gEfiTcp4ServiceBindingProtocolGuid,
432 Private->ChildHandle
433 );
434 ASSERT (!EFI_ERROR (Status));
435 }
436
437 IScsiConfigUpdateForm (This->DriverBindingHandle, IScsiController, FALSE);
438
439 //
440 // Uninstall the private protocol.
441 //
442 gBS->UninstallProtocolInterface (
443 IScsiController,
444 &gEfiCallerIdGuid,
445 &Private->IScsiIdentifier
446 );
447
448 //
449 // Update the iSCSI Boot Firware Table.
450 //
451 IScsiPublishIbft ();
452
453 IScsiSessionAbort (&Private->Session);
454 IScsiCleanDriverData (Private);
455
456 return EFI_SUCCESS;
457 }
458
459 /**
460 Unloads an image(the iSCSI driver).
461
462 @param[in] ImageHandle Handle that identifies the image to be unloaded.
463
464 @retval EFI_SUCCESS The image has been unloaded.
465 @retval Others Other errors as indicated.
466 **/
467 EFI_STATUS
468 EFIAPI
469 EfiIScsiUnload (
470 IN EFI_HANDLE ImageHandle
471 )
472 {
473 EFI_STATUS Status;
474 UINTN DeviceHandleCount;
475 EFI_HANDLE *DeviceHandleBuffer;
476 UINTN Index;
477 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
478 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
479
480 //
481 // Try to disonnect the driver from the devices it's controlling.
482 //
483 Status = gBS->LocateHandleBuffer (
484 AllHandles,
485 NULL,
486 NULL,
487 &DeviceHandleCount,
488 &DeviceHandleBuffer
489 );
490 if (EFI_ERROR (Status)) {
491 return Status;
492 }
493
494 for (Index = 0; Index < DeviceHandleCount; Index++) {
495 Status = IScsiTestManagedDevice (
496 DeviceHandleBuffer[Index],
497 gIScsiDriverBinding.DriverBindingHandle,
498 &gEfiTcp4ProtocolGuid
499 );
500 if (EFI_ERROR (Status)) {
501 continue;
502 }
503 Status = gBS->DisconnectController (
504 DeviceHandleBuffer[Index],
505 gIScsiDriverBinding.DriverBindingHandle,
506 NULL
507 );
508 if (EFI_ERROR (Status)) {
509 goto ON_EXIT;
510 }
511 }
512
513 //
514 // Unload the iSCSI configuration form.
515 //
516 Status = IScsiConfigFormUnload (gIScsiDriverBinding.DriverBindingHandle);
517 if (EFI_ERROR (Status)) {
518 goto ON_EXIT;
519 }
520
521 //
522 // Uninstall the ComponentName and ComponentName2 protocol from iSCSI4 driver binding handle
523 // if it has been installed.
524 //
525 Status = gBS->HandleProtocol (
526 gIScsiDriverBinding.DriverBindingHandle,
527 &gEfiComponentNameProtocolGuid,
528 (VOID **) &ComponentName
529 );
530 if (!EFI_ERROR (Status)) {
531 Status = gBS->UninstallMultipleProtocolInterfaces (
532 gIScsiDriverBinding.DriverBindingHandle,
533 &gEfiComponentNameProtocolGuid,
534 ComponentName,
535 NULL
536 );
537 if (EFI_ERROR (Status)) {
538 goto ON_EXIT;
539 }
540 }
541
542 Status = gBS->HandleProtocol (
543 gIScsiDriverBinding.DriverBindingHandle,
544 &gEfiComponentName2ProtocolGuid,
545 (VOID **) &ComponentName2
546 );
547 if (!EFI_ERROR (Status)) {
548 gBS->UninstallMultipleProtocolInterfaces (
549 gIScsiDriverBinding.DriverBindingHandle,
550 &gEfiComponentName2ProtocolGuid,
551 ComponentName2,
552 NULL
553 );
554 if (EFI_ERROR (Status)) {
555 goto ON_EXIT;
556 }
557 }
558
559 Status = gBS->UninstallMultipleProtocolInterfaces (
560 ImageHandle,
561 &gEfiDriverBindingProtocolGuid,
562 &gIScsiDriverBinding,
563 &gEfiIScsiInitiatorNameProtocolGuid,
564 &gIScsiInitiatorName,
565 NULL
566 );
567 ON_EXIT:
568
569 if (DeviceHandleBuffer != NULL) {
570 FreePool (DeviceHandleBuffer);
571 }
572
573 return Status;
574 }
575
576 /**
577 This is the declaration of an EFI image entry point. This entry point is
578 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
579 both device drivers and bus drivers. It initialize the global variables and
580 publish the driver binding protocol.
581
582 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
583 @param[in] SystemTable A pointer to the EFI System Table.
584
585 @retval EFI_SUCCESS The operation completed successfully.
586 @retval EFI_ACCESS_DENIED EFI_ISCSI_INITIATOR_NAME_PROTOCOL was installed unexpectedly.
587 @retval Others Other errors as indicated.
588 **/
589 EFI_STATUS
590 EFIAPI
591 IScsiDriverEntryPoint (
592 IN EFI_HANDLE ImageHandle,
593 IN EFI_SYSTEM_TABLE *SystemTable
594 )
595 {
596 EFI_STATUS Status;
597 EFI_ISCSI_INITIATOR_NAME_PROTOCOL *IScsiInitiatorName;
598
599 //
600 // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL.
601 //
602 Status = gBS->LocateProtocol (
603 &gEfiIScsiInitiatorNameProtocolGuid,
604 NULL,
605 (VOID**) &IScsiInitiatorName
606 );
607
608 if (!EFI_ERROR (Status)) {
609 return EFI_ACCESS_DENIED;
610 }
611
612 //
613 // Initialize the EFI Driver Library
614 //
615 Status = EfiLibInstallDriverBindingComponentName2 (
616 ImageHandle,
617 SystemTable,
618 &gIScsiDriverBinding,
619 ImageHandle,
620 &gIScsiComponentName,
621 &gIScsiComponentName2
622 );
623
624 if (!EFI_ERROR (Status)) {
625 //
626 // Install the iSCSI Initiator Name Protocol.
627 //
628 Status = gBS->InstallProtocolInterface (
629 &ImageHandle,
630 &gEfiIScsiInitiatorNameProtocolGuid,
631 EFI_NATIVE_INTERFACE,
632 &gIScsiInitiatorName
633 );
634 if (EFI_ERROR (Status)) {
635 gBS->UninstallMultipleProtocolInterfaces (
636 ImageHandle,
637 &gEfiDriverBindingProtocolGuid,
638 &gIScsiDriverBinding,
639 &gEfiComponentName2ProtocolGuid,
640 &gIScsiComponentName2,
641 &gEfiComponentNameProtocolGuid,
642 &gIScsiComponentName,
643 NULL
644 );
645 return Status;
646 }
647
648 //
649 // Initialize the configuration form of iSCSI.
650 //
651 Status = IScsiConfigFormInit ();
652 if (EFI_ERROR (Status)) {
653 gBS->UninstallMultipleProtocolInterfaces (
654 ImageHandle,
655 &gEfiDriverBindingProtocolGuid,
656 &gIScsiDriverBinding,
657 &gEfiComponentName2ProtocolGuid,
658 &gIScsiComponentName2,
659 &gEfiComponentNameProtocolGuid,
660 &gIScsiComponentName,
661 &gEfiIScsiInitiatorNameProtocolGuid,
662 &gIScsiInitiatorName,
663 NULL
664 );
665 }
666 }
667 return Status;
668 }
669