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 gIScsiIp4DriverBinding = { 18 IScsiIp4DriverBindingSupported, 19 IScsiIp4DriverBindingStart, 20 IScsiIp4DriverBindingStop, 21 0xa, 22 NULL, 23 NULL 24 }; 25 26 EFI_DRIVER_BINDING_PROTOCOL gIScsiIp6DriverBinding = { 27 IScsiIp6DriverBindingSupported, 28 IScsiIp6DriverBindingStart, 29 IScsiIp6DriverBindingStop, 30 0xa, 31 NULL, 32 NULL 33 }; 34 35 EFI_GUID gIScsiV4PrivateGuid = ISCSI_V4_PRIVATE_GUID; 36 EFI_GUID gIScsiV6PrivateGuid = ISCSI_V6_PRIVATE_GUID; 37 ISCSI_PRIVATE_DATA *mPrivate = NULL; 38 39 /** 40 Tests to see if this driver supports the RemainingDevicePath. 41 42 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This 43 parameter is ignored by device drivers, and is optional for bus 44 drivers. For bus drivers, if this parameter is not NULL, then 45 the bus driver must determine if the bus controller specified 46 by ControllerHandle and the child controller specified 47 by RemainingDevicePath are both supported by this 48 bus driver. 49 50 @retval EFI_SUCCESS The RemainingDevicePath is supported or NULL. 51 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and 52 RemainingDevicePath is not supported by the driver specified by This. 53 **/ 54 EFI_STATUS 55 IScsiIsDevicePathSupported ( 56 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL 57 ) 58 { 59 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath; 60 61 CurrentDevicePath = RemainingDevicePath; 62 if (CurrentDevicePath != NULL) { 63 while (!IsDevicePathEnd (CurrentDevicePath)) { 64 if ((CurrentDevicePath->Type == MESSAGING_DEVICE_PATH) && (CurrentDevicePath->SubType == MSG_ISCSI_DP)) { 65 return EFI_SUCCESS; 66 } 67 68 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath); 69 } 70 71 return EFI_UNSUPPORTED; 72 } 73 74 return EFI_SUCCESS; 75 } 76 77 /** 78 Check whether an iSCSI HBA adapter already installs an AIP instance with 79 network boot policy matching the value specified in PcdIScsiAIPNetworkBootPolicy. 80 If yes, return EFI_SUCCESS. 81 82 @retval EFI_SUCCESS Found an AIP with matching network boot policy. 83 @retval EFI_NOT_FOUND AIP is unavailable or the network boot policy 84 not matched. 85 **/ 86 EFI_STATUS 87 IScsiCheckAip ( 88 ) 89 { 90 UINTN AipHandleCount; 91 EFI_HANDLE *AipHandleBuffer; 92 UINTN AipIndex; 93 EFI_ADAPTER_INFORMATION_PROTOCOL *Aip; 94 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru; 95 EFI_GUID *InfoTypesBuffer; 96 UINTN InfoTypeBufferCount; 97 UINTN TypeIndex; 98 VOID *InfoBlock; 99 UINTN InfoBlockSize; 100 BOOLEAN Supported; 101 EFI_ADAPTER_INFO_NETWORK_BOOT *NetworkBoot; 102 EFI_STATUS Status; 103 UINT8 NetworkBootPolicy; 104 105 // 106 // Check any AIP instances exist in system. 107 // 108 AipHandleCount = 0; 109 AipHandleBuffer = NULL; 110 Status = gBS->LocateHandleBuffer ( 111 ByProtocol, 112 &gEfiAdapterInformationProtocolGuid, 113 NULL, 114 &AipHandleCount, 115 &AipHandleBuffer 116 ); 117 if (EFI_ERROR (Status) || AipHandleCount == 0) { 118 return EFI_NOT_FOUND; 119 } 120 121 ASSERT (AipHandleBuffer != NULL); 122 123 InfoBlock = NULL; 124 125 for (AipIndex = 0; AipIndex < AipHandleCount; AipIndex++) { 126 Status = gBS->HandleProtocol ( 127 AipHandleBuffer[AipIndex], 128 &gEfiAdapterInformationProtocolGuid, 129 (VOID *) &Aip 130 ); 131 ASSERT_EFI_ERROR (Status); 132 ASSERT (Aip != NULL); 133 134 Status = gBS->HandleProtocol ( 135 AipHandleBuffer[AipIndex], 136 &gEfiExtScsiPassThruProtocolGuid, 137 (VOID *) &ExtScsiPassThru 138 ); 139 if (EFI_ERROR (Status) || ExtScsiPassThru == NULL) { 140 continue; 141 } 142 143 InfoTypesBuffer = NULL; 144 InfoTypeBufferCount = 0; 145 Status = Aip->GetSupportedTypes (Aip, &InfoTypesBuffer, &InfoTypeBufferCount); 146 if (EFI_ERROR (Status) || InfoTypesBuffer == NULL) { 147 continue; 148 } 149 // 150 // Check whether the AIP instance has Network boot information block. 151 // 152 Supported = FALSE; 153 for (TypeIndex = 0; TypeIndex < InfoTypeBufferCount; TypeIndex++) { 154 if (CompareGuid (&InfoTypesBuffer[TypeIndex], &gEfiAdapterInfoNetworkBootGuid)) { 155 Supported = TRUE; 156 break; 157 } 158 } 159 160 FreePool (InfoTypesBuffer); 161 if (!Supported) { 162 continue; 163 } 164 165 // 166 // We now have network boot information block. 167 // 168 InfoBlock = NULL; 169 InfoBlockSize = 0; 170 Status = Aip->GetInformation (Aip, &gEfiAdapterInfoNetworkBootGuid, &InfoBlock, &InfoBlockSize); 171 if (EFI_ERROR (Status) || InfoBlock == NULL) { 172 continue; 173 } 174 175 // 176 // Check whether the network boot policy matches. 177 // 178 NetworkBoot = (EFI_ADAPTER_INFO_NETWORK_BOOT *) InfoBlock; 179 NetworkBootPolicy = PcdGet8 (PcdIScsiAIPNetworkBootPolicy); 180 181 if (NetworkBootPolicy == STOP_UEFI_ISCSI_IF_HBA_INSTALL_AIP) { 182 Status = EFI_SUCCESS; 183 goto Exit; 184 } 185 if (((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_SUPPORT_IP4) != 0 && 186 !NetworkBoot->iScsiIpv4BootCapablity) || 187 ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_SUPPORT_IP6) != 0 && 188 !NetworkBoot->iScsiIpv6BootCapablity) || 189 ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_SUPPORT_OFFLOAD) != 0 && 190 !NetworkBoot->OffloadCapability) || 191 ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_SUPPORT_MPIO) != 0 && 192 !NetworkBoot->iScsiMpioCapability) || 193 ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_CONFIGURED_IP4) != 0 && 194 !NetworkBoot->iScsiIpv4Boot) || 195 ((NetworkBootPolicy & STOP_UEFI_ISCSI_IF_AIP_CONFIGURED_IP6) != 0 && 196 !NetworkBoot->iScsiIpv6Boot)) { 197 FreePool (InfoBlock); 198 continue; 199 } 200 201 Status = EFI_SUCCESS; 202 goto Exit; 203 } 204 205 Status = EFI_NOT_FOUND; 206 207 Exit: 208 if (InfoBlock != NULL) { 209 FreePool (InfoBlock); 210 } 211 if (AipHandleBuffer != NULL) { 212 FreePool (AipHandleBuffer); 213 } 214 return Status; 215 } 216 217 /** 218 Tests to see if this driver supports a given controller. This is the worker function for 219 IScsiIp4(6)DriverBindingSupported. 220 221 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. 222 @param[in] ControllerHandle The handle of the controller to test. This handle 223 must support a protocol interface that supplies 224 an I/O abstraction to the driver. 225 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This 226 parameter is ignored by device drivers, and is optional for bus 227 drivers. For bus drivers, if this parameter is not NULL, then 228 the bus driver must determine if the bus controller specified 229 by ControllerHandle and the child controller specified 230 by RemainingDevicePath are both supported by this 231 bus driver. 232 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. 233 234 @retval EFI_SUCCESS The device specified by ControllerHandle and 235 RemainingDevicePath is supported by the driver specified by This. 236 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and 237 RemainingDevicePath is already being managed by the driver 238 specified by This. 239 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and 240 RemainingDevicePath is not supported by the driver specified by This. 241 **/ 242 EFI_STATUS 243 EFIAPI 244 IScsiSupported ( 245 IN EFI_DRIVER_BINDING_PROTOCOL *This, 246 IN EFI_HANDLE ControllerHandle, 247 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL, 248 IN UINT8 IpVersion 249 ) 250 { 251 EFI_STATUS Status; 252 EFI_GUID *IScsiServiceBindingGuid; 253 EFI_GUID *TcpServiceBindingGuid; 254 EFI_GUID *DhcpServiceBindingGuid; 255 256 if (IpVersion == IP_VERSION_4) { 257 IScsiServiceBindingGuid = &gIScsiV4PrivateGuid; 258 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid; 259 DhcpServiceBindingGuid = &gEfiDhcp4ServiceBindingProtocolGuid; 260 } else { 261 IScsiServiceBindingGuid = &gIScsiV6PrivateGuid; 262 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid; 263 DhcpServiceBindingGuid = &gEfiDhcp6ServiceBindingProtocolGuid; 264 } 265 266 Status = gBS->OpenProtocol ( 267 ControllerHandle, 268 IScsiServiceBindingGuid, 269 NULL, 270 This->DriverBindingHandle, 271 ControllerHandle, 272 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 273 ); 274 if (!EFI_ERROR (Status)) { 275 return EFI_ALREADY_STARTED; 276 } 277 278 Status = gBS->OpenProtocol ( 279 ControllerHandle, 280 TcpServiceBindingGuid, 281 NULL, 282 This->DriverBindingHandle, 283 ControllerHandle, 284 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 285 ); 286 if (EFI_ERROR (Status)) { 287 return EFI_UNSUPPORTED; 288 } 289 290 Status = IScsiIsDevicePathSupported (RemainingDevicePath); 291 if (EFI_ERROR (Status)) { 292 return EFI_UNSUPPORTED; 293 } 294 295 if (IScsiDhcpIsConfigured (ControllerHandle, IpVersion)) { 296 Status = gBS->OpenProtocol ( 297 ControllerHandle, 298 DhcpServiceBindingGuid, 299 NULL, 300 This->DriverBindingHandle, 301 ControllerHandle, 302 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 303 ); 304 if (EFI_ERROR (Status)) { 305 return EFI_UNSUPPORTED; 306 } 307 } 308 309 return EFI_SUCCESS; 310 } 311 312 313 /** 314 Start to manage the controller. This is the worker function for 315 IScsiIp4(6)DriverBindingStart. 316 317 @param[in] Image Handle of the image. 318 @param[in] ControllerHandle Handle of the controller. 319 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. 320 321 @retval EFI_SUCCES This driver was started. 322 @retval EFI_ALREADY_STARTED This driver is already running on this device. 323 @retval EFI_INVALID_PARAMETER Any input parameter is invalid. 324 @retval EFI_NOT_FOUND There is no sufficient information to establish 325 the iScsi session. 326 @retval EFI_DEVICE_ERROR Failed to get TCP connection device path. 327 328 **/ 329 EFI_STATUS 330 IScsiStart ( 331 IN EFI_HANDLE Image, 332 IN EFI_HANDLE ControllerHandle, 333 IN UINT8 IpVersion 334 ) 335 { 336 EFI_STATUS Status; 337 ISCSI_DRIVER_DATA *Private; 338 LIST_ENTRY *Entry; 339 LIST_ENTRY *NextEntry; 340 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData; 341 ISCSI_SESSION *Session; 342 UINT8 Index; 343 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExistIScsiExtScsiPassThru; 344 ISCSI_DRIVER_DATA *ExistPrivate; 345 UINT8 *AttemptConfigOrder; 346 UINTN AttemptConfigOrderSize; 347 UINT8 BootSelected; 348 EFI_HANDLE *HandleBuffer; 349 UINTN NumberOfHandles; 350 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 351 EFI_GUID *IScsiPrivateGuid; 352 EFI_GUID *TcpServiceBindingGuid; 353 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN]; 354 BOOLEAN NeedUpdate; 355 VOID *Interface; 356 EFI_GUID *ProtocolGuid; 357 UINT8 NetworkBootPolicy; 358 359 // 360 // Test to see if iSCSI driver supports the given controller. 361 // 362 363 if (IpVersion == IP_VERSION_4) { 364 IScsiPrivateGuid = &gIScsiV4PrivateGuid; 365 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid; 366 ProtocolGuid = &gEfiTcp4ProtocolGuid; 367 } else if (IpVersion == IP_VERSION_6) { 368 IScsiPrivateGuid = &gIScsiV6PrivateGuid; 369 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid; 370 ProtocolGuid = &gEfiTcp6ProtocolGuid; 371 } else { 372 return EFI_INVALID_PARAMETER; 373 } 374 375 Status = gBS->OpenProtocol ( 376 ControllerHandle, 377 IScsiPrivateGuid, 378 NULL, 379 Image, 380 ControllerHandle, 381 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 382 ); 383 if (!EFI_ERROR (Status)) { 384 return EFI_ALREADY_STARTED; 385 } 386 387 Status = gBS->OpenProtocol ( 388 ControllerHandle, 389 TcpServiceBindingGuid, 390 NULL, 391 Image, 392 ControllerHandle, 393 EFI_OPEN_PROTOCOL_TEST_PROTOCOL 394 ); 395 if (EFI_ERROR (Status)) { 396 return EFI_UNSUPPORTED; 397 } 398 399 NetworkBootPolicy = PcdGet8 (PcdIScsiAIPNetworkBootPolicy); 400 if (NetworkBootPolicy != ALWAYS_USE_UEFI_ISCSI_AND_IGNORE_AIP) { 401 // 402 // Check existing iSCSI AIP. 403 // 404 Status = IScsiCheckAip (); 405 if (!EFI_ERROR (Status)) { 406 // 407 // Find iSCSI AIP with specified network boot policy. return EFI_ABORTED. 408 // 409 return EFI_ABORTED; 410 } 411 } 412 413 // 414 // Record the incoming NIC info. 415 // 416 Status = IScsiAddNic (ControllerHandle); 417 if (EFI_ERROR (Status)) { 418 return Status; 419 } 420 421 // 422 // Create the instance private data. 423 // 424 Private = IScsiCreateDriverData (Image, ControllerHandle); 425 if (Private == NULL) { 426 return EFI_OUT_OF_RESOURCES; 427 } 428 429 // 430 // Create a underlayer child instance, but not need to configure it. Just open ChildHandle 431 // via BY_DRIVER. That is, establishing the relationship between ControllerHandle and ChildHandle. 432 // Therefore, when DisconnectController(), especially VLAN virtual controller handle, 433 // IScsiDriverBindingStop() will be called. 434 // 435 Status = NetLibCreateServiceChild ( 436 ControllerHandle, 437 Image, 438 TcpServiceBindingGuid, 439 &Private->ChildHandle 440 ); 441 442 if (EFI_ERROR (Status)) { 443 goto ON_ERROR; 444 } 445 446 Status = gBS->OpenProtocol ( 447 Private->ChildHandle, /// Default Tcp child 448 ProtocolGuid, 449 &Interface, 450 Image, 451 ControllerHandle, 452 EFI_OPEN_PROTOCOL_BY_DRIVER 453 ); 454 455 if (EFI_ERROR (Status)) { 456 goto ON_ERROR; 457 } 458 459 // 460 // Always install private protocol no matter what happens later. We need to 461 // keep the relationship between ControllerHandle and ChildHandle. 462 // 463 Status = gBS->InstallProtocolInterface ( 464 &ControllerHandle, 465 IScsiPrivateGuid, 466 EFI_NATIVE_INTERFACE, 467 &Private->IScsiIdentifier 468 ); 469 if (EFI_ERROR (Status)) { 470 goto ON_ERROR; 471 } 472 473 if (IpVersion == IP_VERSION_4) { 474 mPrivate->Ipv6Flag = FALSE; 475 } else { 476 mPrivate->Ipv6Flag = TRUE; 477 } 478 479 // 480 // Get the current iSCSI configuration data. 481 // 482 Status = IScsiGetConfigData (Private); 483 if (EFI_ERROR (Status)) { 484 goto ON_ERROR; 485 } 486 487 // 488 // If there is already a successul attempt, check whether this attempt is the 489 // first "enabled for MPIO" attempt. If not, still try the first attempt. 490 // In single path mode, try all attempts. 491 // 492 ExistPrivate = NULL; 493 Status = EFI_NOT_FOUND; 494 495 if (mPrivate->OneSessionEstablished && mPrivate->EnableMpio) { 496 AttemptConfigData = NULL; 497 NET_LIST_FOR_EACH (Entry, &mPrivate->AttemptConfigs) { 498 AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); 499 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) { 500 break; 501 } 502 } 503 504 if (AttemptConfigData == NULL) { 505 goto ON_ERROR; 506 } 507 508 if (AttemptConfigData->AttemptConfigIndex == mPrivate->BootSelectedIndex) { 509 goto ON_EXIT; 510 } 511 512 // 513 // Uninstall the original ExtScsiPassThru first. 514 // 515 516 // 517 // Locate all ExtScsiPassThru protocol instances. 518 // 519 Status = gBS->LocateHandleBuffer ( 520 ByProtocol, 521 &gEfiExtScsiPassThruProtocolGuid, 522 NULL, 523 &NumberOfHandles, 524 &HandleBuffer 525 ); 526 if (EFI_ERROR (Status)) { 527 goto ON_ERROR; 528 } 529 530 // 531 // Find ExtScsiPassThru protocol instance produced by this driver. 532 // 533 ExistIScsiExtScsiPassThru = NULL; 534 for (Index = 0; Index < NumberOfHandles && ExistIScsiExtScsiPassThru == NULL; Index++) { 535 Status = gBS->HandleProtocol ( 536 HandleBuffer[Index], 537 &gEfiDevicePathProtocolGuid, 538 (VOID **) &DevicePath 539 ); 540 if (EFI_ERROR (Status)) { 541 continue; 542 } 543 544 while (!IsDevicePathEnd (DevicePath)) { 545 if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_MAC_ADDR_DP)) { 546 // 547 // Get the ExtScsiPassThru protocol instance. 548 // 549 Status = gBS->HandleProtocol ( 550 HandleBuffer[Index], 551 &gEfiExtScsiPassThruProtocolGuid, 552 (VOID **) &ExistIScsiExtScsiPassThru 553 ); 554 ASSERT_EFI_ERROR (Status); 555 break; 556 } 557 558 DevicePath = NextDevicePathNode (DevicePath); 559 } 560 } 561 562 FreePool (HandleBuffer); 563 564 if (ExistIScsiExtScsiPassThru == NULL) { 565 Status = EFI_NOT_FOUND; 566 goto ON_ERROR; 567 } 568 569 ExistPrivate = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (ExistIScsiExtScsiPassThru); 570 571 Status = gBS->UninstallProtocolInterface ( 572 ExistPrivate->ExtScsiPassThruHandle, 573 &gEfiExtScsiPassThruProtocolGuid, 574 &ExistPrivate->IScsiExtScsiPassThru 575 ); 576 if (EFI_ERROR (Status)) { 577 goto ON_ERROR; 578 } 579 } 580 581 // 582 // Install the Ext SCSI PASS THRU protocol. 583 // 584 Status = gBS->InstallProtocolInterface ( 585 &Private->ExtScsiPassThruHandle, 586 &gEfiExtScsiPassThruProtocolGuid, 587 EFI_NATIVE_INTERFACE, 588 &Private->IScsiExtScsiPassThru 589 ); 590 if (EFI_ERROR (Status)) { 591 goto ON_ERROR; 592 } 593 594 BootSelected = 0; 595 596 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) { 597 AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link); 598 // 599 // Don't process the attempt that does not associate with the current NIC or 600 // this attempt is disabled or established. 601 // 602 if (AttemptConfigData->NicIndex != mPrivate->CurrentNic || 603 AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED || 604 AttemptConfigData->ValidPath) { 605 continue; 606 } 607 608 // 609 // In multipath mode, don't process attempts configured for single path. 610 // In default single path mode, don't process attempts configured for multipath. 611 // 612 if ((mPrivate->EnableMpio && 613 AttemptConfigData->SessionConfigData.Enabled != ISCSI_ENABLED_FOR_MPIO) || 614 (!mPrivate->EnableMpio && 615 AttemptConfigData->SessionConfigData.Enabled != ISCSI_ENABLED)) { 616 continue; 617 } 618 619 // 620 // Don't process the attempt that fails to get the init/target information from DHCP. 621 // 622 if (AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp && 623 !AttemptConfigData->DhcpSuccess) { 624 if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) { 625 mPrivate->ValidSinglePathCount--; 626 } 627 continue; 628 } 629 630 // 631 // Don't process the autoconfigure path if it is already established. 632 // 633 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG && 634 AttemptConfigData->AutoConfigureSuccess) { 635 continue; 636 } 637 638 // 639 // Don't process the attempt if its IP mode is not in the current IP version. 640 // 641 if (!mPrivate->Ipv6Flag) { 642 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) { 643 continue; 644 } 645 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG && 646 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) { 647 continue; 648 } 649 } else { 650 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) { 651 continue; 652 } 653 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG && 654 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) { 655 continue; 656 } 657 } 658 659 // 660 // Fill in the Session and init it. 661 // 662 Session = (ISCSI_SESSION *) AllocateZeroPool (sizeof (ISCSI_SESSION)); 663 if (Session == NULL) { 664 Status = EFI_OUT_OF_RESOURCES; 665 goto ON_ERROR; 666 } 667 668 Session->Private = Private; 669 Session->ConfigData = AttemptConfigData; 670 Session->AuthType = AttemptConfigData->AuthenticationType; 671 672 AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString); 673 UnicodeSPrint ( 674 mPrivate->PortString, 675 (UINTN) ISCSI_NAME_IFR_MAX_SIZE, 676 L"%s%d", 677 MacString, 678 (UINTN) AttemptConfigData->AttemptConfigIndex 679 ); 680 681 if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) { 682 Session->AuthData.CHAP.AuthConfig = &AttemptConfigData->AuthConfigData.CHAP; 683 } 684 685 IScsiSessionInit (Session, FALSE); 686 687 // 688 // Try to login and create an iSCSI session according to the configuration. 689 // 690 Status = IScsiSessionLogin (Session); 691 if (Status == EFI_MEDIA_CHANGED) { 692 // 693 // The specified target is not available, and the redirection information is 694 // received. Login the session again with the updated target address. 695 // 696 Status = IScsiSessionLogin (Session); 697 } else if (Status == EFI_NOT_READY) { 698 Status = IScsiSessionReLogin (Session); 699 } 700 701 if (EFI_ERROR (Status)) { 702 // 703 // In Single path mode, only the successful attempt will be recorded in iBFT; 704 // in multi-path mode, all the attempt entries in MPIO will be recorded in iBFT. 705 // 706 if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) { 707 mPrivate->ValidSinglePathCount--; 708 } 709 710 FreePool (Session); 711 712 } else { 713 AttemptConfigData->ValidPath = TRUE; 714 715 // 716 // Do not record the attempt in iBFT if it login with KRB5. 717 // TODO: record KRB5 attempt information in the iSCSI device path. 718 // 719 if (Session->AuthType == ISCSI_AUTH_TYPE_KRB) { 720 if (!mPrivate->EnableMpio && mPrivate->ValidSinglePathCount > 0) { 721 mPrivate->ValidSinglePathCount--; 722 } 723 724 AttemptConfigData->ValidiBFTPath = FALSE; 725 } else { 726 AttemptConfigData->ValidiBFTPath = TRUE; 727 } 728 729 // 730 // IScsi session success. Update the attempt state to NVR. 731 // 732 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) { 733 AttemptConfigData->AutoConfigureSuccess = TRUE; 734 } 735 736 gRT->SetVariable ( 737 mPrivate->PortString, 738 &gEfiIScsiInitiatorNameProtocolGuid, 739 ISCSI_CONFIG_VAR_ATTR, 740 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA), 741 AttemptConfigData 742 ); 743 744 // 745 // Select the first login session. Abort others. 746 // 747 if (Private->Session == NULL) { 748 Private->Session = Session; 749 BootSelected = AttemptConfigData->AttemptConfigIndex; 750 // 751 // Don't validate other attempt in multipath mode if one is success. 752 // 753 if (mPrivate->EnableMpio) { 754 break; 755 } 756 } else { 757 IScsiSessionAbort (Session); 758 FreePool (Session); 759 } 760 } 761 } 762 763 // 764 // All attempts configured for this driver instance are not valid. 765 // 766 if (Private->Session == NULL) { 767 Status = gBS->UninstallProtocolInterface ( 768 Private->ExtScsiPassThruHandle, 769 &gEfiExtScsiPassThruProtocolGuid, 770 &Private->IScsiExtScsiPassThru 771 ); 772 ASSERT_EFI_ERROR (Status); 773 Private->ExtScsiPassThruHandle = NULL; 774 775 // 776 // Reinstall the original ExtScsiPassThru back. 777 // 778 if (mPrivate->OneSessionEstablished && ExistPrivate != NULL) { 779 Status = gBS->InstallProtocolInterface ( 780 &ExistPrivate->ExtScsiPassThruHandle, 781 &gEfiExtScsiPassThruProtocolGuid, 782 EFI_NATIVE_INTERFACE, 783 &ExistPrivate->IScsiExtScsiPassThru 784 ); 785 if (EFI_ERROR (Status)) { 786 goto ON_ERROR; 787 } 788 789 goto ON_EXIT; 790 } 791 792 Status = EFI_NOT_FOUND; 793 794 goto ON_ERROR; 795 } 796 797 NeedUpdate = TRUE; 798 // 799 // More than one attempt successes. 800 // 801 if (Private->Session != NULL && mPrivate->OneSessionEstablished) { 802 803 AttemptConfigOrder = IScsiGetVariableAndSize ( 804 L"AttemptOrder", 805 &gIScsiConfigGuid, 806 &AttemptConfigOrderSize 807 ); 808 if (AttemptConfigOrder == NULL) { 809 goto ON_ERROR; 810 } 811 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) { 812 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex || 813 AttemptConfigOrder[Index] == BootSelected) { 814 break; 815 } 816 } 817 818 if (mPrivate->EnableMpio) { 819 // 820 // Use the attempt in earlier order. Abort the later one in MPIO. 821 // 822 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) { 823 IScsiSessionAbort (Private->Session); 824 FreePool (Private->Session); 825 Private->Session = NULL; 826 gBS->UninstallProtocolInterface ( 827 Private->ExtScsiPassThruHandle, 828 &gEfiExtScsiPassThruProtocolGuid, 829 &Private->IScsiExtScsiPassThru 830 ); 831 Private->ExtScsiPassThruHandle = NULL; 832 833 // 834 // Reinstall the original ExtScsiPassThru back. 835 // 836 Status = gBS->InstallProtocolInterface ( 837 &ExistPrivate->ExtScsiPassThruHandle, 838 &gEfiExtScsiPassThruProtocolGuid, 839 EFI_NATIVE_INTERFACE, 840 &ExistPrivate->IScsiExtScsiPassThru 841 ); 842 if (EFI_ERROR (Status)) { 843 goto ON_ERROR; 844 } 845 846 goto ON_EXIT; 847 } else { 848 if (AttemptConfigOrder[Index] != BootSelected) { 849 goto ON_ERROR; 850 } 851 mPrivate->BootSelectedIndex = BootSelected; 852 // 853 // Clear the resource in ExistPrivate. 854 // 855 gBS->UninstallProtocolInterface ( 856 ExistPrivate->Controller, 857 IScsiPrivateGuid, 858 &ExistPrivate->IScsiIdentifier 859 ); 860 861 IScsiRemoveNic (ExistPrivate->Controller); 862 if (ExistPrivate->Session != NULL) { 863 IScsiSessionAbort (ExistPrivate->Session); 864 } 865 866 IScsiCleanDriverData (ExistPrivate); 867 } 868 } else { 869 // 870 // Use the attempt in earlier order as boot selected in single path mode. 871 // 872 if (AttemptConfigOrder[Index] == mPrivate->BootSelectedIndex) { 873 NeedUpdate = FALSE; 874 } 875 } 876 877 } 878 879 if (NeedUpdate) { 880 mPrivate->OneSessionEstablished = TRUE; 881 mPrivate->BootSelectedIndex = BootSelected; 882 } 883 884 // 885 // Duplicate the Session's tcp connection device path. The source port field 886 // will be set to zero as one iSCSI session is comprised of several iSCSI 887 // connections. 888 // 889 Private->DevicePath = IScsiGetTcpConnDevicePath (Private->Session); 890 if (Private->DevicePath == NULL) { 891 Status = EFI_DEVICE_ERROR; 892 goto ON_ERROR; 893 } 894 // 895 // Install the updated device path onto the ExtScsiPassThruHandle. 896 // 897 Status = gBS->InstallProtocolInterface ( 898 &Private->ExtScsiPassThruHandle, 899 &gEfiDevicePathProtocolGuid, 900 EFI_NATIVE_INTERFACE, 901 Private->DevicePath 902 ); 903 if (EFI_ERROR (Status)) { 904 goto ON_ERROR; 905 } 906 907 // 908 // ISCSI children should share the default Tcp child, just open the default Tcp child via BY_CHILD_CONTROLLER. 909 // 910 Status = gBS->OpenProtocol ( 911 Private->ChildHandle, /// Default Tcp child 912 ProtocolGuid, 913 &Interface, 914 Image, 915 Private->ExtScsiPassThruHandle, 916 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 917 ); 918 if (EFI_ERROR (Status)) { 919 gBS->UninstallMultipleProtocolInterfaces ( 920 Private->ExtScsiPassThruHandle, 921 &gEfiExtScsiPassThruProtocolGuid, 922 &Private->IScsiExtScsiPassThru, 923 &gEfiDevicePathProtocolGuid, 924 Private->DevicePath, 925 NULL 926 ); 927 928 goto ON_ERROR; 929 } 930 931 ON_EXIT: 932 933 // 934 // Update/Publish the iSCSI Boot Firmware Table. 935 // 936 if (mPrivate->BootSelectedIndex != 0) { 937 IScsiPublishIbft (); 938 } 939 940 return EFI_SUCCESS; 941 942 ON_ERROR: 943 944 if (Private->Session != NULL) { 945 IScsiSessionAbort (Private->Session); 946 } 947 948 return Status; 949 } 950 951 /** 952 Stops a device controller or a bus controller. This is the worker function for 953 IScsiIp4(6)DriverBindingStop. 954 955 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. 956 @param[in] ControllerHandle A handle to the device being stopped. The handle must 957 support a bus specific I/O protocol for the driver 958 to use to stop the device. 959 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. 960 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL 961 if NumberOfChildren is 0. 962 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. 963 964 @retval EFI_SUCCESS The device was stopped. 965 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. 966 967 **/ 968 EFI_STATUS 969 EFIAPI 970 IScsiStop ( 971 IN EFI_DRIVER_BINDING_PROTOCOL *This, 972 IN EFI_HANDLE ControllerHandle, 973 IN UINTN NumberOfChildren, 974 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL, 975 IN UINT8 IpVersion 976 ) 977 { 978 EFI_HANDLE IScsiController; 979 EFI_STATUS Status; 980 ISCSI_PRIVATE_PROTOCOL *IScsiIdentifier; 981 ISCSI_DRIVER_DATA *Private; 982 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru; 983 ISCSI_CONNECTION *Conn; 984 EFI_GUID *ProtocolGuid; 985 EFI_GUID *TcpServiceBindingGuid; 986 EFI_GUID *TcpProtocolGuid; 987 988 989 if (NumberOfChildren != 0) { 990 // 991 // We should have only one child. 992 // 993 Status = gBS->OpenProtocol ( 994 ChildHandleBuffer[0], 995 &gEfiExtScsiPassThruProtocolGuid, 996 (VOID **) &PassThru, 997 This->DriverBindingHandle, 998 ControllerHandle, 999 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1000 ); 1001 if (EFI_ERROR (Status)) { 1002 return EFI_DEVICE_ERROR; 1003 } 1004 1005 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru); 1006 Conn = NET_LIST_HEAD (&Private->Session->Conns, ISCSI_CONNECTION, Link); 1007 1008 // 1009 // Previously the TCP protocol is opened BY_CHILD_CONTROLLER. Just close 1010 // the protocol here, but do not uninstall the device path protocol and 1011 // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle. 1012 // 1013 if (IpVersion == IP_VERSION_4) { 1014 ProtocolGuid = &gEfiTcp4ProtocolGuid; 1015 } else { 1016 ProtocolGuid = &gEfiTcp6ProtocolGuid; 1017 } 1018 1019 gBS->CloseProtocol ( 1020 Private->ChildHandle, 1021 ProtocolGuid, 1022 Private->Image, 1023 Private->ExtScsiPassThruHandle 1024 ); 1025 1026 gBS->CloseProtocol ( 1027 Conn->TcpIo.Handle, 1028 ProtocolGuid, 1029 Private->Image, 1030 Private->ExtScsiPassThruHandle 1031 ); 1032 1033 return EFI_SUCCESS; 1034 } 1035 1036 // 1037 // Get the handle of the controller we are controling. 1038 // 1039 if (IpVersion == IP_VERSION_4) { 1040 ProtocolGuid = &gIScsiV4PrivateGuid; 1041 TcpProtocolGuid = &gEfiTcp4ProtocolGuid; 1042 TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid; 1043 } else { 1044 ProtocolGuid = &gIScsiV6PrivateGuid; 1045 TcpProtocolGuid = &gEfiTcp6ProtocolGuid; 1046 TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid; 1047 } 1048 IScsiController = NetLibGetNicHandle (ControllerHandle, TcpProtocolGuid); 1049 if (IScsiController == NULL) { 1050 return EFI_SUCCESS; 1051 } 1052 1053 Status = gBS->OpenProtocol ( 1054 IScsiController, 1055 ProtocolGuid, 1056 (VOID **) &IScsiIdentifier, 1057 This->DriverBindingHandle, 1058 ControllerHandle, 1059 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1060 ); 1061 if (EFI_ERROR (Status)) { 1062 return EFI_DEVICE_ERROR; 1063 } 1064 1065 Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier); 1066 ASSERT (Private != NULL); 1067 1068 if (Private->ChildHandle != NULL) { 1069 Status = gBS->CloseProtocol ( 1070 Private->ChildHandle, 1071 TcpProtocolGuid, 1072 This->DriverBindingHandle, 1073 IScsiController 1074 ); 1075 1076 ASSERT (!EFI_ERROR (Status)); 1077 1078 Status = NetLibDestroyServiceChild ( 1079 IScsiController, 1080 This->DriverBindingHandle, 1081 TcpServiceBindingGuid, 1082 Private->ChildHandle 1083 ); 1084 1085 ASSERT (!EFI_ERROR (Status)); 1086 } 1087 1088 gBS->UninstallProtocolInterface ( 1089 IScsiController, 1090 ProtocolGuid, 1091 &Private->IScsiIdentifier 1092 ); 1093 1094 // 1095 // Remove this NIC. 1096 // 1097 IScsiRemoveNic (IScsiController); 1098 1099 // 1100 // Update the iSCSI Boot Firware Table. 1101 // 1102 IScsiPublishIbft (); 1103 1104 if (Private->Session != NULL) { 1105 IScsiSessionAbort (Private->Session); 1106 } 1107 1108 IScsiCleanDriverData (Private); 1109 1110 return EFI_SUCCESS; 1111 } 1112 1113 /** 1114 Tests to see if this driver supports a given controller. If a child device is provided, 1115 it tests to see if this driver supports creating a handle for the specified child device. 1116 1117 This function checks to see if the driver specified by This supports the device specified by 1118 ControllerHandle. Drivers typically use the device path attached to 1119 ControllerHandle and/or the services from the bus I/O abstraction attached to 1120 ControllerHandle to determine if the driver supports ControllerHandle. This function 1121 may be called many times during platform initialization. In order to reduce boot times, the tests 1122 performed by this function must be very small and take as little time as possible to execute. This 1123 function must not change the state of any hardware devices, and this function must be aware that the 1124 device specified by ControllerHandle may already be managed by the same driver or a 1125 different driver. This function must match its calls to AllocatePages() with FreePages(), 1126 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). 1127 Since ControllerHandle may have been previously started by the same driver, if a protocol is 1128 already in the opened state, then it must not be closed with CloseProtocol(). This is required 1129 to guarantee the state of ControllerHandle is not modified by this function. 1130 1131 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. 1132 @param[in] ControllerHandle The handle of the controller to test. This handle 1133 must support a protocol interface that supplies 1134 an I/O abstraction to the driver. 1135 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This 1136 parameter is ignored by device drivers, and is optional for bus 1137 drivers. For bus drivers, if this parameter is not NULL, then 1138 the bus driver must determine if the bus controller specified 1139 by ControllerHandle and the child controller specified 1140 by RemainingDevicePath are both supported by this 1141 bus driver. 1142 1143 @retval EFI_SUCCESS The device specified by ControllerHandle and 1144 RemainingDevicePath is supported by the driver specified by This. 1145 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and 1146 RemainingDevicePath is already managed by the driver 1147 specified by This. 1148 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and 1149 RemainingDevicePath is already managed by a different 1150 driver or an application that requires exclusive access. 1151 Currently not implemented. 1152 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and 1153 RemainingDevicePath is not supported by the driver specified by This. 1154 **/ 1155 EFI_STATUS 1156 EFIAPI 1157 IScsiIp4DriverBindingSupported ( 1158 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1159 IN EFI_HANDLE ControllerHandle, 1160 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL 1161 ) 1162 { 1163 return IScsiSupported ( 1164 This, 1165 ControllerHandle, 1166 RemainingDevicePath, 1167 IP_VERSION_4 1168 ); 1169 } 1170 1171 /** 1172 Starts a device controller or a bus controller. 1173 1174 The Start() function is designed to be invoked from the EFI boot service ConnectController(). 1175 As a result, much of the error checking on the parameters to Start() has been moved into this 1176 common boot service. It is legal to call Start() from other locations, 1177 but the following calling restrictions must be followed or the system behavior will not be deterministic. 1178 1. ControllerHandle must be a valid EFI_HANDLE. 1179 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned 1180 EFI_DEVICE_PATH_PROTOCOL. 1181 3. Prior to calling Start(), the Supported() function for the driver specified by This must 1182 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. 1183 1184 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. 1185 @param[in] ControllerHandle The handle of the controller to start. This handle 1186 must support a protocol interface that supplies 1187 an I/O abstraction to the driver. 1188 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This 1189 parameter is ignored by device drivers, and is optional for bus 1190 drivers. For a bus driver, if this parameter is NULL, then handles 1191 for all the children of Controller are created by this driver. 1192 If this parameter is not NULL and the first Device Path Node is 1193 not the End of Device Path Node, then only the handle for the 1194 child device specified by the first Device Path Node of 1195 RemainingDevicePath is created by this driver. 1196 If the first Device Path Node of RemainingDevicePath is 1197 the End of Device Path Node, no child handle is created by this 1198 driver. 1199 1200 @retval EFI_SUCCESS The device was started. 1201 @retval EFI_DEVICE_ERROR The device could not be started due to a device error. Currently not implemented. 1202 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 1203 @retval Others The driver failed to start the device. 1204 1205 **/ 1206 EFI_STATUS 1207 EFIAPI 1208 IScsiIp4DriverBindingStart ( 1209 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1210 IN EFI_HANDLE ControllerHandle, 1211 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL 1212 ) 1213 { 1214 EFI_STATUS Status; 1215 1216 Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_4); 1217 if (Status == EFI_ALREADY_STARTED) { 1218 Status = EFI_SUCCESS; 1219 } 1220 1221 return Status; 1222 } 1223 1224 /** 1225 Stops a device controller or a bus controller. 1226 1227 The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). 1228 As a result, much of the error checking on the parameters to Stop() has been moved 1229 into this common boot service. It is legal to call Stop() from other locations, 1230 but the following calling restrictions must be followed or the system behavior will not be deterministic. 1231 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this 1232 same driver's Start() function. 1233 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid 1234 EFI_HANDLE. In addition, all of these handles must have been created in this driver's 1235 Start() function, and the Start() function must have called OpenProtocol() on 1236 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. 1237 1238 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. 1239 @param[in] ControllerHandle A handle to the device being stopped. The handle must 1240 support a bus specific I/O protocol for the driver 1241 to use to stop the device. 1242 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. 1243 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL 1244 if NumberOfChildren is 0. 1245 1246 @retval EFI_SUCCESS The device was stopped. 1247 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. 1248 1249 **/ 1250 EFI_STATUS 1251 EFIAPI 1252 IScsiIp4DriverBindingStop ( 1253 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1254 IN EFI_HANDLE ControllerHandle, 1255 IN UINTN NumberOfChildren, 1256 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL 1257 ) 1258 { 1259 return IScsiStop ( 1260 This, 1261 ControllerHandle, 1262 NumberOfChildren, 1263 ChildHandleBuffer, 1264 IP_VERSION_4 1265 ); 1266 } 1267 1268 /** 1269 Tests to see if this driver supports a given controller. If a child device is provided, 1270 it tests to see if this driver supports creating a handle for the specified child device. 1271 1272 This function checks to see if the driver specified by This supports the device specified by 1273 ControllerHandle. Drivers typically use the device path attached to 1274 ControllerHandle and/or the services from the bus I/O abstraction attached to 1275 ControllerHandle to determine if the driver supports ControllerHandle. This function 1276 may be called many times during platform initialization. In order to reduce boot times, the tests 1277 performed by this function must be very small and take as little time as possible to execute. This 1278 function must not change the state of any hardware devices, and this function must be aware that the 1279 device specified by ControllerHandle may already be managed by the same driver or a 1280 different driver. This function must match its calls to AllocatePages() with FreePages(), 1281 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). 1282 Since ControllerHandle may have been previously started by the same driver, if a protocol is 1283 already in the opened state, then it must not be closed with CloseProtocol(). This is required 1284 to guarantee the state of ControllerHandle is not modified by this function. 1285 1286 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. 1287 @param[in] ControllerHandle The handle of the controller to test. This handle 1288 must support a protocol interface that supplies 1289 an I/O abstraction to the driver. 1290 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This 1291 parameter is ignored by device drivers, and is optional for bus 1292 drivers. For bus drivers, if this parameter is not NULL, then 1293 the bus driver must determine if the bus controller specified 1294 by ControllerHandle and the child controller specified 1295 by RemainingDevicePath are both supported by this 1296 bus driver. 1297 1298 @retval EFI_SUCCESS The device specified by ControllerHandle and 1299 RemainingDevicePath is supported by the driver specified by This. 1300 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and 1301 RemainingDevicePath is already managed by the driver 1302 specified by This. 1303 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and 1304 RemainingDevicePath is already managed by a different 1305 driver or an application that requires exclusive access. 1306 Currently not implemented. 1307 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and 1308 RemainingDevicePath is not supported by the driver specified by This. 1309 **/ 1310 EFI_STATUS 1311 EFIAPI 1312 IScsiIp6DriverBindingSupported ( 1313 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1314 IN EFI_HANDLE ControllerHandle, 1315 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL 1316 ) 1317 { 1318 return IScsiSupported ( 1319 This, 1320 ControllerHandle, 1321 RemainingDevicePath, 1322 IP_VERSION_6 1323 ); 1324 } 1325 1326 /** 1327 Starts a device controller or a bus controller. 1328 1329 The Start() function is designed to be invoked from the EFI boot service ConnectController(). 1330 As a result, much of the error checking on the parameters to Start() has been moved into this 1331 common boot service. It is legal to call Start() from other locations, 1332 but the following calling restrictions must be followed or the system behavior will not be deterministic. 1333 1. ControllerHandle must be a valid EFI_HANDLE. 1334 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned 1335 EFI_DEVICE_PATH_PROTOCOL. 1336 3. Prior to calling Start(), the Supported() function for the driver specified by This must 1337 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. 1338 1339 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. 1340 @param[in] ControllerHandle The handle of the controller to start. This handle 1341 must support a protocol interface that supplies 1342 an I/O abstraction to the driver. 1343 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This 1344 parameter is ignored by device drivers, and is optional for bus 1345 drivers. For a bus driver, if this parameter is NULL, then handles 1346 for all the children of Controller are created by this driver. 1347 If this parameter is not NULL and the first Device Path Node is 1348 not the End of Device Path Node, then only the handle for the 1349 child device specified by the first Device Path Node of 1350 RemainingDevicePath is created by this driver. 1351 If the first Device Path Node of RemainingDevicePath is 1352 the End of Device Path Node, no child handle is created by this 1353 driver. 1354 1355 @retval EFI_SUCCESS The device was started. 1356 @retval EFI_DEVICE_ERROR The device could not be started due to a device error. Currently not implemented. 1357 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 1358 @retval Others The driver failed to start the device. 1359 1360 **/ 1361 EFI_STATUS 1362 EFIAPI 1363 IScsiIp6DriverBindingStart ( 1364 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1365 IN EFI_HANDLE ControllerHandle, 1366 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL 1367 ) 1368 { 1369 EFI_STATUS Status; 1370 1371 Status = IScsiStart (This->DriverBindingHandle, ControllerHandle, IP_VERSION_6); 1372 if (Status == EFI_ALREADY_STARTED) { 1373 Status = EFI_SUCCESS; 1374 } 1375 1376 return Status; 1377 } 1378 1379 /** 1380 Stops a device controller or a bus controller. 1381 1382 The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). 1383 As a result, much of the error checking on the parameters to Stop() has been moved 1384 into this common boot service. It is legal to call Stop() from other locations, 1385 but the following calling restrictions must be followed or the system behavior will not be deterministic. 1386 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this 1387 same driver's Start() function. 1388 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid 1389 EFI_HANDLE. In addition, all of these handles must have been created in this driver's 1390 Start() function, and the Start() function must have called OpenProtocol() on 1391 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. 1392 1393 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. 1394 @param[in] ControllerHandle A handle to the device being stopped. The handle must 1395 support a bus specific I/O protocol for the driver 1396 to use to stop the device. 1397 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. 1398 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL 1399 if NumberOfChildren is 0. 1400 1401 @retval EFI_SUCCESS The device was stopped. 1402 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. 1403 1404 **/ 1405 EFI_STATUS 1406 EFIAPI 1407 IScsiIp6DriverBindingStop ( 1408 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1409 IN EFI_HANDLE ControllerHandle, 1410 IN UINTN NumberOfChildren, 1411 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL 1412 ) 1413 { 1414 return IScsiStop ( 1415 This, 1416 ControllerHandle, 1417 NumberOfChildren, 1418 ChildHandleBuffer, 1419 IP_VERSION_6 1420 ); 1421 } 1422 1423 /** 1424 Unload the iSCSI driver. 1425 1426 @param[in] ImageHandle The handle of the driver image. 1427 1428 @retval EFI_SUCCESS The driver is unloaded. 1429 @retval EFI_DEVICE_ERROR An unexpected error occurred. 1430 1431 **/ 1432 EFI_STATUS 1433 EFIAPI 1434 IScsiUnload ( 1435 IN EFI_HANDLE ImageHandle 1436 ) 1437 { 1438 EFI_STATUS Status; 1439 UINTN DeviceHandleCount; 1440 EFI_HANDLE *DeviceHandleBuffer; 1441 UINTN Index; 1442 EFI_COMPONENT_NAME_PROTOCOL *ComponentName; 1443 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2; 1444 1445 // 1446 // Try to disonnect the driver from the devices it's controlling. 1447 // 1448 Status = gBS->LocateHandleBuffer ( 1449 AllHandles, 1450 NULL, 1451 NULL, 1452 &DeviceHandleCount, 1453 &DeviceHandleBuffer 1454 ); 1455 if (EFI_ERROR (Status)) { 1456 return Status; 1457 } 1458 1459 // 1460 // Disconnect the iSCSI4 driver from the controlled device. 1461 // 1462 for (Index = 0; Index < DeviceHandleCount; Index++) { 1463 Status = IScsiTestManagedDevice ( 1464 DeviceHandleBuffer[Index], 1465 gIScsiIp4DriverBinding.DriverBindingHandle, 1466 &gEfiTcp4ProtocolGuid) 1467 ; 1468 if (EFI_ERROR (Status)) { 1469 continue; 1470 } 1471 Status = gBS->DisconnectController ( 1472 DeviceHandleBuffer[Index], 1473 gIScsiIp4DriverBinding.DriverBindingHandle, 1474 NULL 1475 ); 1476 if (EFI_ERROR (Status)) { 1477 goto ON_EXIT; 1478 } 1479 } 1480 1481 // 1482 // Disconnect the iSCSI6 driver from the controlled device. 1483 // 1484 for (Index = 0; Index < DeviceHandleCount; Index++) { 1485 Status = IScsiTestManagedDevice ( 1486 DeviceHandleBuffer[Index], 1487 gIScsiIp6DriverBinding.DriverBindingHandle, 1488 &gEfiTcp6ProtocolGuid 1489 ); 1490 if (EFI_ERROR (Status)) { 1491 continue; 1492 } 1493 Status = gBS->DisconnectController ( 1494 DeviceHandleBuffer[Index], 1495 gIScsiIp6DriverBinding.DriverBindingHandle, 1496 NULL 1497 ); 1498 if (EFI_ERROR (Status)) { 1499 goto ON_EXIT; 1500 } 1501 } 1502 1503 // 1504 // Unload the iSCSI configuration form. 1505 // 1506 Status = IScsiConfigFormUnload (gIScsiIp4DriverBinding.DriverBindingHandle); 1507 if (EFI_ERROR (Status)) { 1508 goto ON_EXIT; 1509 } 1510 1511 // 1512 // Uninstall the protocols installed by iSCSI driver. 1513 // 1514 Status = gBS->UninstallMultipleProtocolInterfaces ( 1515 ImageHandle, 1516 &gEfiAuthenticationInfoProtocolGuid, 1517 &gIScsiAuthenticationInfo, 1518 NULL 1519 ); 1520 if (EFI_ERROR (Status)) { 1521 goto ON_EXIT; 1522 } 1523 1524 if (gIScsiControllerNameTable!= NULL) { 1525 Status = FreeUnicodeStringTable (gIScsiControllerNameTable); 1526 if (EFI_ERROR (Status)) { 1527 goto ON_EXIT; 1528 } 1529 gIScsiControllerNameTable = NULL; 1530 } 1531 1532 // 1533 // Uninstall the ComponentName and ComponentName2 protocol from iSCSI4 driver binding handle 1534 // if it has been installed. 1535 // 1536 Status = gBS->HandleProtocol ( 1537 gIScsiIp4DriverBinding.DriverBindingHandle, 1538 &gEfiComponentNameProtocolGuid, 1539 (VOID **) &ComponentName 1540 ); 1541 if (!EFI_ERROR (Status)) { 1542 Status = gBS->UninstallMultipleProtocolInterfaces ( 1543 gIScsiIp4DriverBinding.DriverBindingHandle, 1544 &gEfiComponentNameProtocolGuid, 1545 ComponentName, 1546 NULL 1547 ); 1548 if (EFI_ERROR (Status)) { 1549 goto ON_EXIT; 1550 } 1551 } 1552 1553 Status = gBS->HandleProtocol ( 1554 gIScsiIp4DriverBinding.DriverBindingHandle, 1555 &gEfiComponentName2ProtocolGuid, 1556 (VOID **) &ComponentName2 1557 ); 1558 if (!EFI_ERROR (Status)) { 1559 gBS->UninstallMultipleProtocolInterfaces ( 1560 gIScsiIp4DriverBinding.DriverBindingHandle, 1561 &gEfiComponentName2ProtocolGuid, 1562 ComponentName2, 1563 NULL 1564 ); 1565 if (EFI_ERROR (Status)) { 1566 goto ON_EXIT; 1567 } 1568 } 1569 1570 // 1571 // Uninstall the ComponentName and ComponentName2 protocol from iSCSI6 driver binding handle 1572 // if it has been installed. 1573 // 1574 Status = gBS->HandleProtocol ( 1575 gIScsiIp6DriverBinding.DriverBindingHandle, 1576 &gEfiComponentNameProtocolGuid, 1577 (VOID **) &ComponentName 1578 ); 1579 if (!EFI_ERROR (Status)) { 1580 Status = gBS->UninstallMultipleProtocolInterfaces ( 1581 gIScsiIp6DriverBinding.DriverBindingHandle, 1582 &gEfiComponentNameProtocolGuid, 1583 ComponentName, 1584 NULL 1585 ); 1586 if (EFI_ERROR (Status)) { 1587 goto ON_EXIT; 1588 } 1589 } 1590 1591 Status = gBS->HandleProtocol ( 1592 gIScsiIp6DriverBinding.DriverBindingHandle, 1593 &gEfiComponentName2ProtocolGuid, 1594 (VOID **) &ComponentName2 1595 ); 1596 if (!EFI_ERROR (Status)) { 1597 gBS->UninstallMultipleProtocolInterfaces ( 1598 gIScsiIp6DriverBinding.DriverBindingHandle, 1599 &gEfiComponentName2ProtocolGuid, 1600 ComponentName2, 1601 NULL 1602 ); 1603 if (EFI_ERROR (Status)) { 1604 goto ON_EXIT; 1605 } 1606 } 1607 1608 // 1609 // Uninstall the IScsiInitiatorNameProtocol and all the driver binding protocols. 1610 // 1611 Status = gBS->UninstallMultipleProtocolInterfaces ( 1612 gIScsiIp4DriverBinding.DriverBindingHandle, 1613 &gEfiDriverBindingProtocolGuid, 1614 &gIScsiIp4DriverBinding, 1615 &gEfiIScsiInitiatorNameProtocolGuid, 1616 &gIScsiInitiatorName, 1617 NULL 1618 ); 1619 if (EFI_ERROR (Status)) { 1620 goto ON_EXIT; 1621 } 1622 1623 Status = gBS->UninstallMultipleProtocolInterfaces ( 1624 gIScsiIp6DriverBinding.DriverBindingHandle, 1625 &gEfiDriverBindingProtocolGuid, 1626 &gIScsiIp6DriverBinding, 1627 NULL 1628 ); 1629 1630 ON_EXIT: 1631 1632 if (DeviceHandleBuffer != NULL) { 1633 FreePool (DeviceHandleBuffer); 1634 } 1635 1636 return Status; 1637 } 1638 1639 /** 1640 This is the declaration of an EFI image entry point. This entry point is 1641 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including 1642 both device drivers and bus drivers. 1643 1644 The entry point for iSCSI driver which initializes the global variables and 1645 installs the driver binding, component name protocol, iSCSI initiator name 1646 protocol and Authentication Info protocol on its image. 1647 1648 @param[in] ImageHandle The firmware allocated handle for the UEFI image. 1649 @param[in] SystemTable A pointer to the EFI System Table. 1650 1651 @retval EFI_SUCCESS The operation completed successfully. 1652 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. 1653 1654 **/ 1655 EFI_STATUS 1656 EFIAPI 1657 IScsiDriverEntryPoint ( 1658 IN EFI_HANDLE ImageHandle, 1659 IN EFI_SYSTEM_TABLE *SystemTable 1660 ) 1661 { 1662 EFI_STATUS Status; 1663 EFI_ISCSI_INITIATOR_NAME_PROTOCOL *IScsiInitiatorName; 1664 EFI_AUTHENTICATION_INFO_PROTOCOL *AuthenticationInfo; 1665 1666 // 1667 // There should be only one EFI_ISCSI_INITIATOR_NAME_PROTOCOL. 1668 // 1669 Status = gBS->LocateProtocol ( 1670 &gEfiIScsiInitiatorNameProtocolGuid, 1671 NULL, 1672 (VOID **) &IScsiInitiatorName 1673 ); 1674 if (!EFI_ERROR (Status)) { 1675 return EFI_ACCESS_DENIED; 1676 } 1677 1678 // 1679 // Initialize the EFI Driver Library. 1680 // 1681 Status = EfiLibInstallDriverBindingComponentName2 ( 1682 ImageHandle, 1683 SystemTable, 1684 &gIScsiIp4DriverBinding, 1685 ImageHandle, 1686 &gIScsiComponentName, 1687 &gIScsiComponentName2 1688 ); 1689 if (EFI_ERROR (Status)) { 1690 return Status; 1691 } 1692 1693 Status = EfiLibInstallDriverBindingComponentName2 ( 1694 ImageHandle, 1695 SystemTable, 1696 &gIScsiIp6DriverBinding, 1697 NULL, 1698 &gIScsiComponentName, 1699 &gIScsiComponentName2 1700 ); 1701 if (EFI_ERROR (Status)) { 1702 goto Error1; 1703 } 1704 1705 // 1706 // Install the iSCSI Initiator Name Protocol. 1707 // 1708 Status = gBS->InstallProtocolInterface ( 1709 &ImageHandle, 1710 &gEfiIScsiInitiatorNameProtocolGuid, 1711 EFI_NATIVE_INTERFACE, 1712 &gIScsiInitiatorName 1713 ); 1714 if (EFI_ERROR (Status)) { 1715 goto Error2; 1716 } 1717 1718 // 1719 // Create the private data structures. 1720 // 1721 mPrivate = AllocateZeroPool (sizeof (ISCSI_PRIVATE_DATA)); 1722 if (mPrivate == NULL) { 1723 Status = EFI_OUT_OF_RESOURCES; 1724 goto Error3; 1725 } 1726 1727 InitializeListHead (&mPrivate->NicInfoList); 1728 InitializeListHead (&mPrivate->AttemptConfigs); 1729 1730 // 1731 // Initialize the configuration form of iSCSI. 1732 // 1733 Status = IScsiConfigFormInit (gIScsiIp4DriverBinding.DriverBindingHandle); 1734 if (EFI_ERROR (Status)) { 1735 goto Error4; 1736 } 1737 1738 // 1739 // There should be only one EFI_AUTHENTICATION_INFO_PROTOCOL. If already exists, 1740 // do not produce the protocol instance. 1741 // 1742 Status = gBS->LocateProtocol ( 1743 &gEfiAuthenticationInfoProtocolGuid, 1744 NULL, 1745 (VOID **) &AuthenticationInfo 1746 ); 1747 if (Status == EFI_NOT_FOUND) { 1748 Status = gBS->InstallProtocolInterface ( 1749 &ImageHandle, 1750 &gEfiAuthenticationInfoProtocolGuid, 1751 EFI_NATIVE_INTERFACE, 1752 &gIScsiAuthenticationInfo 1753 ); 1754 if (EFI_ERROR (Status)) { 1755 goto Error5; 1756 } 1757 } 1758 1759 return EFI_SUCCESS; 1760 1761 Error5: 1762 IScsiConfigFormUnload (gIScsiIp4DriverBinding.DriverBindingHandle); 1763 1764 Error4: 1765 FreePool (mPrivate); 1766 1767 Error3: 1768 gBS->UninstallMultipleProtocolInterfaces ( 1769 ImageHandle, 1770 &gEfiIScsiInitiatorNameProtocolGuid, 1771 &gIScsiInitiatorName, 1772 NULL 1773 ); 1774 1775 Error2: 1776 gBS->UninstallMultipleProtocolInterfaces ( 1777 gIScsiIp6DriverBinding.DriverBindingHandle, 1778 &gEfiDriverBindingProtocolGuid, 1779 &gIScsiIp6DriverBinding, 1780 &gEfiComponentName2ProtocolGuid, 1781 &gIScsiComponentName2, 1782 &gEfiComponentNameProtocolGuid, 1783 &gIScsiComponentName, 1784 NULL 1785 ); 1786 1787 Error1: 1788 gBS->UninstallMultipleProtocolInterfaces ( 1789 ImageHandle, 1790 &gEfiDriverBindingProtocolGuid, 1791 &gIScsiIp4DriverBinding, 1792 &gEfiComponentName2ProtocolGuid, 1793 &gIScsiComponentName2, 1794 &gEfiComponentNameProtocolGuid, 1795 &gIScsiComponentName, 1796 NULL 1797 ); 1798 1799 return Status; 1800 } 1801 1802