1 /** @file 2 The entry point of IScsi driver. 3 4 Copyright (c) 2004 - 2016, 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 @retval EFI_INVALID_PARAMETER Child handle is NULL. 343 @retval EFI_ACCESS_DENIED The protocol could not be removed from the Handle 344 because its interfaces are being used. 345 346 **/ 347 EFI_STATUS 348 EFIAPI 349 IScsiDriverBindingStop ( 350 IN EFI_DRIVER_BINDING_PROTOCOL *This, 351 IN EFI_HANDLE ControllerHandle, 352 IN UINTN NumberOfChildren, 353 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL 354 ) 355 { 356 EFI_HANDLE IScsiController; 357 EFI_STATUS Status; 358 ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier; 359 ISCSI_DRIVER_DATA *Private; 360 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru; 361 ISCSI_CONNECTION *Conn; 362 363 if (NumberOfChildren != 0) { 364 // 365 // We should have only one child. 366 // 367 Status = gBS->OpenProtocol ( 368 ChildHandleBuffer[0], 369 &gEfiExtScsiPassThruProtocolGuid, 370 (VOID **) &PassThru, 371 This->DriverBindingHandle, 372 ControllerHandle, 373 EFI_OPEN_PROTOCOL_GET_PROTOCOL 374 ); 375 if (EFI_ERROR (Status)) { 376 return EFI_DEVICE_ERROR; 377 } 378 379 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru); 380 Conn = NET_LIST_HEAD (&Private->Session.Conns, ISCSI_CONNECTION, Link); 381 382 // 383 // Previously the TCP4 protocol is opened BY_CHILD_CONTROLLER. Just close 384 // the protocol here but not uninstall the device path protocol and 385 // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle. 386 // 387 gBS->CloseProtocol ( 388 Private->ChildHandle, 389 &gEfiTcp4ProtocolGuid, 390 Private->Image, 391 Private->ExtScsiPassThruHandle 392 ); 393 394 gBS->CloseProtocol ( 395 Conn->Tcp4Io.Handle, 396 &gEfiTcp4ProtocolGuid, 397 Private->Image, 398 Private->ExtScsiPassThruHandle 399 ); 400 401 return EFI_SUCCESS; 402 } 403 // 404 // Get the handle of the controller we are controling. 405 // 406 IScsiController = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid); 407 408 Status = gBS->OpenProtocol ( 409 IScsiController, 410 &gEfiCallerIdGuid, 411 (VOID **)&IScsiIdentifier, 412 This->DriverBindingHandle, 413 ControllerHandle, 414 EFI_OPEN_PROTOCOL_GET_PROTOCOL 415 ); 416 if (EFI_ERROR (Status)) { 417 return EFI_DEVICE_ERROR; 418 } 419 420 Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier); 421 422 if (Private->ChildHandle != NULL) { 423 Status = gBS->CloseProtocol ( 424 Private->ChildHandle, 425 &gEfiTcp4ProtocolGuid, 426 This->DriverBindingHandle, 427 IScsiController 428 ); 429 430 ASSERT (!EFI_ERROR (Status)); 431 432 Status = NetLibDestroyServiceChild ( 433 IScsiController, 434 This->DriverBindingHandle, 435 &gEfiTcp4ServiceBindingProtocolGuid, 436 Private->ChildHandle 437 ); 438 ASSERT (!EFI_ERROR (Status)); 439 } 440 441 IScsiConfigUpdateForm (This->DriverBindingHandle, IScsiController, FALSE); 442 443 // 444 // Uninstall the private protocol. 445 // 446 gBS->UninstallProtocolInterface ( 447 IScsiController, 448 &gEfiCallerIdGuid, 449 &Private->IScsiIdentifier 450 ); 451 452 // 453 // Update the iSCSI Boot Firware Table. 454 // 455 IScsiPublishIbft (); 456 457 IScsiSessionAbort (&Private->Session); 458 Status = IScsiCleanDriverData (Private); 459 if (EFI_ERROR (Status)) { 460 return Status; 461 } 462 463 return EFI_SUCCESS; 464 } 465 466 /** 467 Unloads an image(the iSCSI driver). 468 469 @param[in] ImageHandle Handle that identifies the image to be unloaded. 470 471 @retval EFI_SUCCESS The image has been unloaded. 472 @retval Others Other errors as indicated. 473 **/ 474 EFI_STATUS 475 EFIAPI 476 EfiIScsiUnload ( 477 IN EFI_HANDLE ImageHandle 478 ) 479 { 480 EFI_STATUS Status; 481 UINTN DeviceHandleCount; 482 EFI_HANDLE *DeviceHandleBuffer; 483 UINTN Index; 484 EFI_COMPONENT_NAME_PROTOCOL *ComponentName; 485 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2; 486 487 // 488 // Try to disonnect the driver from the devices it's controlling. 489 // 490 Status = gBS->LocateHandleBuffer ( 491 AllHandles, 492 NULL, 493 NULL, 494 &DeviceHandleCount, 495 &DeviceHandleBuffer 496 ); 497 if (EFI_ERROR (Status)) { 498 return Status; 499 } 500 501 for (Index = 0; Index < DeviceHandleCount; Index++) { 502 Status = IScsiTestManagedDevice ( 503 DeviceHandleBuffer[Index], 504 gIScsiDriverBinding.DriverBindingHandle, 505 &gEfiTcp4ProtocolGuid 506 ); 507 if (EFI_ERROR (Status)) { 508 continue; 509 } 510 Status = gBS->DisconnectController ( 511 DeviceHandleBuffer[Index], 512 gIScsiDriverBinding.DriverBindingHandle, 513 NULL 514 ); 515 if (EFI_ERROR (Status)) { 516 goto ON_EXIT; 517 } 518 } 519 520 // 521 // Unload the iSCSI configuration form. 522 // 523 Status = IScsiConfigFormUnload (gIScsiDriverBinding.DriverBindingHandle); 524 if (EFI_ERROR (Status)) { 525 goto ON_EXIT; 526 } 527 528 // 529 // Uninstall the ComponentName and ComponentName2 protocol from iSCSI4 driver binding handle 530 // if it has been installed. 531 // 532 Status = gBS->HandleProtocol ( 533 gIScsiDriverBinding.DriverBindingHandle, 534 &gEfiComponentNameProtocolGuid, 535 (VOID **) &ComponentName 536 ); 537 if (!EFI_ERROR (Status)) { 538 Status = gBS->UninstallMultipleProtocolInterfaces ( 539 gIScsiDriverBinding.DriverBindingHandle, 540 &gEfiComponentNameProtocolGuid, 541 ComponentName, 542 NULL 543 ); 544 if (EFI_ERROR (Status)) { 545 goto ON_EXIT; 546 } 547 } 548 549 Status = gBS->HandleProtocol ( 550 gIScsiDriverBinding.DriverBindingHandle, 551 &gEfiComponentName2ProtocolGuid, 552 (VOID **) &ComponentName2 553 ); 554 if (!EFI_ERROR (Status)) { 555 gBS->UninstallMultipleProtocolInterfaces ( 556 gIScsiDriverBinding.DriverBindingHandle, 557 &gEfiComponentName2ProtocolGuid, 558 ComponentName2, 559 NULL 560 ); 561 if (EFI_ERROR (Status)) { 562 goto ON_EXIT; 563 } 564 } 565 566 Status = gBS->UninstallMultipleProtocolInterfaces ( 567 ImageHandle, 568 &gEfiDriverBindingProtocolGuid, 569 &gIScsiDriverBinding, 570 &gEfiIScsiInitiatorNameProtocolGuid, 571 &gIScsiInitiatorName, 572 NULL 573 ); 574 ON_EXIT: 575 576 if (DeviceHandleBuffer != NULL) { 577 FreePool (DeviceHandleBuffer); 578 } 579 580 return Status; 581 } 582 583 /** 584 This is the declaration of an EFI image entry point. This entry point is 585 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including 586 both device drivers and bus drivers. It initialize the global variables and 587 publish the driver binding protocol. 588 589 @param[in] ImageHandle The firmware allocated handle for the UEFI image. 590 @param[in] SystemTable A pointer to the EFI System Table. 591 592 @retval EFI_SUCCESS The operation completed successfully. 593 @retval EFI_ACCESS_DENIED EFI_ISCSI_INITIATOR_NAME_PROTOCOL was installed unexpectedly. 594 @retval Others Other errors as indicated. 595 **/ 596 EFI_STATUS 597 EFIAPI 598 IScsiDriverEntryPoint ( 599 IN EFI_HANDLE ImageHandle, 600 IN EFI_SYSTEM_TABLE *SystemTable 601 ) 602 { 603 EFI_STATUS Status; 604 EFI_ISCSI_INITIATOR_NAME_PROTOCOL *IScsiInitiatorName; 605 606 // 607 // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL. 608 // 609 Status = gBS->LocateProtocol ( 610 &gEfiIScsiInitiatorNameProtocolGuid, 611 NULL, 612 (VOID**) &IScsiInitiatorName 613 ); 614 615 if (!EFI_ERROR (Status)) { 616 return EFI_ACCESS_DENIED; 617 } 618 619 // 620 // Initialize the EFI Driver Library 621 // 622 Status = EfiLibInstallDriverBindingComponentName2 ( 623 ImageHandle, 624 SystemTable, 625 &gIScsiDriverBinding, 626 ImageHandle, 627 &gIScsiComponentName, 628 &gIScsiComponentName2 629 ); 630 631 if (!EFI_ERROR (Status)) { 632 // 633 // Install the iSCSI Initiator Name Protocol. 634 // 635 Status = gBS->InstallProtocolInterface ( 636 &ImageHandle, 637 &gEfiIScsiInitiatorNameProtocolGuid, 638 EFI_NATIVE_INTERFACE, 639 &gIScsiInitiatorName 640 ); 641 if (EFI_ERROR (Status)) { 642 gBS->UninstallMultipleProtocolInterfaces ( 643 ImageHandle, 644 &gEfiDriverBindingProtocolGuid, 645 &gIScsiDriverBinding, 646 &gEfiComponentName2ProtocolGuid, 647 &gIScsiComponentName2, 648 &gEfiComponentNameProtocolGuid, 649 &gIScsiComponentName, 650 NULL 651 ); 652 return Status; 653 } 654 655 // 656 // Initialize the configuration form of iSCSI. 657 // 658 Status = IScsiConfigFormInit (); 659 if (EFI_ERROR (Status)) { 660 gBS->UninstallMultipleProtocolInterfaces ( 661 ImageHandle, 662 &gEfiDriverBindingProtocolGuid, 663 &gIScsiDriverBinding, 664 &gEfiComponentName2ProtocolGuid, 665 &gIScsiComponentName2, 666 &gEfiComponentNameProtocolGuid, 667 &gIScsiComponentName, 668 &gEfiIScsiInitiatorNameProtocolGuid, 669 &gIScsiInitiatorName, 670 NULL 671 ); 672 } 673 } 674 return Status; 675 } 676 677