1 /** @file 2 SCSI Bus driver that layers on every SCSI Pass Thru and 3 Extended SCSI Pass Thru protocol in the system. 4 5 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 17 #include "ScsiBus.h" 18 19 20 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = { 21 SCSIBusDriverBindingSupported, 22 SCSIBusDriverBindingStart, 23 SCSIBusDriverBindingStop, 24 0xa, 25 NULL, 26 NULL 27 }; 28 29 VOID *mWorkingBuffer; 30 31 /** 32 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet. 33 34 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET 35 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET 36 37 **/ 38 EFI_STATUS 39 EFIAPI 40 ScsiioToPassThruPacket ( 41 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet, 42 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket 43 ); 44 45 /** 46 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet. 47 48 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET 49 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET 50 51 **/ 52 EFI_STATUS 53 EFIAPI 54 PassThruToScsiioPacket ( 55 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket, 56 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet 57 ); 58 59 /** 60 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0 61 SCSI IO Packet. 62 63 @param Event The instance of EFI_EVENT. 64 @param Context The parameter passed in. 65 66 **/ 67 VOID 68 EFIAPI 69 NotifyFunction ( 70 IN EFI_EVENT Event, 71 IN VOID *Context 72 ); 73 74 /** 75 Allocates an aligned buffer for SCSI device. 76 77 This function allocates an aligned buffer for the SCSI device to perform 78 SCSI pass through operations. The alignment requirement is from SCSI pass 79 through interface. 80 81 @param ScsiIoDevice The SCSI child device involved for the operation. 82 @param BufferSize The request buffer size. 83 84 @return A pointer to the aligned buffer or NULL if the allocation fails. 85 86 **/ 87 VOID * 88 AllocateAlignedBuffer ( 89 IN SCSI_IO_DEV *ScsiIoDevice, 90 IN UINTN BufferSize 91 ) 92 { 93 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiIoDevice->ScsiIo.IoAlign); 94 } 95 96 /** 97 Frees an aligned buffer for SCSI device. 98 99 This function frees an aligned buffer for the SCSI device to perform 100 SCSI pass through operations. 101 102 @param Buffer The aligned buffer to be freed. 103 @param BufferSize The request buffer size. 104 105 **/ 106 VOID 107 FreeAlignedBuffer ( 108 IN VOID *Buffer, 109 IN UINTN BufferSize 110 ) 111 { 112 if (Buffer != NULL) { 113 FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize)); 114 } 115 } 116 117 /** 118 The user Entry Point for module ScsiBus. The user code starts with this function. 119 120 @param ImageHandle The firmware allocated handle for the EFI image. 121 @param SystemTable A pointer to the EFI System Table. 122 123 @retval EFI_SUCCESS The entry point is executed successfully. 124 @retval other Some error occurs when executing this entry point. 125 126 **/ 127 EFI_STATUS 128 EFIAPI 129 InitializeScsiBus( 130 IN EFI_HANDLE ImageHandle, 131 IN EFI_SYSTEM_TABLE *SystemTable 132 ) 133 { 134 EFI_STATUS Status; 135 136 // 137 // Install driver model protocol(s). 138 // 139 Status = EfiLibInstallDriverBindingComponentName2 ( 140 ImageHandle, 141 SystemTable, 142 &gSCSIBusDriverBinding, 143 ImageHandle, 144 &gScsiBusComponentName, 145 &gScsiBusComponentName2 146 ); 147 ASSERT_EFI_ERROR (Status); 148 149 return Status; 150 } 151 152 153 /** 154 Test to see if this driver supports ControllerHandle. 155 156 This service is called by the EFI boot service ConnectController(). In order 157 to make drivers as small as possible, there are a few calling restrictions for 158 this service. ConnectController() must follow these calling restrictions. If 159 any other agent wishes to call Supported() it must also follow these calling 160 restrictions. 161 162 @param This Protocol instance pointer. 163 @param ControllerHandle Handle of device to test 164 @param RemainingDevicePath Optional parameter use to pick a specific child 165 device to start. 166 167 @retval EFI_SUCCESS This driver supports this device 168 @retval EFI_ALREADY_STARTED This driver is already running on this device 169 @retval other This driver does not support this device 170 171 **/ 172 EFI_STATUS 173 EFIAPI 174 SCSIBusDriverBindingSupported ( 175 IN EFI_DRIVER_BINDING_PROTOCOL *This, 176 IN EFI_HANDLE Controller, 177 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 178 ) 179 { 180 EFI_STATUS Status; 181 EFI_SCSI_PASS_THRU_PROTOCOL *PassThru; 182 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtPassThru; 183 UINT64 Lun; 184 UINT8 *TargetId; 185 SCSI_TARGET_ID ScsiTargetId; 186 187 TargetId = &ScsiTargetId.ScsiId.ExtScsi[0]; 188 SetMem (TargetId, TARGET_MAX_BYTES, 0xFF); 189 190 // 191 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as 192 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly 193 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead. 194 // 195 Status = gBS->OpenProtocol ( 196 Controller, 197 &gEfiExtScsiPassThruProtocolGuid, 198 (VOID **)&ExtPassThru, 199 This->DriverBindingHandle, 200 Controller, 201 EFI_OPEN_PROTOCOL_BY_DRIVER 202 ); 203 204 if (Status == EFI_ALREADY_STARTED) { 205 return EFI_SUCCESS; 206 } else if (!EFI_ERROR(Status)) { 207 // 208 // Check if RemainingDevicePath is NULL or the End of Device Path Node, 209 // if yes, return EFI_SUCCESS. 210 // 211 if ((RemainingDevicePath == NULL) || IsDevicePathEnd (RemainingDevicePath)) { 212 // 213 // Close protocol regardless of RemainingDevicePath validation 214 // 215 gBS->CloseProtocol ( 216 Controller, 217 &gEfiExtScsiPassThruProtocolGuid, 218 This->DriverBindingHandle, 219 Controller 220 ); 221 return EFI_SUCCESS; 222 } else { 223 // 224 // If RemainingDevicePath isn't the End of Device Path Node, check its validation 225 // 226 Status = ExtPassThru->GetTargetLun (ExtPassThru, RemainingDevicePath, &TargetId, &Lun); 227 // 228 // Close protocol regardless of RemainingDevicePath validation 229 // 230 gBS->CloseProtocol ( 231 Controller, 232 &gEfiExtScsiPassThruProtocolGuid, 233 This->DriverBindingHandle, 234 Controller 235 ); 236 if (!EFI_ERROR(Status)) { 237 return EFI_SUCCESS; 238 } 239 } 240 } 241 242 // 243 // Come here in 2 condition: 244 // 1. ExtPassThru doesn't exist. 245 // 2. ExtPassThru exists but RemainingDevicePath is invalid. 246 // 247 Status = gBS->OpenProtocol ( 248 Controller, 249 &gEfiScsiPassThruProtocolGuid, 250 (VOID **)&PassThru, 251 This->DriverBindingHandle, 252 Controller, 253 EFI_OPEN_PROTOCOL_BY_DRIVER 254 ); 255 256 if (Status == EFI_ALREADY_STARTED) { 257 return EFI_SUCCESS; 258 } 259 260 if (EFI_ERROR (Status)) { 261 return Status; 262 } 263 264 // 265 // Test RemainingDevicePath is valid or not. 266 // 267 if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) { 268 Status = PassThru->GetTargetLun (PassThru, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun); 269 } 270 271 gBS->CloseProtocol ( 272 Controller, 273 &gEfiScsiPassThruProtocolGuid, 274 This->DriverBindingHandle, 275 Controller 276 ); 277 return Status; 278 } 279 280 281 /** 282 Start this driver on ControllerHandle. 283 284 This service is called by the EFI boot service ConnectController(). In order 285 to make drivers as small as possible, there are a few calling restrictions for 286 this service. ConnectController() must follow these calling restrictions. If 287 any other agent wishes to call Start() it must also follow these calling 288 restrictions. 289 290 @param This Protocol instance pointer. 291 @param ControllerHandle Handle of device to bind driver to 292 @param RemainingDevicePath Optional parameter use to pick a specific child 293 device to start. 294 295 @retval EFI_SUCCESS This driver is added to ControllerHandle 296 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle 297 @retval other This driver does not support this device 298 299 **/ 300 EFI_STATUS 301 EFIAPI 302 SCSIBusDriverBindingStart ( 303 IN EFI_DRIVER_BINDING_PROTOCOL *This, 304 IN EFI_HANDLE Controller, 305 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath 306 ) 307 { 308 UINT64 Lun; 309 UINT8 *TargetId; 310 BOOLEAN ScanOtherPuns; 311 BOOLEAN FromFirstTarget; 312 BOOLEAN ExtScsiSupport; 313 EFI_STATUS Status; 314 EFI_STATUS DevicePathStatus; 315 EFI_STATUS PassThruStatus; 316 SCSI_BUS_DEVICE *ScsiBusDev; 317 SCSI_TARGET_ID ScsiTargetId; 318 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; 319 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiInterface; 320 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiInterface; 321 EFI_SCSI_BUS_PROTOCOL *BusIdentify; 322 323 TargetId = NULL; 324 ScanOtherPuns = TRUE; 325 FromFirstTarget = FALSE; 326 ExtScsiSupport = FALSE; 327 PassThruStatus = EFI_SUCCESS; 328 329 TargetId = &ScsiTargetId.ScsiId.ExtScsi[0]; 330 SetMem (TargetId, TARGET_MAX_BYTES, 0xFF); 331 332 DevicePathStatus = gBS->OpenProtocol ( 333 Controller, 334 &gEfiDevicePathProtocolGuid, 335 (VOID **) &ParentDevicePath, 336 This->DriverBindingHandle, 337 Controller, 338 EFI_OPEN_PROTOCOL_BY_DRIVER 339 ); 340 if (EFI_ERROR (DevicePathStatus) && (DevicePathStatus != EFI_ALREADY_STARTED)) { 341 return DevicePathStatus; 342 } 343 344 // 345 // Report Status Code to indicate SCSI bus starts 346 // 347 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 348 EFI_PROGRESS_CODE, 349 (EFI_IO_BUS_SCSI | EFI_IOB_PC_INIT), 350 ParentDevicePath 351 ); 352 353 // 354 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as 355 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly 356 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead. 357 // 358 Status = gBS->OpenProtocol ( 359 Controller, 360 &gEfiExtScsiPassThruProtocolGuid, 361 (VOID **) &ExtScsiInterface, 362 This->DriverBindingHandle, 363 Controller, 364 EFI_OPEN_PROTOCOL_BY_DRIVER 365 ); 366 // 367 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead. 368 // 369 if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { 370 Status = gBS->OpenProtocol ( 371 Controller, 372 &gEfiScsiPassThruProtocolGuid, 373 (VOID **) &ScsiInterface, 374 This->DriverBindingHandle, 375 Controller, 376 EFI_OPEN_PROTOCOL_BY_DRIVER 377 ); 378 // 379 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time. 380 // 381 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { 382 if (!EFI_ERROR(DevicePathStatus)) { 383 gBS->CloseProtocol ( 384 Controller, 385 &gEfiDevicePathProtocolGuid, 386 This->DriverBindingHandle, 387 Controller 388 ); 389 } 390 return Status; 391 } 392 } else { 393 // 394 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol 395 // with BY_DRIVER if it is also present on the handle. The intent is to prevent 396 // another SCSI Bus Driver to work on the same host handle. 397 // 398 ExtScsiSupport = TRUE; 399 PassThruStatus = gBS->OpenProtocol ( 400 Controller, 401 &gEfiScsiPassThruProtocolGuid, 402 (VOID **) &ScsiInterface, 403 This->DriverBindingHandle, 404 Controller, 405 EFI_OPEN_PROTOCOL_BY_DRIVER 406 ); 407 } 408 409 if (Status != EFI_ALREADY_STARTED) { 410 // 411 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened 412 // on this handle for this time. Then construct Host controller private data. 413 // 414 ScsiBusDev = NULL; 415 ScsiBusDev = AllocateZeroPool(sizeof(SCSI_BUS_DEVICE)); 416 if (ScsiBusDev == NULL) { 417 Status = EFI_OUT_OF_RESOURCES; 418 goto ErrorExit; 419 } 420 ScsiBusDev->Signature = SCSI_BUS_DEVICE_SIGNATURE; 421 ScsiBusDev->ExtScsiSupport = ExtScsiSupport; 422 ScsiBusDev->DevicePath = ParentDevicePath; 423 if (ScsiBusDev->ExtScsiSupport) { 424 ScsiBusDev->ExtScsiInterface = ExtScsiInterface; 425 } else { 426 ScsiBusDev->ScsiInterface = ScsiInterface; 427 } 428 429 // 430 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be 431 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru 432 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol. 433 // 434 Status = gBS->InstallProtocolInterface ( 435 &Controller, 436 &gEfiCallerIdGuid, 437 EFI_NATIVE_INTERFACE, 438 &ScsiBusDev->BusIdentify 439 ); 440 if (EFI_ERROR (Status)) { 441 goto ErrorExit; 442 } 443 } else { 444 // 445 // Go through here means Start() is re-invoked again, nothing special is required to do except 446 // picking up Host controller private information. 447 // 448 Status = gBS->OpenProtocol ( 449 Controller, 450 &gEfiCallerIdGuid, 451 (VOID **) &BusIdentify, 452 This->DriverBindingHandle, 453 Controller, 454 EFI_OPEN_PROTOCOL_GET_PROTOCOL 455 ); 456 457 if (EFI_ERROR (Status)) { 458 return Status; 459 } 460 ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify); 461 } 462 463 // 464 // Report Status Code to indicate detecting devices on bus 465 // 466 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 467 EFI_PROGRESS_CODE, 468 (EFI_IO_BUS_SCSI | EFI_IOB_PC_DETECT), 469 ParentDevicePath 470 ); 471 472 Lun = 0; 473 if (RemainingDevicePath == NULL) { 474 // 475 // If RemainingDevicePath is NULL, 476 // must enumerate all SCSI devices anyway 477 // 478 FromFirstTarget = TRUE; 479 } else if (!IsDevicePathEnd (RemainingDevicePath)) { 480 // 481 // If RemainingDevicePath isn't the End of Device Path Node, 482 // only scan the specified device by RemainingDevicePath 483 // 484 if (ScsiBusDev->ExtScsiSupport) { 485 Status = ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun); 486 } else { 487 Status = ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun); 488 } 489 490 if (EFI_ERROR (Status)) { 491 return Status; 492 } 493 } else { 494 // 495 // If RemainingDevicePath is the End of Device Path Node, 496 // skip enumerate any device and return EFI_SUCESSS 497 // 498 ScanOtherPuns = FALSE; 499 } 500 501 while(ScanOtherPuns) { 502 if (FromFirstTarget) { 503 // 504 // Remaining Device Path is NULL, scan all the possible Puns in the 505 // SCSI Channel. 506 // 507 if (ScsiBusDev->ExtScsiSupport) { 508 Status = ScsiBusDev->ExtScsiInterface->GetNextTargetLun (ScsiBusDev->ExtScsiInterface, &TargetId, &Lun); 509 } else { 510 Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId.ScsiId.Scsi, &Lun); 511 } 512 if (EFI_ERROR (Status)) { 513 // 514 // no legal Pun and Lun found any more 515 // 516 break; 517 } 518 } else { 519 ScanOtherPuns = FALSE; 520 } 521 // 522 // Avoid creating handle for the host adapter. 523 // 524 if (ScsiBusDev->ExtScsiSupport) { 525 if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) { 526 continue; 527 } 528 } else { 529 if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) { 530 continue; 531 } 532 } 533 // 534 // Scan for the scsi device, if it attaches to the scsi bus, 535 // then create handle and install scsi i/o protocol. 536 // 537 Status = ScsiScanCreateDevice (This, Controller, &ScsiTargetId, Lun, ScsiBusDev); 538 } 539 return EFI_SUCCESS; 540 541 ErrorExit: 542 543 if (ScsiBusDev != NULL) { 544 FreePool (ScsiBusDev); 545 } 546 547 if (ExtScsiSupport) { 548 gBS->CloseProtocol ( 549 Controller, 550 &gEfiExtScsiPassThruProtocolGuid, 551 This->DriverBindingHandle, 552 Controller 553 ); 554 if (!EFI_ERROR (PassThruStatus)) { 555 gBS->CloseProtocol ( 556 Controller, 557 &gEfiScsiPassThruProtocolGuid, 558 This->DriverBindingHandle, 559 Controller 560 ); 561 } 562 } else { 563 gBS->CloseProtocol ( 564 Controller, 565 &gEfiScsiPassThruProtocolGuid, 566 This->DriverBindingHandle, 567 Controller 568 ); 569 } 570 return Status; 571 } 572 573 /** 574 Stop this driver on ControllerHandle. 575 576 This service is called by the EFI boot service DisconnectController(). 577 In order to make drivers as small as possible, there are a few calling 578 restrictions for this service. DisconnectController() must follow these 579 calling restrictions. If any other agent wishes to call Stop() it must also 580 follow these calling restrictions. 581 582 @param This Protocol instance pointer. 583 @param ControllerHandle Handle of device to stop driver on 584 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of 585 children is zero stop the entire bus driver. 586 @param ChildHandleBuffer List of Child Handles to Stop. 587 588 @retval EFI_SUCCESS This driver is removed ControllerHandle 589 @retval other This driver was not removed from this device 590 591 **/ 592 EFI_STATUS 593 EFIAPI 594 SCSIBusDriverBindingStop ( 595 IN EFI_DRIVER_BINDING_PROTOCOL *This, 596 IN EFI_HANDLE Controller, 597 IN UINTN NumberOfChildren, 598 IN EFI_HANDLE *ChildHandleBuffer 599 ) 600 { 601 EFI_STATUS Status; 602 BOOLEAN AllChildrenStopped; 603 UINTN Index; 604 EFI_SCSI_IO_PROTOCOL *ScsiIo; 605 SCSI_IO_DEV *ScsiIoDevice; 606 VOID *ScsiPassThru; 607 EFI_SCSI_BUS_PROTOCOL *Scsidentifier; 608 SCSI_BUS_DEVICE *ScsiBusDev; 609 610 if (NumberOfChildren == 0) { 611 // 612 // Get the SCSI_BUS_DEVICE 613 // 614 Status = gBS->OpenProtocol ( 615 Controller, 616 &gEfiCallerIdGuid, 617 (VOID **) &Scsidentifier, 618 This->DriverBindingHandle, 619 Controller, 620 EFI_OPEN_PROTOCOL_GET_PROTOCOL 621 ); 622 623 if (EFI_ERROR (Status)) { 624 return EFI_DEVICE_ERROR; 625 } 626 627 ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier); 628 629 // 630 // Uninstall SCSI Bus Protocol 631 // 632 gBS->UninstallProtocolInterface ( 633 Controller, 634 &gEfiCallerIdGuid, 635 &ScsiBusDev->BusIdentify 636 ); 637 638 // 639 // Close the bus driver 640 // 641 if (ScsiBusDev->ExtScsiSupport) { 642 // 643 // Close ExtPassThru Protocol from this controller handle 644 // 645 gBS->CloseProtocol ( 646 Controller, 647 &gEfiExtScsiPassThruProtocolGuid, 648 This->DriverBindingHandle, 649 Controller 650 ); 651 // 652 // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER. 653 // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle. 654 // So Stop() needs to try to close PassThru if present here. 655 // 656 gBS->CloseProtocol ( 657 Controller, 658 &gEfiScsiPassThruProtocolGuid, 659 This->DriverBindingHandle, 660 Controller 661 ); 662 } else { 663 gBS->CloseProtocol ( 664 Controller, 665 &gEfiScsiPassThruProtocolGuid, 666 This->DriverBindingHandle, 667 Controller 668 ); 669 } 670 671 gBS->CloseProtocol ( 672 Controller, 673 &gEfiDevicePathProtocolGuid, 674 This->DriverBindingHandle, 675 Controller 676 ); 677 FreePool (ScsiBusDev); 678 return EFI_SUCCESS; 679 } 680 681 AllChildrenStopped = TRUE; 682 683 for (Index = 0; Index < NumberOfChildren; Index++) { 684 685 Status = gBS->OpenProtocol ( 686 ChildHandleBuffer[Index], 687 &gEfiScsiIoProtocolGuid, 688 (VOID **) &ScsiIo, 689 This->DriverBindingHandle, 690 Controller, 691 EFI_OPEN_PROTOCOL_GET_PROTOCOL 692 ); 693 if (EFI_ERROR (Status)) { 694 AllChildrenStopped = FALSE; 695 continue; 696 } 697 698 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (ScsiIo); 699 // 700 // Close the child handle 701 // 702 if (ScsiIoDevice->ExtScsiSupport) { 703 Status = gBS->CloseProtocol ( 704 Controller, 705 &gEfiExtScsiPassThruProtocolGuid, 706 This->DriverBindingHandle, 707 ChildHandleBuffer[Index] 708 ); 709 710 } else { 711 Status = gBS->CloseProtocol ( 712 Controller, 713 &gEfiScsiPassThruProtocolGuid, 714 This->DriverBindingHandle, 715 ChildHandleBuffer[Index] 716 ); 717 } 718 719 Status = gBS->UninstallMultipleProtocolInterfaces ( 720 ChildHandleBuffer[Index], 721 &gEfiDevicePathProtocolGuid, 722 ScsiIoDevice->DevicePath, 723 &gEfiScsiIoProtocolGuid, 724 &ScsiIoDevice->ScsiIo, 725 NULL 726 ); 727 if (EFI_ERROR (Status)) { 728 AllChildrenStopped = FALSE; 729 if (ScsiIoDevice->ExtScsiSupport) { 730 gBS->OpenProtocol ( 731 Controller, 732 &gEfiExtScsiPassThruProtocolGuid, 733 &ScsiPassThru, 734 This->DriverBindingHandle, 735 ChildHandleBuffer[Index], 736 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 737 ); 738 } else { 739 gBS->OpenProtocol ( 740 Controller, 741 &gEfiScsiPassThruProtocolGuid, 742 &ScsiPassThru, 743 This->DriverBindingHandle, 744 ChildHandleBuffer[Index], 745 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 746 ); 747 } 748 } else { 749 FreePool (ScsiIoDevice); 750 } 751 } 752 753 if (!AllChildrenStopped) { 754 return EFI_DEVICE_ERROR; 755 } 756 757 return EFI_SUCCESS; 758 } 759 760 761 /** 762 Retrieves the device type information of the SCSI Controller. 763 764 @param This Protocol instance pointer. 765 @param DeviceType A pointer to the device type information retrieved from 766 the SCSI Controller. 767 768 @retval EFI_SUCCESS Retrieves the device type information successfully. 769 @retval EFI_INVALID_PARAMETER The DeviceType is NULL. 770 771 **/ 772 EFI_STATUS 773 EFIAPI 774 ScsiGetDeviceType ( 775 IN EFI_SCSI_IO_PROTOCOL *This, 776 OUT UINT8 *DeviceType 777 ) 778 { 779 SCSI_IO_DEV *ScsiIoDevice; 780 781 if (DeviceType == NULL) { 782 return EFI_INVALID_PARAMETER; 783 } 784 785 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); 786 *DeviceType = ScsiIoDevice->ScsiDeviceType; 787 return EFI_SUCCESS; 788 } 789 790 791 /** 792 Retrieves the device location in the SCSI channel. 793 794 @param This Protocol instance pointer. 795 @param Target A pointer to the Target ID of a SCSI device 796 on the SCSI channel. 797 @param Lun A pointer to the LUN of the SCSI device on 798 the SCSI channel. 799 800 @retval EFI_SUCCESS Retrieves the device location successfully. 801 @retval EFI_INVALID_PARAMETER The Target or Lun is NULL. 802 803 **/ 804 EFI_STATUS 805 EFIAPI 806 ScsiGetDeviceLocation ( 807 IN EFI_SCSI_IO_PROTOCOL *This, 808 IN OUT UINT8 **Target, 809 OUT UINT64 *Lun 810 ) 811 { 812 SCSI_IO_DEV *ScsiIoDevice; 813 814 if (Target == NULL || Lun == NULL) { 815 return EFI_INVALID_PARAMETER; 816 } 817 818 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); 819 820 CopyMem (*Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES); 821 822 *Lun = ScsiIoDevice->Lun; 823 824 return EFI_SUCCESS; 825 } 826 827 /** 828 Resets the SCSI Bus that the SCSI Controller is attached to. 829 830 @param This Protocol instance pointer. 831 832 @retval EFI_SUCCESS The SCSI bus is reset successfully. 833 @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus. 834 @retval EFI_UNSUPPORTED The bus reset operation is not supported by the 835 SCSI Host Controller. 836 @retval EFI_TIMEOUT A timeout occurred while attempting to reset 837 the SCSI bus. 838 **/ 839 EFI_STATUS 840 EFIAPI 841 ScsiResetBus ( 842 IN EFI_SCSI_IO_PROTOCOL *This 843 ) 844 { 845 SCSI_IO_DEV *ScsiIoDevice; 846 847 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); 848 849 // 850 // Report Status Code to indicate reset happens 851 // 852 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 853 EFI_PROGRESS_CODE, 854 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET), 855 ScsiIoDevice->ScsiBusDeviceData->DevicePath 856 ); 857 858 if (ScsiIoDevice->ExtScsiSupport){ 859 return ScsiIoDevice->ExtScsiPassThru->ResetChannel (ScsiIoDevice->ExtScsiPassThru); 860 } else { 861 return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru); 862 } 863 } 864 865 866 /** 867 Resets the SCSI Controller that the device handle specifies. 868 869 @param This Protocol instance pointer. 870 871 @retval EFI_SUCCESS Reset the SCSI controller successfully. 872 @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller. 873 @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation. 874 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the 875 SCSI Controller. 876 **/ 877 EFI_STATUS 878 EFIAPI 879 ScsiResetDevice ( 880 IN EFI_SCSI_IO_PROTOCOL *This 881 ) 882 { 883 SCSI_IO_DEV *ScsiIoDevice; 884 UINT8 Target[TARGET_MAX_BYTES]; 885 886 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); 887 888 // 889 // Report Status Code to indicate reset happens 890 // 891 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 892 EFI_PROGRESS_CODE, 893 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET), 894 ScsiIoDevice->ScsiBusDeviceData->DevicePath 895 ); 896 897 CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES); 898 899 900 if (ScsiIoDevice->ExtScsiSupport) { 901 return ScsiIoDevice->ExtScsiPassThru->ResetTargetLun ( 902 ScsiIoDevice->ExtScsiPassThru, 903 Target, 904 ScsiIoDevice->Lun 905 ); 906 } else { 907 return ScsiIoDevice->ScsiPassThru->ResetTarget ( 908 ScsiIoDevice->ScsiPassThru, 909 ScsiIoDevice->Pun.ScsiId.Scsi, 910 ScsiIoDevice->Lun 911 ); 912 } 913 } 914 915 916 /** 917 Sends a SCSI Request Packet to the SCSI Controller for execution. 918 919 @param This Protocol instance pointer. 920 @param CommandPacket The SCSI request packet to send to the SCSI 921 Controller specified by the device handle. 922 @param Event If the SCSI bus where the SCSI device is attached 923 does not support non-blocking I/O, then Event is 924 ignored, and blocking I/O is performed. 925 If Event is NULL, then blocking I/O is performed. 926 If Event is not NULL and non-blocking I/O is 927 supported, then non-blocking I/O is performed, 928 and Event will be signaled when the SCSI Request 929 Packet completes. 930 931 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host 932 successfully, and TransferLength bytes were 933 transferred to/from DataBuffer.See 934 HostAdapterStatus, TargetStatus, 935 SenseDataLength, and SenseData in that order 936 for additional status information. 937 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, 938 but the entire DataBuffer could not be transferred. 939 The actual number of bytes transferred is returned 940 in TransferLength. See HostAdapterStatus, 941 TargetStatus, SenseDataLength, and SenseData in 942 that order for additional status information. 943 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because 944 there are too many SCSI Command Packets already 945 queued.The caller may retry again later. 946 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send 947 the SCSI Request Packet. See HostAdapterStatus, 948 TargetStatus, SenseDataLength, and SenseData in 949 that order for additional status information. 950 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid. 951 The SCSI Request Packet was not sent, so no 952 additional status information is available. 953 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet 954 is not supported by the SCSI initiator(i.e., SCSI 955 Host Controller). The SCSI Request Packet was not 956 sent, so no additional status information is 957 available. 958 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI 959 Request Packet to execute. See HostAdapterStatus, 960 TargetStatus, SenseDataLength, and SenseData in 961 that order for additional status information. 962 **/ 963 EFI_STATUS 964 EFIAPI 965 ScsiExecuteSCSICommand ( 966 IN EFI_SCSI_IO_PROTOCOL *This, 967 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet, 968 IN EFI_EVENT Event OPTIONAL 969 ) 970 { 971 SCSI_IO_DEV *ScsiIoDevice; 972 EFI_STATUS Status; 973 UINT8 Target[TARGET_MAX_BYTES]; 974 EFI_EVENT PacketEvent; 975 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ExtRequestPacket; 976 SCSI_EVENT_DATA EventData; 977 978 PacketEvent = NULL; 979 980 if (Packet == NULL) { 981 return EFI_INVALID_PARAMETER; 982 } 983 984 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This); 985 CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES); 986 987 if (ScsiIoDevice->ExtScsiSupport) { 988 ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet; 989 990 if (((ScsiIoDevice->ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) { 991 Status = ScsiIoDevice->ExtScsiPassThru->PassThru ( 992 ScsiIoDevice->ExtScsiPassThru, 993 Target, 994 ScsiIoDevice->Lun, 995 ExtRequestPacket, 996 Event 997 ); 998 } else { 999 // 1000 // If there's no event or the SCSI Device doesn't support NON-BLOCKING, 1001 // let the 'Event' parameter for PassThru() be NULL. 1002 // 1003 Status = ScsiIoDevice->ExtScsiPassThru->PassThru ( 1004 ScsiIoDevice->ExtScsiPassThru, 1005 Target, 1006 ScsiIoDevice->Lun, 1007 ExtRequestPacket, 1008 NULL 1009 ); 1010 if ((!EFI_ERROR(Status)) && (Event != NULL)) { 1011 // 1012 // Signal Event to tell caller to pick up the SCSI IO packet if the 1013 // PassThru() succeeds. 1014 // 1015 gBS->SignalEvent (Event); 1016 } 1017 } 1018 } else { 1019 1020 mWorkingBuffer = AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET)); 1021 1022 if (mWorkingBuffer == NULL) { 1023 return EFI_DEVICE_ERROR; 1024 } 1025 1026 // 1027 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET. 1028 // 1029 Status = ScsiioToPassThruPacket(Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer); 1030 if (EFI_ERROR(Status)) { 1031 FreePool(mWorkingBuffer); 1032 return Status; 1033 } 1034 1035 if (((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) { 1036 EventData.Data1 = (VOID*)Packet; 1037 EventData.Data2 = Event; 1038 // 1039 // Create Event 1040 // 1041 Status = gBS->CreateEvent ( 1042 EVT_NOTIFY_SIGNAL, 1043 TPL_NOTIFY, 1044 NotifyFunction, 1045 &EventData, 1046 &PacketEvent 1047 ); 1048 if (EFI_ERROR(Status)) { 1049 FreePool(mWorkingBuffer); 1050 return Status; 1051 } 1052 1053 Status = ScsiIoDevice->ScsiPassThru->PassThru ( 1054 ScsiIoDevice->ScsiPassThru, 1055 ScsiIoDevice->Pun.ScsiId.Scsi, 1056 ScsiIoDevice->Lun, 1057 mWorkingBuffer, 1058 PacketEvent 1059 ); 1060 1061 if (EFI_ERROR(Status)) { 1062 FreePool(mWorkingBuffer); 1063 gBS->CloseEvent(PacketEvent); 1064 return Status; 1065 } 1066 1067 } else { 1068 // 1069 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert 1070 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet. 1071 // 1072 Status = ScsiIoDevice->ScsiPassThru->PassThru ( 1073 ScsiIoDevice->ScsiPassThru, 1074 ScsiIoDevice->Pun.ScsiId.Scsi, 1075 ScsiIoDevice->Lun, 1076 mWorkingBuffer, 1077 NULL 1078 ); 1079 if (EFI_ERROR(Status)) { 1080 FreePool(mWorkingBuffer); 1081 return Status; 1082 } 1083 1084 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer,Packet); 1085 // 1086 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet, 1087 // free mWorkingBuffer. 1088 // 1089 FreePool(mWorkingBuffer); 1090 1091 // 1092 // Signal Event to tell caller to pick up the SCSI IO Packet. 1093 // 1094 if (Event != NULL) { 1095 gBS->SignalEvent (Event); 1096 } 1097 } 1098 } 1099 return Status; 1100 } 1101 1102 1103 /** 1104 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it. 1105 1106 @param This Protocol instance pointer 1107 @param Controller Controller handle 1108 @param TargetId Tartget to be scanned 1109 @param Lun The Lun of the SCSI device on the SCSI channel. 1110 @param ScsiBusDev The pointer of SCSI_BUS_DEVICE 1111 1112 @retval EFI_SUCCESS Successfully to discover the device and attach 1113 ScsiIoProtocol to it. 1114 @retval EFI_OUT_OF_RESOURCES Fail to discover the device. 1115 1116 **/ 1117 EFI_STATUS 1118 EFIAPI 1119 ScsiScanCreateDevice ( 1120 IN EFI_DRIVER_BINDING_PROTOCOL *This, 1121 IN EFI_HANDLE Controller, 1122 IN SCSI_TARGET_ID *TargetId, 1123 IN UINT64 Lun, 1124 IN OUT SCSI_BUS_DEVICE *ScsiBusDev 1125 ) 1126 { 1127 EFI_STATUS Status; 1128 SCSI_IO_DEV *ScsiIoDevice; 1129 EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath; 1130 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 1131 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; 1132 EFI_HANDLE DeviceHandle; 1133 1134 DevicePath = NULL; 1135 RemainingDevicePath = NULL; 1136 ScsiDevicePath = NULL; 1137 ScsiIoDevice = NULL; 1138 1139 // 1140 // Build Device Path 1141 // 1142 if (ScsiBusDev->ExtScsiSupport){ 1143 Status = ScsiBusDev->ExtScsiInterface->BuildDevicePath ( 1144 ScsiBusDev->ExtScsiInterface, 1145 &TargetId->ScsiId.ExtScsi[0], 1146 Lun, 1147 &ScsiDevicePath 1148 ); 1149 } else { 1150 Status = ScsiBusDev->ScsiInterface->BuildDevicePath ( 1151 ScsiBusDev->ScsiInterface, 1152 TargetId->ScsiId.Scsi, 1153 Lun, 1154 &ScsiDevicePath 1155 ); 1156 } 1157 1158 if (EFI_ERROR(Status)) { 1159 return Status; 1160 } 1161 1162 DevicePath = AppendDevicePathNode ( 1163 ScsiBusDev->DevicePath, 1164 ScsiDevicePath 1165 ); 1166 1167 if (DevicePath == NULL) { 1168 Status = EFI_OUT_OF_RESOURCES; 1169 goto ErrorExit; 1170 } 1171 1172 DeviceHandle = NULL; 1173 RemainingDevicePath = DevicePath; 1174 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle); 1175 if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) { 1176 // 1177 // The device has been started, directly return to fast boot. 1178 // 1179 Status = EFI_ALREADY_STARTED; 1180 goto ErrorExit; 1181 } 1182 1183 ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV)); 1184 if (ScsiIoDevice == NULL) { 1185 Status = EFI_OUT_OF_RESOURCES; 1186 goto ErrorExit; 1187 } 1188 1189 ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE; 1190 ScsiIoDevice->ScsiBusDeviceData = ScsiBusDev; 1191 CopyMem(&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES); 1192 ScsiIoDevice->Lun = Lun; 1193 1194 if (ScsiBusDev->ExtScsiSupport) { 1195 ScsiIoDevice->ExtScsiPassThru = ScsiBusDev->ExtScsiInterface; 1196 ScsiIoDevice->ExtScsiSupport = TRUE; 1197 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ExtScsiPassThru->Mode->IoAlign; 1198 1199 } else { 1200 ScsiIoDevice->ScsiPassThru = ScsiBusDev->ScsiInterface; 1201 ScsiIoDevice->ExtScsiSupport = FALSE; 1202 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ScsiPassThru->Mode->IoAlign; 1203 } 1204 1205 ScsiIoDevice->ScsiIo.GetDeviceType = ScsiGetDeviceType; 1206 ScsiIoDevice->ScsiIo.GetDeviceLocation = ScsiGetDeviceLocation; 1207 ScsiIoDevice->ScsiIo.ResetBus = ScsiResetBus; 1208 ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice; 1209 ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand; 1210 1211 // 1212 // Report Status Code here since the new SCSI device will be discovered 1213 // 1214 REPORT_STATUS_CODE_WITH_DEVICE_PATH ( 1215 EFI_PROGRESS_CODE, 1216 (EFI_IO_BUS_SCSI | EFI_IOB_PC_ENABLE), 1217 ScsiBusDev->DevicePath 1218 ); 1219 1220 if (!DiscoverScsiDevice (ScsiIoDevice)) { 1221 Status = EFI_OUT_OF_RESOURCES; 1222 goto ErrorExit; 1223 } 1224 1225 ScsiIoDevice->DevicePath = DevicePath; 1226 1227 Status = gBS->InstallMultipleProtocolInterfaces ( 1228 &ScsiIoDevice->Handle, 1229 &gEfiDevicePathProtocolGuid, 1230 ScsiIoDevice->DevicePath, 1231 &gEfiScsiIoProtocolGuid, 1232 &ScsiIoDevice->ScsiIo, 1233 NULL 1234 ); 1235 if (EFI_ERROR (Status)) { 1236 goto ErrorExit; 1237 } else { 1238 if (ScsiBusDev->ExtScsiSupport) { 1239 gBS->OpenProtocol ( 1240 Controller, 1241 &gEfiExtScsiPassThruProtocolGuid, 1242 (VOID **) &(ScsiBusDev->ExtScsiInterface), 1243 This->DriverBindingHandle, 1244 ScsiIoDevice->Handle, 1245 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 1246 ); 1247 } else { 1248 gBS->OpenProtocol ( 1249 Controller, 1250 &gEfiScsiPassThruProtocolGuid, 1251 (VOID **) &(ScsiBusDev->ScsiInterface), 1252 This->DriverBindingHandle, 1253 ScsiIoDevice->Handle, 1254 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 1255 ); 1256 } 1257 } 1258 return EFI_SUCCESS; 1259 1260 ErrorExit: 1261 1262 // 1263 // The memory space for ScsiDevicePath is allocated in 1264 // ScsiPassThru->BuildDevicePath() function; It is no longer used 1265 // after AppendDevicePathNode,so free the memory it occupies. 1266 // 1267 FreePool (ScsiDevicePath); 1268 1269 if (DevicePath != NULL) { 1270 FreePool (DevicePath); 1271 } 1272 1273 if (ScsiIoDevice != NULL) { 1274 FreePool (ScsiIoDevice); 1275 } 1276 1277 return Status; 1278 } 1279 1280 1281 /** 1282 Discovery SCSI Device 1283 1284 @param ScsiIoDevice The pointer of SCSI_IO_DEV 1285 1286 @retval TRUE Find SCSI Device and verify it. 1287 @retval FALSE Unable to find SCSI Device. 1288 1289 **/ 1290 BOOLEAN 1291 DiscoverScsiDevice ( 1292 IN OUT SCSI_IO_DEV *ScsiIoDevice 1293 ) 1294 { 1295 EFI_STATUS Status; 1296 UINT32 InquiryDataLength; 1297 UINT8 SenseDataLength; 1298 UINT8 HostAdapterStatus; 1299 UINT8 TargetStatus; 1300 EFI_SCSI_INQUIRY_DATA *InquiryData; 1301 UINT8 MaxRetry; 1302 UINT8 Index; 1303 BOOLEAN ScsiDeviceFound; 1304 1305 HostAdapterStatus = 0; 1306 TargetStatus = 0; 1307 1308 InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA)); 1309 if (InquiryData == NULL) { 1310 ScsiDeviceFound = FALSE; 1311 goto Done; 1312 } 1313 1314 // 1315 // Using Inquiry command to scan for the device 1316 // 1317 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA); 1318 SenseDataLength = 0; 1319 ZeroMem (InquiryData, InquiryDataLength); 1320 1321 MaxRetry = 2; 1322 for (Index = 0; Index < MaxRetry; Index++) { 1323 Status = ScsiInquiryCommand ( 1324 &ScsiIoDevice->ScsiIo, 1325 SCSI_BUS_TIMEOUT, 1326 NULL, 1327 &SenseDataLength, 1328 &HostAdapterStatus, 1329 &TargetStatus, 1330 (VOID *) InquiryData, 1331 &InquiryDataLength, 1332 FALSE 1333 ); 1334 if (!EFI_ERROR (Status)) { 1335 break; 1336 } else if ((Status == EFI_BAD_BUFFER_SIZE) || 1337 (Status == EFI_INVALID_PARAMETER) || 1338 (Status == EFI_UNSUPPORTED)) { 1339 ScsiDeviceFound = FALSE; 1340 goto Done; 1341 } 1342 } 1343 1344 if (Index == MaxRetry) { 1345 ScsiDeviceFound = FALSE; 1346 goto Done; 1347 } 1348 1349 // 1350 // Retrieved inquiry data successfully 1351 // 1352 if ((InquiryData->Peripheral_Qualifier != 0) && 1353 (InquiryData->Peripheral_Qualifier != 3)) { 1354 ScsiDeviceFound = FALSE; 1355 goto Done; 1356 } 1357 1358 if (InquiryData->Peripheral_Qualifier == 3) { 1359 if (InquiryData->Peripheral_Type != 0x1f) { 1360 ScsiDeviceFound = FALSE; 1361 goto Done; 1362 } 1363 } 1364 1365 if (0x1e >= InquiryData->Peripheral_Type && InquiryData->Peripheral_Type >= 0xa) { 1366 ScsiDeviceFound = FALSE; 1367 goto Done; 1368 } 1369 1370 // 1371 // valid device type and peripheral qualifier combination. 1372 // 1373 ScsiIoDevice->ScsiDeviceType = InquiryData->Peripheral_Type; 1374 ScsiIoDevice->RemovableDevice = InquiryData->Rmb; 1375 if (InquiryData->Version == 0) { 1376 ScsiIoDevice->ScsiVersion = 0; 1377 } else { 1378 // 1379 // ANSI-approved version 1380 // 1381 ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData->Version & 0x07); 1382 } 1383 1384 ScsiDeviceFound = TRUE; 1385 1386 Done: 1387 FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA)); 1388 1389 return ScsiDeviceFound; 1390 } 1391 1392 1393 /** 1394 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet. 1395 1396 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET 1397 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET 1398 1399 **/ 1400 EFI_STATUS 1401 EFIAPI 1402 ScsiioToPassThruPacket ( 1403 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet, 1404 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket 1405 ) 1406 { 1407 // 1408 //EFI 1.10 doesn't support Bi-Direction Command. 1409 // 1410 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL) { 1411 return EFI_UNSUPPORTED; 1412 } 1413 1414 ZeroMem (CommandPacket, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET)); 1415 1416 CommandPacket->Timeout = Packet->Timeout; 1417 CommandPacket->Cdb = Packet->Cdb; 1418 CommandPacket->CdbLength = Packet->CdbLength; 1419 CommandPacket->DataDirection = Packet->DataDirection; 1420 CommandPacket->HostAdapterStatus = Packet->HostAdapterStatus; 1421 CommandPacket->TargetStatus = Packet->TargetStatus; 1422 CommandPacket->SenseData = Packet->SenseData; 1423 CommandPacket->SenseDataLength = Packet->SenseDataLength; 1424 1425 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) { 1426 CommandPacket->DataBuffer = Packet->InDataBuffer; 1427 CommandPacket->TransferLength = Packet->InTransferLength; 1428 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) { 1429 CommandPacket->DataBuffer = Packet->OutDataBuffer; 1430 CommandPacket->TransferLength = Packet->OutTransferLength; 1431 } 1432 return EFI_SUCCESS; 1433 } 1434 1435 1436 /** 1437 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet. 1438 1439 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET 1440 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET 1441 1442 **/ 1443 EFI_STATUS 1444 EFIAPI 1445 PassThruToScsiioPacket ( 1446 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket, 1447 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet 1448 ) 1449 { 1450 Packet->Timeout = ScsiPacket->Timeout; 1451 Packet->Cdb = ScsiPacket->Cdb; 1452 Packet->CdbLength = ScsiPacket->CdbLength; 1453 Packet->DataDirection = ScsiPacket->DataDirection; 1454 Packet->HostAdapterStatus = ScsiPacket->HostAdapterStatus; 1455 Packet->TargetStatus = ScsiPacket->TargetStatus; 1456 Packet->SenseData = ScsiPacket->SenseData; 1457 Packet->SenseDataLength = ScsiPacket->SenseDataLength; 1458 1459 if (ScsiPacket->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) { 1460 Packet->InDataBuffer = ScsiPacket->DataBuffer; 1461 Packet->InTransferLength = ScsiPacket->TransferLength; 1462 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) { 1463 Packet->OutDataBuffer = ScsiPacket->DataBuffer; 1464 Packet->OutTransferLength = ScsiPacket->TransferLength; 1465 } 1466 1467 return EFI_SUCCESS; 1468 } 1469 1470 /** 1471 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0 1472 SCSI IO Packet. 1473 1474 @param Event The instance of EFI_EVENT. 1475 @param Context The parameter passed in. 1476 1477 **/ 1478 VOID 1479 EFIAPI 1480 NotifyFunction ( 1481 IN EFI_EVENT Event, 1482 IN VOID *Context 1483 ) 1484 { 1485 EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet; 1486 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket; 1487 EFI_EVENT CallerEvent; 1488 SCSI_EVENT_DATA *PassData; 1489 1490 PassData = (SCSI_EVENT_DATA*)Context; 1491 Packet = (EFI_SCSI_IO_SCSI_REQUEST_PACKET *)PassData->Data1; 1492 ScsiPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer; 1493 1494 // 1495 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet. 1496 // 1497 PassThruToScsiioPacket(ScsiPacket, Packet); 1498 1499 // 1500 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet, 1501 // free mWorkingBuffer. 1502 // 1503 gBS->FreePool(mWorkingBuffer); 1504 1505 // 1506 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet. 1507 // 1508 CallerEvent = PassData->Data2; 1509 gBS->CloseEvent(Event); 1510 gBS->SignalEvent(CallerEvent); 1511 } 1512 1513