1 /** @file 2 SCSI disk driver that layers on every SCSI IO protocol in the system. 3 4 Copyright (c) 2006 - 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 16 #include "ScsiDisk.h" 17 18 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = { 19 ScsiDiskDriverBindingSupported, 20 ScsiDiskDriverBindingStart, 21 ScsiDiskDriverBindingStop, 22 0xa, 23 NULL, 24 NULL 25 }; 26 27 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = { 28 EFI_DISK_INFO_SCSI_INTERFACE_GUID, 29 ScsiDiskInfoInquiry, 30 ScsiDiskInfoIdentify, 31 ScsiDiskInfoSenseData, 32 ScsiDiskInfoWhichIde 33 }; 34 35 /** 36 Allocates an aligned buffer for SCSI disk. 37 38 This function allocates an aligned buffer for the SCSI disk to perform 39 SCSI IO operations. The alignment requirement is from SCSI IO interface. 40 41 @param ScsiDiskDevice The SCSI disk involved for the operation. 42 @param BufferSize The request buffer size. 43 44 @return A pointer to the aligned buffer or NULL if the allocation fails. 45 46 **/ 47 VOID * 48 AllocateAlignedBuffer ( 49 IN SCSI_DISK_DEV *ScsiDiskDevice, 50 IN UINTN BufferSize 51 ) 52 { 53 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiDiskDevice->ScsiIo->IoAlign); 54 } 55 56 /** 57 Frees an aligned buffer for SCSI disk. 58 59 This function frees an aligned buffer for the SCSI disk to perform 60 SCSI IO operations. 61 62 @param Buffer The aligned buffer to be freed. 63 @param BufferSize The request buffer size. 64 65 **/ 66 VOID 67 FreeAlignedBuffer ( 68 IN VOID *Buffer, 69 IN UINTN BufferSize 70 ) 71 { 72 if (Buffer != NULL) { 73 FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize)); 74 } 75 } 76 77 /** 78 The user Entry Point for module ScsiDisk. 79 80 The user code starts with this function. 81 82 @param ImageHandle The firmware allocated handle for the EFI image. 83 @param SystemTable A pointer to the EFI System Table. 84 85 @retval EFI_SUCCESS The entry point is executed successfully. 86 @retval other Some error occurs when executing this entry point. 87 88 **/ 89 EFI_STATUS 90 EFIAPI 91 InitializeScsiDisk( 92 IN EFI_HANDLE ImageHandle, 93 IN EFI_SYSTEM_TABLE *SystemTable 94 ) 95 { 96 EFI_STATUS Status; 97 98 // 99 // Install driver model protocol(s). 100 // 101 Status = EfiLibInstallDriverBindingComponentName2 ( 102 ImageHandle, 103 SystemTable, 104 &gScsiDiskDriverBinding, 105 ImageHandle, 106 &gScsiDiskComponentName, 107 &gScsiDiskComponentName2 108 ); 109 ASSERT_EFI_ERROR (Status); 110 111 112 return Status; 113 } 114 115 /** 116 Test to see if this driver supports ControllerHandle. 117 118 This service is called by the EFI boot service ConnectController(). In order 119 to make drivers as small as possible, there are a few calling restrictions for 120 this service. ConnectController() must follow these calling restrictions. 121 If any other agent wishes to call Supported() it must also follow these 122 calling restrictions. 123 124 @param This Protocol instance pointer. 125 @param ControllerHandle Handle of device to test 126 @param RemainingDevicePath Optional parameter use to pick a specific child 127 device to start. 128 129 @retval EFI_SUCCESS This driver supports this device 130 @retval EFI_ALREADY_STARTED This driver is already running on this device 131 @retval other This driver does not support this device 132 133 **/ 134 EFI_STATUS 135 EFIAPI 136 ScsiDiskDriverBindingSupported ( 137 IN EFI_DRIVER_BINDING_PROTOCOL *This, 138 IN EFI_HANDLE Controller, 139 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL 140 ) 141 { 142 EFI_STATUS Status; 143 EFI_SCSI_IO_PROTOCOL *ScsiIo; 144 UINT8 DeviceType; 145 146 Status = gBS->OpenProtocol ( 147 Controller, 148 &gEfiScsiIoProtocolGuid, 149 (VOID **) &ScsiIo, 150 This->DriverBindingHandle, 151 Controller, 152 EFI_OPEN_PROTOCOL_BY_DRIVER 153 ); 154 if (EFI_ERROR (Status)) { 155 return Status; 156 } 157 158 Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType); 159 if (!EFI_ERROR (Status)) { 160 if ((DeviceType == EFI_SCSI_TYPE_DISK) || (DeviceType == EFI_SCSI_TYPE_CDROM)) { 161 Status = EFI_SUCCESS; 162 } else { 163 Status = EFI_UNSUPPORTED; 164 } 165 } 166 167 gBS->CloseProtocol ( 168 Controller, 169 &gEfiScsiIoProtocolGuid, 170 This->DriverBindingHandle, 171 Controller 172 ); 173 return Status; 174 } 175 176 177 /** 178 Start this driver on ControllerHandle. 179 180 This service is called by the EFI boot service ConnectController(). In order 181 to make drivers as small as possible, there are a few calling restrictions for 182 this service. ConnectController() must follow these calling restrictions. If 183 any other agent wishes to call Start() it must also follow these calling 184 restrictions. 185 186 @param This Protocol instance pointer. 187 @param ControllerHandle Handle of device to bind driver to 188 @param RemainingDevicePath Optional parameter use to pick a specific child 189 device to start. 190 191 @retval EFI_SUCCESS This driver is added to ControllerHandle 192 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle 193 @retval other This driver does not support this device 194 195 **/ 196 EFI_STATUS 197 EFIAPI 198 ScsiDiskDriverBindingStart ( 199 IN EFI_DRIVER_BINDING_PROTOCOL *This, 200 IN EFI_HANDLE Controller, 201 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL 202 ) 203 { 204 EFI_STATUS Status; 205 EFI_SCSI_IO_PROTOCOL *ScsiIo; 206 SCSI_DISK_DEV *ScsiDiskDevice; 207 BOOLEAN Temp; 208 UINT8 Index; 209 UINT8 MaxRetry; 210 BOOLEAN NeedRetry; 211 BOOLEAN MustReadCapacity; 212 213 MustReadCapacity = TRUE; 214 215 ScsiDiskDevice = (SCSI_DISK_DEV *) AllocateZeroPool (sizeof (SCSI_DISK_DEV)); 216 if (ScsiDiskDevice == NULL) { 217 return EFI_OUT_OF_RESOURCES; 218 } 219 220 Status = gBS->OpenProtocol ( 221 Controller, 222 &gEfiScsiIoProtocolGuid, 223 (VOID **) &ScsiIo, 224 This->DriverBindingHandle, 225 Controller, 226 EFI_OPEN_PROTOCOL_BY_DRIVER 227 ); 228 if (EFI_ERROR (Status)) { 229 FreePool (ScsiDiskDevice); 230 return Status; 231 } 232 233 ScsiDiskDevice->Signature = SCSI_DISK_DEV_SIGNATURE; 234 ScsiDiskDevice->ScsiIo = ScsiIo; 235 ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3; 236 ScsiDiskDevice->BlkIo.Media = &ScsiDiskDevice->BlkIoMedia; 237 ScsiDiskDevice->BlkIo.Media->IoAlign = ScsiIo->IoAlign; 238 ScsiDiskDevice->BlkIo.Reset = ScsiDiskReset; 239 ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks; 240 ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks; 241 ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks; 242 ScsiDiskDevice->BlkIo2.Media = &ScsiDiskDevice->BlkIoMedia; 243 ScsiDiskDevice->BlkIo2.Reset = ScsiDiskResetEx; 244 ScsiDiskDevice->BlkIo2.ReadBlocksEx = ScsiDiskReadBlocksEx; 245 ScsiDiskDevice->BlkIo2.WriteBlocksEx = ScsiDiskWriteBlocksEx; 246 ScsiDiskDevice->BlkIo2.FlushBlocksEx = ScsiDiskFlushBlocksEx; 247 ScsiDiskDevice->Handle = Controller; 248 InitializeListHead (&ScsiDiskDevice->BlkIo2Queue); 249 250 ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType)); 251 switch (ScsiDiskDevice->DeviceType) { 252 case EFI_SCSI_TYPE_DISK: 253 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200; 254 MustReadCapacity = TRUE; 255 break; 256 257 case EFI_SCSI_TYPE_CDROM: 258 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800; 259 ScsiDiskDevice->BlkIo.Media->ReadOnly = TRUE; 260 MustReadCapacity = FALSE; 261 break; 262 } 263 // 264 // The Sense Data Array's initial size is 6 265 // 266 ScsiDiskDevice->SenseDataNumber = 6; 267 ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *) AllocateZeroPool ( 268 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber 269 ); 270 if (ScsiDiskDevice->SenseData == NULL) { 271 gBS->CloseProtocol ( 272 Controller, 273 &gEfiScsiIoProtocolGuid, 274 This->DriverBindingHandle, 275 Controller 276 ); 277 FreePool (ScsiDiskDevice); 278 return EFI_OUT_OF_RESOURCES; 279 } 280 281 // 282 // Retrieve device information 283 // 284 MaxRetry = 2; 285 for (Index = 0; Index < MaxRetry; Index++) { 286 Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry); 287 if (!EFI_ERROR (Status)) { 288 break; 289 } 290 291 if (!NeedRetry) { 292 FreePool (ScsiDiskDevice->SenseData); 293 gBS->CloseProtocol ( 294 Controller, 295 &gEfiScsiIoProtocolGuid, 296 This->DriverBindingHandle, 297 Controller 298 ); 299 FreePool (ScsiDiskDevice); 300 return EFI_DEVICE_ERROR; 301 } 302 } 303 // 304 // The second parameter "TRUE" means must 305 // retrieve media capacity 306 // 307 Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp); 308 if (!EFI_ERROR (Status)) { 309 // 310 // Determine if Block IO & Block IO2 should be produced on this controller 311 // handle 312 // 313 if (DetermineInstallBlockIo(Controller)) { 314 InitializeInstallDiskInfo(ScsiDiskDevice, Controller); 315 Status = gBS->InstallMultipleProtocolInterfaces ( 316 &Controller, 317 &gEfiBlockIoProtocolGuid, 318 &ScsiDiskDevice->BlkIo, 319 &gEfiBlockIo2ProtocolGuid, 320 &ScsiDiskDevice->BlkIo2, 321 &gEfiDiskInfoProtocolGuid, 322 &ScsiDiskDevice->DiskInfo, 323 NULL 324 ); 325 if (!EFI_ERROR(Status)) { 326 ScsiDiskDevice->ControllerNameTable = NULL; 327 AddUnicodeString2 ( 328 "eng", 329 gScsiDiskComponentName.SupportedLanguages, 330 &ScsiDiskDevice->ControllerNameTable, 331 L"SCSI Disk Device", 332 TRUE 333 ); 334 AddUnicodeString2 ( 335 "en", 336 gScsiDiskComponentName2.SupportedLanguages, 337 &ScsiDiskDevice->ControllerNameTable, 338 L"SCSI Disk Device", 339 FALSE 340 ); 341 return EFI_SUCCESS; 342 } 343 } 344 } 345 346 gBS->FreePool (ScsiDiskDevice->SenseData); 347 gBS->FreePool (ScsiDiskDevice); 348 gBS->CloseProtocol ( 349 Controller, 350 &gEfiScsiIoProtocolGuid, 351 This->DriverBindingHandle, 352 Controller 353 ); 354 return Status; 355 356 } 357 358 359 /** 360 Stop this driver on ControllerHandle. 361 362 This service is called by the EFI boot service DisconnectController(). 363 In order to make drivers as small as possible, there are a few calling 364 restrictions for this service. DisconnectController() must follow these 365 calling restrictions. If any other agent wishes to call Stop() it must 366 also follow these calling restrictions. 367 368 @param This Protocol instance pointer. 369 @param ControllerHandle Handle of device to stop driver on 370 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of 371 children is zero stop the entire bus driver. 372 @param ChildHandleBuffer List of Child Handles to Stop. 373 374 @retval EFI_SUCCESS This driver is removed ControllerHandle 375 @retval other This driver was not removed from this device 376 377 **/ 378 EFI_STATUS 379 EFIAPI 380 ScsiDiskDriverBindingStop ( 381 IN EFI_DRIVER_BINDING_PROTOCOL *This, 382 IN EFI_HANDLE Controller, 383 IN UINTN NumberOfChildren, 384 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL 385 ) 386 { 387 EFI_BLOCK_IO_PROTOCOL *BlkIo; 388 SCSI_DISK_DEV *ScsiDiskDevice; 389 EFI_STATUS Status; 390 391 Status = gBS->OpenProtocol ( 392 Controller, 393 &gEfiBlockIoProtocolGuid, 394 (VOID **) &BlkIo, 395 This->DriverBindingHandle, 396 Controller, 397 EFI_OPEN_PROTOCOL_GET_PROTOCOL 398 ); 399 if (EFI_ERROR (Status)) { 400 return Status; 401 } 402 403 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlkIo); 404 405 // 406 // Wait for the BlockIo2 requests queue to become empty 407 // 408 while (!IsListEmpty (&ScsiDiskDevice->BlkIo2Queue)); 409 410 Status = gBS->UninstallMultipleProtocolInterfaces ( 411 Controller, 412 &gEfiBlockIoProtocolGuid, 413 &ScsiDiskDevice->BlkIo, 414 &gEfiBlockIo2ProtocolGuid, 415 &ScsiDiskDevice->BlkIo2, 416 &gEfiDiskInfoProtocolGuid, 417 &ScsiDiskDevice->DiskInfo, 418 NULL 419 ); 420 if (!EFI_ERROR (Status)) { 421 gBS->CloseProtocol ( 422 Controller, 423 &gEfiScsiIoProtocolGuid, 424 This->DriverBindingHandle, 425 Controller 426 ); 427 428 ReleaseScsiDiskDeviceResources (ScsiDiskDevice); 429 430 return EFI_SUCCESS; 431 } 432 // 433 // errors met 434 // 435 return Status; 436 } 437 438 /** 439 Reset SCSI Disk. 440 441 442 @param This The pointer of EFI_BLOCK_IO_PROTOCOL 443 @param ExtendedVerification The flag about if extend verificate 444 445 @retval EFI_SUCCESS The device was reset. 446 @retval EFI_DEVICE_ERROR The device is not functioning properly and could 447 not be reset. 448 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice(). 449 450 **/ 451 EFI_STATUS 452 EFIAPI 453 ScsiDiskReset ( 454 IN EFI_BLOCK_IO_PROTOCOL *This, 455 IN BOOLEAN ExtendedVerification 456 ) 457 { 458 EFI_TPL OldTpl; 459 SCSI_DISK_DEV *ScsiDiskDevice; 460 EFI_STATUS Status; 461 462 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 463 464 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This); 465 466 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); 467 468 if (EFI_ERROR (Status)) { 469 Status = EFI_DEVICE_ERROR; 470 goto Done; 471 } 472 473 if (!ExtendedVerification) { 474 goto Done; 475 } 476 477 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); 478 479 if (EFI_ERROR (Status)) { 480 Status = EFI_DEVICE_ERROR; 481 goto Done; 482 } 483 484 Done: 485 gBS->RestoreTPL (OldTpl); 486 return Status; 487 } 488 489 /** 490 The function is to Read Block from SCSI Disk. 491 492 @param This The pointer of EFI_BLOCK_IO_PROTOCOL. 493 @param MediaId The Id of Media detected 494 @param Lba The logic block address 495 @param BufferSize The size of Buffer 496 @param Buffer The buffer to fill the read out data 497 498 @retval EFI_SUCCESS Successfully to read out block. 499 @retval EFI_DEVICE_ERROR Fail to detect media. 500 @retval EFI_NO_MEDIA Media is not present. 501 @retval EFI_MEDIA_CHANGED Media has changed. 502 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. 503 @retval EFI_INVALID_PARAMETER Invalid parameter passed in. 504 505 **/ 506 EFI_STATUS 507 EFIAPI 508 ScsiDiskReadBlocks ( 509 IN EFI_BLOCK_IO_PROTOCOL *This, 510 IN UINT32 MediaId, 511 IN EFI_LBA Lba, 512 IN UINTN BufferSize, 513 OUT VOID *Buffer 514 ) 515 { 516 SCSI_DISK_DEV *ScsiDiskDevice; 517 EFI_BLOCK_IO_MEDIA *Media; 518 EFI_STATUS Status; 519 UINTN BlockSize; 520 UINTN NumberOfBlocks; 521 BOOLEAN MediaChange; 522 EFI_TPL OldTpl; 523 524 MediaChange = FALSE; 525 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 526 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This); 527 528 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) { 529 530 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange); 531 if (EFI_ERROR (Status)) { 532 Status = EFI_DEVICE_ERROR; 533 goto Done; 534 } 535 536 if (MediaChange) { 537 gBS->ReinstallProtocolInterface ( 538 ScsiDiskDevice->Handle, 539 &gEfiBlockIoProtocolGuid, 540 &ScsiDiskDevice->BlkIo, 541 &ScsiDiskDevice->BlkIo 542 ); 543 gBS->ReinstallProtocolInterface ( 544 ScsiDiskDevice->Handle, 545 &gEfiBlockIo2ProtocolGuid, 546 &ScsiDiskDevice->BlkIo2, 547 &ScsiDiskDevice->BlkIo2 548 ); 549 Status = EFI_MEDIA_CHANGED; 550 goto Done; 551 } 552 } 553 // 554 // Get the intrinsic block size 555 // 556 Media = ScsiDiskDevice->BlkIo.Media; 557 BlockSize = Media->BlockSize; 558 559 NumberOfBlocks = BufferSize / BlockSize; 560 561 if (!(Media->MediaPresent)) { 562 Status = EFI_NO_MEDIA; 563 goto Done; 564 } 565 566 if (MediaId != Media->MediaId) { 567 Status = EFI_MEDIA_CHANGED; 568 goto Done; 569 } 570 571 if (Buffer == NULL) { 572 Status = EFI_INVALID_PARAMETER; 573 goto Done; 574 } 575 576 if (BufferSize == 0) { 577 Status = EFI_SUCCESS; 578 goto Done; 579 } 580 581 if (BufferSize % BlockSize != 0) { 582 Status = EFI_BAD_BUFFER_SIZE; 583 goto Done; 584 } 585 586 if (Lba > Media->LastBlock) { 587 Status = EFI_INVALID_PARAMETER; 588 goto Done; 589 } 590 591 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) { 592 Status = EFI_INVALID_PARAMETER; 593 goto Done; 594 } 595 596 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { 597 Status = EFI_INVALID_PARAMETER; 598 goto Done; 599 } 600 601 // 602 // If all the parameters are valid, then perform read sectors command 603 // to transfer data from device to host. 604 // 605 Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks); 606 607 Done: 608 gBS->RestoreTPL (OldTpl); 609 return Status; 610 } 611 612 /** 613 The function is to Write Block to SCSI Disk. 614 615 @param This The pointer of EFI_BLOCK_IO_PROTOCOL 616 @param MediaId The Id of Media detected 617 @param Lba The logic block address 618 @param BufferSize The size of Buffer 619 @param Buffer The buffer to fill the read out data 620 621 @retval EFI_SUCCESS Successfully to read out block. 622 @retval EFI_WRITE_PROTECTED The device can not be written to. 623 @retval EFI_DEVICE_ERROR Fail to detect media. 624 @retval EFI_NO_MEDIA Media is not present. 625 @retval EFI_MEDIA_CHNAGED Media has changed. 626 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. 627 @retval EFI_INVALID_PARAMETER Invalid parameter passed in. 628 629 **/ 630 EFI_STATUS 631 EFIAPI 632 ScsiDiskWriteBlocks ( 633 IN EFI_BLOCK_IO_PROTOCOL *This, 634 IN UINT32 MediaId, 635 IN EFI_LBA Lba, 636 IN UINTN BufferSize, 637 IN VOID *Buffer 638 ) 639 { 640 SCSI_DISK_DEV *ScsiDiskDevice; 641 EFI_BLOCK_IO_MEDIA *Media; 642 EFI_STATUS Status; 643 UINTN BlockSize; 644 UINTN NumberOfBlocks; 645 BOOLEAN MediaChange; 646 EFI_TPL OldTpl; 647 648 MediaChange = FALSE; 649 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 650 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This); 651 652 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) { 653 654 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange); 655 if (EFI_ERROR (Status)) { 656 Status = EFI_DEVICE_ERROR; 657 goto Done; 658 } 659 660 if (MediaChange) { 661 gBS->ReinstallProtocolInterface ( 662 ScsiDiskDevice->Handle, 663 &gEfiBlockIoProtocolGuid, 664 &ScsiDiskDevice->BlkIo, 665 &ScsiDiskDevice->BlkIo 666 ); 667 gBS->ReinstallProtocolInterface ( 668 ScsiDiskDevice->Handle, 669 &gEfiBlockIo2ProtocolGuid, 670 &ScsiDiskDevice->BlkIo2, 671 &ScsiDiskDevice->BlkIo2 672 ); 673 Status = EFI_MEDIA_CHANGED; 674 goto Done; 675 } 676 } 677 // 678 // Get the intrinsic block size 679 // 680 Media = ScsiDiskDevice->BlkIo.Media; 681 BlockSize = Media->BlockSize; 682 683 NumberOfBlocks = BufferSize / BlockSize; 684 685 if (!(Media->MediaPresent)) { 686 Status = EFI_NO_MEDIA; 687 goto Done; 688 } 689 690 if (MediaId != Media->MediaId) { 691 Status = EFI_MEDIA_CHANGED; 692 goto Done; 693 } 694 695 if (Media->ReadOnly) { 696 Status = EFI_WRITE_PROTECTED; 697 goto Done; 698 } 699 700 if (BufferSize == 0) { 701 Status = EFI_SUCCESS; 702 goto Done; 703 } 704 705 if (Buffer == NULL) { 706 Status = EFI_INVALID_PARAMETER; 707 goto Done; 708 } 709 710 if (BufferSize % BlockSize != 0) { 711 Status = EFI_BAD_BUFFER_SIZE; 712 goto Done; 713 } 714 715 if (Lba > Media->LastBlock) { 716 Status = EFI_INVALID_PARAMETER; 717 goto Done; 718 } 719 720 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) { 721 Status = EFI_INVALID_PARAMETER; 722 goto Done; 723 } 724 725 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { 726 Status = EFI_INVALID_PARAMETER; 727 goto Done; 728 } 729 // 730 // if all the parameters are valid, then perform read sectors command 731 // to transfer data from device to host. 732 // 733 Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks); 734 735 Done: 736 gBS->RestoreTPL (OldTpl); 737 return Status; 738 } 739 740 /** 741 Flush Block to Disk. 742 743 EFI_SUCCESS is returned directly. 744 745 @param This The pointer of EFI_BLOCK_IO_PROTOCOL 746 747 @retval EFI_SUCCESS All outstanding data was written to the device 748 749 **/ 750 EFI_STATUS 751 EFIAPI 752 ScsiDiskFlushBlocks ( 753 IN EFI_BLOCK_IO_PROTOCOL *This 754 ) 755 { 756 // 757 // return directly 758 // 759 return EFI_SUCCESS; 760 } 761 762 763 /** 764 Reset SCSI Disk. 765 766 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL. 767 @param ExtendedVerification The flag about if extend verificate. 768 769 @retval EFI_SUCCESS The device was reset. 770 @retval EFI_DEVICE_ERROR The device is not functioning properly and could 771 not be reset. 772 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice(). 773 774 **/ 775 EFI_STATUS 776 EFIAPI 777 ScsiDiskResetEx ( 778 IN EFI_BLOCK_IO2_PROTOCOL *This, 779 IN BOOLEAN ExtendedVerification 780 ) 781 { 782 EFI_TPL OldTpl; 783 SCSI_DISK_DEV *ScsiDiskDevice; 784 EFI_STATUS Status; 785 786 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 787 788 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This); 789 790 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); 791 792 if (EFI_ERROR (Status)) { 793 Status = EFI_DEVICE_ERROR; 794 goto Done; 795 } 796 797 if (!ExtendedVerification) { 798 goto Done; 799 } 800 801 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); 802 803 if (EFI_ERROR (Status)) { 804 Status = EFI_DEVICE_ERROR; 805 goto Done; 806 } 807 808 Done: 809 gBS->RestoreTPL (OldTpl); 810 return Status; 811 } 812 813 /** 814 The function is to Read Block from SCSI Disk. 815 816 @param This The pointer of EFI_BLOCK_IO_PROTOCOL. 817 @param MediaId The Id of Media detected. 818 @param Lba The logic block address. 819 @param Token A pointer to the token associated with the transaction. 820 @param BufferSize The size of Buffer. 821 @param Buffer The buffer to fill the read out data. 822 823 @retval EFI_SUCCESS The read request was queued if Token-> Event is 824 not NULL. The data was read correctly from the 825 device if theToken-> Event is NULL. 826 @retval EFI_DEVICE_ERROR The device reported an error while attempting 827 to perform the read operation. 828 @retval EFI_NO_MEDIA There is no media in the device. 829 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. 830 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of 831 the intrinsic block size of the device. 832 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not 833 valid, or the buffer is not on proper 834 alignment. 835 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a 836 lack of resources. 837 838 **/ 839 EFI_STATUS 840 EFIAPI 841 ScsiDiskReadBlocksEx ( 842 IN EFI_BLOCK_IO2_PROTOCOL *This, 843 IN UINT32 MediaId, 844 IN EFI_LBA Lba, 845 IN OUT EFI_BLOCK_IO2_TOKEN *Token, 846 IN UINTN BufferSize, 847 OUT VOID *Buffer 848 ) 849 { 850 SCSI_DISK_DEV *ScsiDiskDevice; 851 EFI_BLOCK_IO_MEDIA *Media; 852 EFI_STATUS Status; 853 UINTN BlockSize; 854 UINTN NumberOfBlocks; 855 BOOLEAN MediaChange; 856 EFI_TPL OldTpl; 857 858 MediaChange = FALSE; 859 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 860 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This); 861 862 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) { 863 864 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange); 865 if (EFI_ERROR (Status)) { 866 Status = EFI_DEVICE_ERROR; 867 goto Done; 868 } 869 870 if (MediaChange) { 871 gBS->ReinstallProtocolInterface ( 872 ScsiDiskDevice->Handle, 873 &gEfiBlockIoProtocolGuid, 874 &ScsiDiskDevice->BlkIo, 875 &ScsiDiskDevice->BlkIo 876 ); 877 gBS->ReinstallProtocolInterface ( 878 ScsiDiskDevice->Handle, 879 &gEfiBlockIo2ProtocolGuid, 880 &ScsiDiskDevice->BlkIo2, 881 &ScsiDiskDevice->BlkIo2 882 ); 883 Status = EFI_MEDIA_CHANGED; 884 goto Done; 885 } 886 } 887 // 888 // Get the intrinsic block size 889 // 890 Media = ScsiDiskDevice->BlkIo2.Media; 891 BlockSize = Media->BlockSize; 892 893 NumberOfBlocks = BufferSize / BlockSize; 894 895 if (!(Media->MediaPresent)) { 896 Status = EFI_NO_MEDIA; 897 goto Done; 898 } 899 900 if (MediaId != Media->MediaId) { 901 Status = EFI_MEDIA_CHANGED; 902 goto Done; 903 } 904 905 if (Buffer == NULL) { 906 Status = EFI_INVALID_PARAMETER; 907 goto Done; 908 } 909 910 if (BufferSize == 0) { 911 if ((Token != NULL) && (Token->Event != NULL)) { 912 Token->TransactionStatus = EFI_SUCCESS; 913 gBS->SignalEvent (Token->Event); 914 } 915 916 Status = EFI_SUCCESS; 917 goto Done; 918 } 919 920 if (BufferSize % BlockSize != 0) { 921 Status = EFI_BAD_BUFFER_SIZE; 922 goto Done; 923 } 924 925 if (Lba > Media->LastBlock) { 926 Status = EFI_INVALID_PARAMETER; 927 goto Done; 928 } 929 930 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) { 931 Status = EFI_INVALID_PARAMETER; 932 goto Done; 933 } 934 935 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { 936 Status = EFI_INVALID_PARAMETER; 937 goto Done; 938 } 939 940 // 941 // If all the parameters are valid, then perform read sectors command 942 // to transfer data from device to host. 943 // 944 if ((Token != NULL) && (Token->Event != NULL)) { 945 Token->TransactionStatus = EFI_SUCCESS; 946 Status = ScsiDiskAsyncReadSectors ( 947 ScsiDiskDevice, 948 Buffer, 949 Lba, 950 NumberOfBlocks, 951 Token 952 ); 953 } else { 954 Status = ScsiDiskReadSectors ( 955 ScsiDiskDevice, 956 Buffer, 957 Lba, 958 NumberOfBlocks 959 ); 960 } 961 962 Done: 963 gBS->RestoreTPL (OldTpl); 964 return Status; 965 } 966 967 /** 968 The function is to Write Block to SCSI Disk. 969 970 @param This The pointer of EFI_BLOCK_IO_PROTOCOL. 971 @param MediaId The Id of Media detected. 972 @param Lba The logic block address. 973 @param Token A pointer to the token associated with the transaction. 974 @param BufferSize The size of Buffer. 975 @param Buffer The buffer to fill the read out data. 976 977 @retval EFI_SUCCESS The data were written correctly to the device. 978 @retval EFI_WRITE_PROTECTED The device cannot be written to. 979 @retval EFI_NO_MEDIA There is no media in the device. 980 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. 981 @retval EFI_DEVICE_ERROR The device reported an error while attempting 982 to perform the write operation. 983 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of 984 the intrinsic block size of the device. 985 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not 986 valid, or the buffer is not on proper 987 alignment. 988 989 **/ 990 EFI_STATUS 991 EFIAPI 992 ScsiDiskWriteBlocksEx ( 993 IN EFI_BLOCK_IO2_PROTOCOL *This, 994 IN UINT32 MediaId, 995 IN EFI_LBA Lba, 996 IN OUT EFI_BLOCK_IO2_TOKEN *Token, 997 IN UINTN BufferSize, 998 IN VOID *Buffer 999 ) 1000 { 1001 SCSI_DISK_DEV *ScsiDiskDevice; 1002 EFI_BLOCK_IO_MEDIA *Media; 1003 EFI_STATUS Status; 1004 UINTN BlockSize; 1005 UINTN NumberOfBlocks; 1006 BOOLEAN MediaChange; 1007 EFI_TPL OldTpl; 1008 1009 MediaChange = FALSE; 1010 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 1011 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This); 1012 1013 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) { 1014 1015 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange); 1016 if (EFI_ERROR (Status)) { 1017 Status = EFI_DEVICE_ERROR; 1018 goto Done; 1019 } 1020 1021 if (MediaChange) { 1022 gBS->ReinstallProtocolInterface ( 1023 ScsiDiskDevice->Handle, 1024 &gEfiBlockIoProtocolGuid, 1025 &ScsiDiskDevice->BlkIo, 1026 &ScsiDiskDevice->BlkIo 1027 ); 1028 gBS->ReinstallProtocolInterface ( 1029 ScsiDiskDevice->Handle, 1030 &gEfiBlockIo2ProtocolGuid, 1031 &ScsiDiskDevice->BlkIo2, 1032 &ScsiDiskDevice->BlkIo2 1033 ); 1034 Status = EFI_MEDIA_CHANGED; 1035 goto Done; 1036 } 1037 } 1038 // 1039 // Get the intrinsic block size 1040 // 1041 Media = ScsiDiskDevice->BlkIo2.Media; 1042 BlockSize = Media->BlockSize; 1043 1044 NumberOfBlocks = BufferSize / BlockSize; 1045 1046 if (!(Media->MediaPresent)) { 1047 Status = EFI_NO_MEDIA; 1048 goto Done; 1049 } 1050 1051 if (MediaId != Media->MediaId) { 1052 Status = EFI_MEDIA_CHANGED; 1053 goto Done; 1054 } 1055 1056 if (Media->ReadOnly) { 1057 Status = EFI_WRITE_PROTECTED; 1058 goto Done; 1059 } 1060 1061 if (BufferSize == 0) { 1062 if ((Token != NULL) && (Token->Event != NULL)) { 1063 Token->TransactionStatus = EFI_SUCCESS; 1064 gBS->SignalEvent (Token->Event); 1065 } 1066 1067 Status = EFI_SUCCESS; 1068 goto Done; 1069 } 1070 1071 if (Buffer == NULL) { 1072 Status = EFI_INVALID_PARAMETER; 1073 goto Done; 1074 } 1075 1076 if (BufferSize % BlockSize != 0) { 1077 Status = EFI_BAD_BUFFER_SIZE; 1078 goto Done; 1079 } 1080 1081 if (Lba > Media->LastBlock) { 1082 Status = EFI_INVALID_PARAMETER; 1083 goto Done; 1084 } 1085 1086 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) { 1087 Status = EFI_INVALID_PARAMETER; 1088 goto Done; 1089 } 1090 1091 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { 1092 Status = EFI_INVALID_PARAMETER; 1093 goto Done; 1094 } 1095 1096 // 1097 // if all the parameters are valid, then perform write sectors command 1098 // to transfer data from device to host. 1099 // 1100 if ((Token != NULL) && (Token->Event != NULL)) { 1101 Token->TransactionStatus = EFI_SUCCESS; 1102 Status = ScsiDiskAsyncWriteSectors ( 1103 ScsiDiskDevice, 1104 Buffer, 1105 Lba, 1106 NumberOfBlocks, 1107 Token 1108 ); 1109 } else { 1110 Status = ScsiDiskWriteSectors ( 1111 ScsiDiskDevice, 1112 Buffer, 1113 Lba, 1114 NumberOfBlocks 1115 ); 1116 } 1117 1118 Done: 1119 gBS->RestoreTPL (OldTpl); 1120 return Status; 1121 } 1122 1123 /** 1124 Flush the Block Device. 1125 1126 @param This Indicates a pointer to the calling context. 1127 @param Token A pointer to the token associated with the transaction. 1128 1129 @retval EFI_SUCCESS All outstanding data was written to the device. 1130 @retval EFI_DEVICE_ERROR The device reported an error while attempting to 1131 write data. 1132 @retval EFI_WRITE_PROTECTED The device cannot be written to. 1133 @retval EFI_NO_MEDIA There is no media in the device. 1134 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. 1135 1136 **/ 1137 EFI_STATUS 1138 EFIAPI 1139 ScsiDiskFlushBlocksEx ( 1140 IN EFI_BLOCK_IO2_PROTOCOL *This, 1141 IN OUT EFI_BLOCK_IO2_TOKEN *Token 1142 ) 1143 { 1144 SCSI_DISK_DEV *ScsiDiskDevice; 1145 EFI_BLOCK_IO_MEDIA *Media; 1146 EFI_STATUS Status; 1147 BOOLEAN MediaChange; 1148 EFI_TPL OldTpl; 1149 1150 MediaChange = FALSE; 1151 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 1152 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This); 1153 1154 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) { 1155 1156 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange); 1157 if (EFI_ERROR (Status)) { 1158 Status = EFI_DEVICE_ERROR; 1159 goto Done; 1160 } 1161 1162 if (MediaChange) { 1163 gBS->ReinstallProtocolInterface ( 1164 ScsiDiskDevice->Handle, 1165 &gEfiBlockIoProtocolGuid, 1166 &ScsiDiskDevice->BlkIo, 1167 &ScsiDiskDevice->BlkIo 1168 ); 1169 gBS->ReinstallProtocolInterface ( 1170 ScsiDiskDevice->Handle, 1171 &gEfiBlockIo2ProtocolGuid, 1172 &ScsiDiskDevice->BlkIo2, 1173 &ScsiDiskDevice->BlkIo2 1174 ); 1175 Status = EFI_MEDIA_CHANGED; 1176 goto Done; 1177 } 1178 } 1179 1180 Media = ScsiDiskDevice->BlkIo2.Media; 1181 1182 if (!(Media->MediaPresent)) { 1183 Status = EFI_NO_MEDIA; 1184 goto Done; 1185 } 1186 1187 if (Media->ReadOnly) { 1188 Status = EFI_WRITE_PROTECTED; 1189 goto Done; 1190 } 1191 1192 // 1193 // Wait for the BlockIo2 requests queue to become empty 1194 // 1195 while (!IsListEmpty (&ScsiDiskDevice->BlkIo2Queue)); 1196 1197 Status = EFI_SUCCESS; 1198 1199 // 1200 // Signal caller event 1201 // 1202 if ((Token != NULL) && (Token->Event != NULL)) { 1203 Token->TransactionStatus = EFI_SUCCESS; 1204 gBS->SignalEvent (Token->Event); 1205 } 1206 1207 Done: 1208 gBS->RestoreTPL (OldTpl); 1209 return Status; 1210 } 1211 1212 1213 /** 1214 Detect Device and read out capacity ,if error occurs, parse the sense key. 1215 1216 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV 1217 @param MustReadCapacity The flag about reading device capacity 1218 @param MediaChange The pointer of flag indicates if media has changed 1219 1220 @retval EFI_DEVICE_ERROR Indicates that error occurs 1221 @retval EFI_SUCCESS Successfully to detect media 1222 1223 **/ 1224 EFI_STATUS 1225 ScsiDiskDetectMedia ( 1226 IN SCSI_DISK_DEV *ScsiDiskDevice, 1227 IN BOOLEAN MustReadCapacity, 1228 OUT BOOLEAN *MediaChange 1229 ) 1230 { 1231 EFI_STATUS Status; 1232 EFI_SCSI_SENSE_DATA *SenseData; 1233 UINTN NumberOfSenseKeys; 1234 BOOLEAN NeedRetry; 1235 BOOLEAN NeedReadCapacity; 1236 UINT8 Retry; 1237 UINT8 MaxRetry; 1238 EFI_BLOCK_IO_MEDIA OldMedia; 1239 UINTN Action; 1240 EFI_EVENT TimeoutEvt; 1241 1242 Status = EFI_SUCCESS; 1243 SenseData = NULL; 1244 NumberOfSenseKeys = 0; 1245 Retry = 0; 1246 MaxRetry = 3; 1247 Action = ACTION_NO_ACTION; 1248 NeedReadCapacity = FALSE; 1249 *MediaChange = FALSE; 1250 TimeoutEvt = NULL; 1251 1252 CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia)); 1253 1254 Status = gBS->CreateEvent ( 1255 EVT_TIMER, 1256 TPL_CALLBACK, 1257 NULL, 1258 NULL, 1259 &TimeoutEvt 1260 ); 1261 if (EFI_ERROR (Status)) { 1262 return Status; 1263 } 1264 1265 Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(120)); 1266 if (EFI_ERROR (Status)) { 1267 goto EXIT; 1268 } 1269 1270 // 1271 // Sending Test_Unit cmd to poll device status. 1272 // If the sense data shows the drive is not ready or reset before, we need poll the device status again. 1273 // We limit the upper boundary to 120 seconds. 1274 // 1275 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) { 1276 Status = ScsiDiskTestUnitReady ( 1277 ScsiDiskDevice, 1278 &NeedRetry, 1279 &SenseData, 1280 &NumberOfSenseKeys 1281 ); 1282 if (!EFI_ERROR (Status)) { 1283 Status = DetectMediaParsingSenseKeys ( 1284 ScsiDiskDevice, 1285 SenseData, 1286 NumberOfSenseKeys, 1287 &Action 1288 ); 1289 if (EFI_ERROR (Status)) { 1290 goto EXIT; 1291 } else if (Action == ACTION_RETRY_COMMAND_LATER) { 1292 continue; 1293 } else { 1294 break; 1295 } 1296 } else { 1297 Retry++; 1298 if (!NeedRetry || (Retry >= MaxRetry)) { 1299 goto EXIT; 1300 } 1301 } 1302 } 1303 1304 if (EFI_ERROR (Status)) { 1305 goto EXIT; 1306 } 1307 1308 // 1309 // ACTION_NO_ACTION: need not read capacity 1310 // other action code: need read capacity 1311 // 1312 if (Action == ACTION_READ_CAPACITY) { 1313 NeedReadCapacity = TRUE; 1314 } 1315 1316 // 1317 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE, 1318 // retrieve capacity via Read Capacity command 1319 // 1320 if (NeedReadCapacity || MustReadCapacity) { 1321 // 1322 // retrieve media information 1323 // 1324 for (Retry = 0; Retry < MaxRetry; Retry++) { 1325 Status = ScsiDiskReadCapacity ( 1326 ScsiDiskDevice, 1327 &NeedRetry, 1328 &SenseData, 1329 &NumberOfSenseKeys 1330 ); 1331 if (!EFI_ERROR (Status)) { 1332 // 1333 // analyze sense key to action 1334 // 1335 Status = DetectMediaParsingSenseKeys ( 1336 ScsiDiskDevice, 1337 SenseData, 1338 NumberOfSenseKeys, 1339 &Action 1340 ); 1341 if (EFI_ERROR (Status)) { 1342 // 1343 // if Status is error, it may indicate crisis error, 1344 // so return without retry. 1345 // 1346 goto EXIT; 1347 } else if (Action == ACTION_RETRY_COMMAND_LATER) { 1348 Retry = 0; 1349 continue; 1350 } else { 1351 break; 1352 } 1353 } else { 1354 Retry++; 1355 if (!NeedRetry || (Retry >= MaxRetry)) { 1356 goto EXIT; 1357 } 1358 } 1359 } 1360 1361 if (EFI_ERROR (Status)) { 1362 goto EXIT; 1363 } 1364 } 1365 1366 if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) { 1367 // 1368 // Media change information got from the device 1369 // 1370 *MediaChange = TRUE; 1371 } 1372 1373 if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) { 1374 *MediaChange = TRUE; 1375 ScsiDiskDevice->BlkIo.Media->MediaId += 1; 1376 } 1377 1378 if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) { 1379 *MediaChange = TRUE; 1380 ScsiDiskDevice->BlkIo.Media->MediaId += 1; 1381 } 1382 1383 if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) { 1384 *MediaChange = TRUE; 1385 ScsiDiskDevice->BlkIo.Media->MediaId += 1; 1386 } 1387 1388 if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) { 1389 if (ScsiDiskDevice->BlkIo.Media->MediaPresent) { 1390 // 1391 // when change from no media to media present, reset the MediaId to 1. 1392 // 1393 ScsiDiskDevice->BlkIo.Media->MediaId = 1; 1394 } else { 1395 // 1396 // when no media, reset the MediaId to zero. 1397 // 1398 ScsiDiskDevice->BlkIo.Media->MediaId = 0; 1399 } 1400 1401 *MediaChange = TRUE; 1402 } 1403 1404 EXIT: 1405 if (TimeoutEvt != NULL) { 1406 gBS->CloseEvent (TimeoutEvt); 1407 } 1408 return Status; 1409 } 1410 1411 1412 /** 1413 Send out Inquiry command to Device. 1414 1415 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV 1416 @param NeedRetry Indicates if needs try again when error happens 1417 1418 @retval EFI_DEVICE_ERROR Indicates that error occurs 1419 @retval EFI_SUCCESS Successfully to detect media 1420 1421 **/ 1422 EFI_STATUS 1423 ScsiDiskInquiryDevice ( 1424 IN OUT SCSI_DISK_DEV *ScsiDiskDevice, 1425 OUT BOOLEAN *NeedRetry 1426 ) 1427 { 1428 UINT32 InquiryDataLength; 1429 UINT8 SenseDataLength; 1430 UINT8 HostAdapterStatus; 1431 UINT8 TargetStatus; 1432 EFI_SCSI_SENSE_DATA *SenseDataArray; 1433 UINTN NumberOfSenseKeys; 1434 EFI_STATUS Status; 1435 UINT8 MaxRetry; 1436 UINT8 Index; 1437 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE *SupportedVpdPages; 1438 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE *BlockLimits; 1439 UINTN PageLength; 1440 1441 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA); 1442 SenseDataLength = 0; 1443 1444 Status = ScsiInquiryCommand ( 1445 ScsiDiskDevice->ScsiIo, 1446 SCSI_DISK_TIMEOUT, 1447 NULL, 1448 &SenseDataLength, 1449 &HostAdapterStatus, 1450 &TargetStatus, 1451 (VOID *) &(ScsiDiskDevice->InquiryData), 1452 &InquiryDataLength, 1453 FALSE 1454 ); 1455 // 1456 // no need to check HostAdapterStatus and TargetStatus 1457 // 1458 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) { 1459 ParseInquiryData (ScsiDiskDevice); 1460 1461 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) { 1462 // 1463 // Check whether the device supports Block Limits VPD page (0xB0) 1464 // 1465 SupportedVpdPages = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE)); 1466 if (SupportedVpdPages == NULL) { 1467 *NeedRetry = FALSE; 1468 return EFI_DEVICE_ERROR; 1469 } 1470 ZeroMem (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE)); 1471 InquiryDataLength = sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE); 1472 SenseDataLength = 0; 1473 Status = ScsiInquiryCommandEx ( 1474 ScsiDiskDevice->ScsiIo, 1475 SCSI_DISK_TIMEOUT, 1476 NULL, 1477 &SenseDataLength, 1478 &HostAdapterStatus, 1479 &TargetStatus, 1480 (VOID *) SupportedVpdPages, 1481 &InquiryDataLength, 1482 TRUE, 1483 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD 1484 ); 1485 if (!EFI_ERROR (Status)) { 1486 PageLength = (SupportedVpdPages->PageLength2 << 8) 1487 | SupportedVpdPages->PageLength1; 1488 for (Index = 0; Index < PageLength; Index++) { 1489 if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) { 1490 break; 1491 } 1492 } 1493 1494 // 1495 // Query the Block Limits VPD page 1496 // 1497 if (Index < PageLength) { 1498 BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE)); 1499 if (BlockLimits == NULL) { 1500 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE)); 1501 *NeedRetry = FALSE; 1502 return EFI_DEVICE_ERROR; 1503 } 1504 ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE)); 1505 InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE); 1506 SenseDataLength = 0; 1507 Status = ScsiInquiryCommandEx ( 1508 ScsiDiskDevice->ScsiIo, 1509 SCSI_DISK_TIMEOUT, 1510 NULL, 1511 &SenseDataLength, 1512 &HostAdapterStatus, 1513 &TargetStatus, 1514 (VOID *) BlockLimits, 1515 &InquiryDataLength, 1516 TRUE, 1517 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD 1518 ); 1519 if (!EFI_ERROR (Status)) { 1520 ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity = 1521 (BlockLimits->OptimalTransferLengthGranularity2 << 8) | 1522 BlockLimits->OptimalTransferLengthGranularity1; 1523 } 1524 1525 FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE)); 1526 } 1527 } 1528 1529 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE)); 1530 } 1531 } 1532 1533 if (!EFI_ERROR (Status)) { 1534 return EFI_SUCCESS; 1535 1536 } else if (Status == EFI_NOT_READY) { 1537 *NeedRetry = TRUE; 1538 return EFI_DEVICE_ERROR; 1539 1540 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) { 1541 *NeedRetry = FALSE; 1542 return EFI_DEVICE_ERROR; 1543 } 1544 // 1545 // go ahead to check HostAdapterStatus and TargetStatus 1546 // (EFI_TIMEOUT, EFI_DEVICE_ERROR) 1547 // 1548 1549 Status = CheckHostAdapterStatus (HostAdapterStatus); 1550 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) { 1551 *NeedRetry = TRUE; 1552 return EFI_DEVICE_ERROR; 1553 } else if (Status == EFI_DEVICE_ERROR) { 1554 // 1555 // reset the scsi channel 1556 // 1557 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); 1558 *NeedRetry = FALSE; 1559 return EFI_DEVICE_ERROR; 1560 } 1561 1562 Status = CheckTargetStatus (TargetStatus); 1563 if (Status == EFI_NOT_READY) { 1564 // 1565 // reset the scsi device 1566 // 1567 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); 1568 *NeedRetry = TRUE; 1569 return EFI_DEVICE_ERROR; 1570 1571 } else if (Status == EFI_DEVICE_ERROR) { 1572 *NeedRetry = FALSE; 1573 return EFI_DEVICE_ERROR; 1574 } 1575 1576 // 1577 // if goes here, meant ScsiInquiryCommand() failed. 1578 // if ScsiDiskRequestSenseKeys() succeeds at last, 1579 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE) 1580 // 1581 MaxRetry = 3; 1582 for (Index = 0; Index < MaxRetry; Index++) { 1583 Status = ScsiDiskRequestSenseKeys ( 1584 ScsiDiskDevice, 1585 NeedRetry, 1586 &SenseDataArray, 1587 &NumberOfSenseKeys, 1588 TRUE 1589 ); 1590 if (!EFI_ERROR (Status)) { 1591 *NeedRetry = TRUE; 1592 return EFI_DEVICE_ERROR; 1593 } 1594 1595 if (!*NeedRetry) { 1596 return EFI_DEVICE_ERROR; 1597 } 1598 } 1599 // 1600 // ScsiDiskRequestSenseKeys() failed after several rounds of retry. 1601 // set *NeedRetry = FALSE to avoid the outside caller try again. 1602 // 1603 *NeedRetry = FALSE; 1604 return EFI_DEVICE_ERROR; 1605 } 1606 1607 /** 1608 To test device. 1609 1610 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense; 1611 When Test Unit Ready command encounters any error caused by host adapter or 1612 target, return error without retrieving Sense Keys. 1613 1614 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV 1615 @param NeedRetry The pointer of flag indicates try again 1616 @param SenseDataArray The pointer of an array of sense data 1617 @param NumberOfSenseKeys The pointer of the number of sense data array 1618 1619 @retval EFI_DEVICE_ERROR Indicates that error occurs 1620 @retval EFI_SUCCESS Successfully to test unit 1621 1622 **/ 1623 EFI_STATUS 1624 ScsiDiskTestUnitReady ( 1625 IN SCSI_DISK_DEV *ScsiDiskDevice, 1626 OUT BOOLEAN *NeedRetry, 1627 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, 1628 OUT UINTN *NumberOfSenseKeys 1629 ) 1630 { 1631 EFI_STATUS Status; 1632 UINT8 SenseDataLength; 1633 UINT8 HostAdapterStatus; 1634 UINT8 TargetStatus; 1635 UINT8 Index; 1636 UINT8 MaxRetry; 1637 1638 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA)); 1639 *NumberOfSenseKeys = 0; 1640 1641 // 1642 // Parameter 3 and 4: do not require sense data, retrieve it when needed. 1643 // 1644 Status = ScsiTestUnitReadyCommand ( 1645 ScsiDiskDevice->ScsiIo, 1646 SCSI_DISK_TIMEOUT, 1647 ScsiDiskDevice->SenseData, 1648 &SenseDataLength, 1649 &HostAdapterStatus, 1650 &TargetStatus 1651 ); 1652 // 1653 // no need to check HostAdapterStatus and TargetStatus 1654 // 1655 if (Status == EFI_NOT_READY) { 1656 *NeedRetry = TRUE; 1657 return EFI_DEVICE_ERROR; 1658 1659 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) { 1660 *NeedRetry = FALSE; 1661 return EFI_DEVICE_ERROR; 1662 } 1663 // 1664 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR) 1665 // 1666 1667 Status = CheckHostAdapterStatus (HostAdapterStatus); 1668 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) { 1669 *NeedRetry = TRUE; 1670 return EFI_DEVICE_ERROR; 1671 1672 } else if (Status == EFI_DEVICE_ERROR) { 1673 // 1674 // reset the scsi channel 1675 // 1676 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); 1677 *NeedRetry = FALSE; 1678 return EFI_DEVICE_ERROR; 1679 } 1680 1681 Status = CheckTargetStatus (TargetStatus); 1682 if (Status == EFI_NOT_READY) { 1683 // 1684 // reset the scsi device 1685 // 1686 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); 1687 *NeedRetry = TRUE; 1688 return EFI_DEVICE_ERROR; 1689 1690 } else if (Status == EFI_DEVICE_ERROR) { 1691 *NeedRetry = FALSE; 1692 return EFI_DEVICE_ERROR; 1693 } 1694 1695 if (SenseDataLength != 0) { 1696 *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA); 1697 *SenseDataArray = ScsiDiskDevice->SenseData; 1698 return EFI_SUCCESS; 1699 } 1700 1701 MaxRetry = 3; 1702 for (Index = 0; Index < MaxRetry; Index++) { 1703 Status = ScsiDiskRequestSenseKeys ( 1704 ScsiDiskDevice, 1705 NeedRetry, 1706 SenseDataArray, 1707 NumberOfSenseKeys, 1708 FALSE 1709 ); 1710 if (!EFI_ERROR (Status)) { 1711 return EFI_SUCCESS; 1712 } 1713 1714 if (!*NeedRetry) { 1715 return EFI_DEVICE_ERROR; 1716 } 1717 } 1718 // 1719 // ScsiDiskRequestSenseKeys() failed after several rounds of retry. 1720 // set *NeedRetry = FALSE to avoid the outside caller try again. 1721 // 1722 *NeedRetry = FALSE; 1723 return EFI_DEVICE_ERROR; 1724 } 1725 1726 /** 1727 Parsing Sense Keys which got from request sense command. 1728 1729 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV 1730 @param SenseData The pointer of EFI_SCSI_SENSE_DATA 1731 @param NumberOfSenseKeys The number of sense key 1732 @param Action The pointer of action which indicates what is need to do next 1733 1734 @retval EFI_DEVICE_ERROR Indicates that error occurs 1735 @retval EFI_SUCCESS Successfully to complete the parsing 1736 1737 **/ 1738 EFI_STATUS 1739 DetectMediaParsingSenseKeys ( 1740 OUT SCSI_DISK_DEV *ScsiDiskDevice, 1741 IN EFI_SCSI_SENSE_DATA *SenseData, 1742 IN UINTN NumberOfSenseKeys, 1743 OUT UINTN *Action 1744 ) 1745 { 1746 BOOLEAN RetryLater; 1747 1748 // 1749 // Default is to read capacity, unless.. 1750 // 1751 *Action = ACTION_READ_CAPACITY; 1752 1753 if (NumberOfSenseKeys == 0) { 1754 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) { 1755 *Action = ACTION_NO_ACTION; 1756 } 1757 return EFI_SUCCESS; 1758 } 1759 1760 if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) { 1761 // 1762 // No Sense Key returned from last submitted command 1763 // 1764 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) { 1765 *Action = ACTION_NO_ACTION; 1766 } 1767 return EFI_SUCCESS; 1768 } 1769 1770 if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) { 1771 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE; 1772 ScsiDiskDevice->BlkIo.Media->LastBlock = 0; 1773 *Action = ACTION_NO_ACTION; 1774 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n")); 1775 return EFI_SUCCESS; 1776 } 1777 1778 if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) { 1779 ScsiDiskDevice->BlkIo.Media->MediaId++; 1780 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n")); 1781 return EFI_SUCCESS; 1782 } 1783 1784 if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) { 1785 *Action = ACTION_RETRY_COMMAND_LATER; 1786 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n")); 1787 return EFI_SUCCESS; 1788 } 1789 1790 if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) { 1791 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n")); 1792 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO; 1793 return EFI_DEVICE_ERROR; 1794 } 1795 1796 if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) { 1797 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n")); 1798 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO; 1799 return EFI_DEVICE_ERROR; 1800 } 1801 1802 if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) { 1803 if (RetryLater) { 1804 *Action = ACTION_RETRY_COMMAND_LATER; 1805 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n")); 1806 return EFI_SUCCESS; 1807 } 1808 *Action = ACTION_NO_ACTION; 1809 return EFI_DEVICE_ERROR; 1810 } 1811 1812 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO; 1813 DEBUG ((EFI_D_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code)); 1814 return EFI_SUCCESS; 1815 } 1816 1817 1818 /** 1819 Send read capacity command to device and get the device parameter. 1820 1821 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV 1822 @param NeedRetry The pointer of flag indicates if need a retry 1823 @param SenseDataArray The pointer of an array of sense data 1824 @param NumberOfSenseKeys The number of sense key 1825 1826 @retval EFI_DEVICE_ERROR Indicates that error occurs 1827 @retval EFI_SUCCESS Successfully to read capacity or sense data is received. 1828 1829 **/ 1830 EFI_STATUS 1831 ScsiDiskReadCapacity ( 1832 IN OUT SCSI_DISK_DEV *ScsiDiskDevice, 1833 OUT BOOLEAN *NeedRetry, 1834 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, 1835 OUT UINTN *NumberOfSenseKeys 1836 ) 1837 { 1838 UINT8 HostAdapterStatus; 1839 UINT8 TargetStatus; 1840 EFI_STATUS CommandStatus; 1841 EFI_STATUS Status; 1842 UINT8 Index; 1843 UINT8 MaxRetry; 1844 UINT8 SenseDataLength; 1845 UINT32 DataLength10; 1846 UINT32 DataLength16; 1847 EFI_SCSI_DISK_CAPACITY_DATA *CapacityData10; 1848 EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16; 1849 1850 CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA)); 1851 if (CapacityData10 == NULL) { 1852 *NeedRetry = FALSE; 1853 return EFI_DEVICE_ERROR; 1854 } 1855 CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16)); 1856 if (CapacityData16 == NULL) { 1857 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA)); 1858 *NeedRetry = FALSE; 1859 return EFI_DEVICE_ERROR; 1860 } 1861 1862 SenseDataLength = 0; 1863 DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA); 1864 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16); 1865 ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA)); 1866 ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16)); 1867 1868 *NumberOfSenseKeys = 0; 1869 *NeedRetry = FALSE; 1870 1871 // 1872 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh, 1873 // 16 byte command should be used to access large hard disk >2TB 1874 // 1875 CommandStatus = ScsiReadCapacityCommand ( 1876 ScsiDiskDevice->ScsiIo, 1877 SCSI_DISK_TIMEOUT, 1878 NULL, 1879 &SenseDataLength, 1880 &HostAdapterStatus, 1881 &TargetStatus, 1882 (VOID *) CapacityData10, 1883 &DataLength10, 1884 FALSE 1885 ); 1886 1887 ScsiDiskDevice->Cdb16Byte = FALSE; 1888 if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) && 1889 (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff)) { 1890 // 1891 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB 1892 // 1893 ScsiDiskDevice->Cdb16Byte = TRUE; 1894 // 1895 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock 1896 // and LowestAlignedLba 1897 // 1898 CommandStatus = ScsiReadCapacity16Command ( 1899 ScsiDiskDevice->ScsiIo, 1900 SCSI_DISK_TIMEOUT, 1901 NULL, 1902 &SenseDataLength, 1903 &HostAdapterStatus, 1904 &TargetStatus, 1905 (VOID *) CapacityData16, 1906 &DataLength16, 1907 FALSE 1908 ); 1909 } 1910 1911 // 1912 // no need to check HostAdapterStatus and TargetStatus 1913 // 1914 if (CommandStatus == EFI_SUCCESS) { 1915 GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16); 1916 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA)); 1917 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16)); 1918 return EFI_SUCCESS; 1919 } 1920 1921 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA)); 1922 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16)); 1923 1924 if (CommandStatus == EFI_NOT_READY) { 1925 *NeedRetry = TRUE; 1926 return EFI_DEVICE_ERROR; 1927 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) { 1928 *NeedRetry = FALSE; 1929 return EFI_DEVICE_ERROR; 1930 } 1931 1932 // 1933 // go ahead to check HostAdapterStatus and TargetStatus 1934 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL) 1935 // 1936 1937 Status = CheckHostAdapterStatus (HostAdapterStatus); 1938 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) { 1939 *NeedRetry = TRUE; 1940 return EFI_DEVICE_ERROR; 1941 1942 } else if (Status == EFI_DEVICE_ERROR) { 1943 // 1944 // reset the scsi channel 1945 // 1946 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); 1947 *NeedRetry = FALSE; 1948 return EFI_DEVICE_ERROR; 1949 } 1950 1951 Status = CheckTargetStatus (TargetStatus); 1952 if (Status == EFI_NOT_READY) { 1953 // 1954 // reset the scsi device 1955 // 1956 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); 1957 *NeedRetry = TRUE; 1958 return EFI_DEVICE_ERROR; 1959 1960 } else if (Status == EFI_DEVICE_ERROR) { 1961 *NeedRetry = FALSE; 1962 return EFI_DEVICE_ERROR; 1963 } 1964 1965 // 1966 // if goes here, meant ScsiReadCapacityCommand() failed. 1967 // if ScsiDiskRequestSenseKeys() succeeds at last, 1968 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE) 1969 // 1970 MaxRetry = 3; 1971 for (Index = 0; Index < MaxRetry; Index++) { 1972 1973 Status = ScsiDiskRequestSenseKeys ( 1974 ScsiDiskDevice, 1975 NeedRetry, 1976 SenseDataArray, 1977 NumberOfSenseKeys, 1978 TRUE 1979 ); 1980 if (!EFI_ERROR (Status)) { 1981 return EFI_SUCCESS; 1982 } 1983 1984 if (!*NeedRetry) { 1985 return EFI_DEVICE_ERROR; 1986 } 1987 } 1988 // 1989 // ScsiDiskRequestSenseKeys() failed after several rounds of retry. 1990 // set *NeedRetry = FALSE to avoid the outside caller try again. 1991 // 1992 *NeedRetry = FALSE; 1993 return EFI_DEVICE_ERROR; 1994 } 1995 1996 /** 1997 Check the HostAdapter status and re-interpret it in EFI_STATUS. 1998 1999 @param HostAdapterStatus Host Adapter status 2000 2001 @retval EFI_SUCCESS Host adapter is OK. 2002 @retval EFI_TIMEOUT Timeout. 2003 @retval EFI_NOT_READY Adapter NOT ready. 2004 @retval EFI_DEVICE_ERROR Adapter device error. 2005 2006 **/ 2007 EFI_STATUS 2008 CheckHostAdapterStatus ( 2009 IN UINT8 HostAdapterStatus 2010 ) 2011 { 2012 switch (HostAdapterStatus) { 2013 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK: 2014 return EFI_SUCCESS; 2015 2016 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT: 2017 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT: 2018 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND: 2019 return EFI_TIMEOUT; 2020 2021 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT: 2022 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR: 2023 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED: 2024 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN: 2025 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET: 2026 return EFI_NOT_READY; 2027 2028 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE: 2029 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR: 2030 return EFI_DEVICE_ERROR; 2031 2032 default: 2033 return EFI_SUCCESS; 2034 } 2035 } 2036 2037 2038 /** 2039 Check the target status and re-interpret it in EFI_STATUS. 2040 2041 @param TargetStatus Target status 2042 2043 @retval EFI_NOT_READY Device is NOT ready. 2044 @retval EFI_DEVICE_ERROR 2045 @retval EFI_SUCCESS 2046 2047 **/ 2048 EFI_STATUS 2049 CheckTargetStatus ( 2050 IN UINT8 TargetStatus 2051 ) 2052 { 2053 switch (TargetStatus) { 2054 case EFI_EXT_SCSI_STATUS_TARGET_GOOD: 2055 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION: 2056 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET: 2057 return EFI_SUCCESS; 2058 2059 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE: 2060 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET: 2061 case EFI_EXT_SCSI_STATUS_TARGET_BUSY: 2062 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL: 2063 return EFI_NOT_READY; 2064 2065 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT: 2066 return EFI_DEVICE_ERROR; 2067 2068 default: 2069 return EFI_SUCCESS; 2070 } 2071 } 2072 2073 2074 /** 2075 Retrieve all sense keys from the device. 2076 2077 When encountering error during the process, if retrieve sense keys before 2078 error encountered, it returns the sense keys with return status set to EFI_SUCCESS, 2079 and NeedRetry set to FALSE; otherwize, return the proper return status. 2080 2081 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV 2082 @param NeedRetry The pointer of flag indicates if need a retry 2083 @param SenseDataArray The pointer of an array of sense data 2084 @param NumberOfSenseKeys The number of sense key 2085 @param AskResetIfError The flag indicates if need reset when error occurs 2086 2087 @retval EFI_DEVICE_ERROR Indicates that error occurs 2088 @retval EFI_SUCCESS Successfully to request sense key 2089 2090 **/ 2091 EFI_STATUS 2092 ScsiDiskRequestSenseKeys ( 2093 IN OUT SCSI_DISK_DEV *ScsiDiskDevice, 2094 OUT BOOLEAN *NeedRetry, 2095 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, 2096 OUT UINTN *NumberOfSenseKeys, 2097 IN BOOLEAN AskResetIfError 2098 ) 2099 { 2100 EFI_SCSI_SENSE_DATA *PtrSenseData; 2101 UINT8 SenseDataLength; 2102 BOOLEAN SenseReq; 2103 EFI_STATUS Status; 2104 EFI_STATUS FallStatus; 2105 UINT8 HostAdapterStatus; 2106 UINT8 TargetStatus; 2107 2108 FallStatus = EFI_SUCCESS; 2109 SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA); 2110 2111 ZeroMem ( 2112 ScsiDiskDevice->SenseData, 2113 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber) 2114 ); 2115 2116 *NumberOfSenseKeys = 0; 2117 *SenseDataArray = ScsiDiskDevice->SenseData; 2118 Status = EFI_SUCCESS; 2119 PtrSenseData = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA)); 2120 if (PtrSenseData == NULL) { 2121 return EFI_DEVICE_ERROR; 2122 } 2123 2124 for (SenseReq = TRUE; SenseReq;) { 2125 ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA)); 2126 Status = ScsiRequestSenseCommand ( 2127 ScsiDiskDevice->ScsiIo, 2128 SCSI_DISK_TIMEOUT, 2129 PtrSenseData, 2130 &SenseDataLength, 2131 &HostAdapterStatus, 2132 &TargetStatus 2133 ); 2134 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) { 2135 FallStatus = EFI_SUCCESS; 2136 2137 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) { 2138 *NeedRetry = TRUE; 2139 FallStatus = EFI_DEVICE_ERROR; 2140 2141 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) { 2142 *NeedRetry = FALSE; 2143 FallStatus = EFI_DEVICE_ERROR; 2144 2145 } else if (Status == EFI_DEVICE_ERROR) { 2146 if (AskResetIfError) { 2147 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); 2148 } 2149 2150 FallStatus = EFI_DEVICE_ERROR; 2151 } 2152 2153 if (EFI_ERROR (FallStatus)) { 2154 if (*NumberOfSenseKeys != 0) { 2155 *NeedRetry = FALSE; 2156 Status = EFI_SUCCESS; 2157 goto EXIT; 2158 } else { 2159 Status = EFI_DEVICE_ERROR; 2160 goto EXIT; 2161 } 2162 } 2163 2164 CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength); 2165 (*NumberOfSenseKeys) += 1; 2166 2167 // 2168 // no more sense key or number of sense keys exceeds predefined, 2169 // skip the loop. 2170 // 2171 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) || 2172 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) { 2173 SenseReq = FALSE; 2174 } 2175 } 2176 2177 EXIT: 2178 FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA)); 2179 return Status; 2180 } 2181 2182 2183 /** 2184 Get information from media read capacity command. 2185 2186 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV 2187 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA 2188 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16 2189 2190 **/ 2191 VOID 2192 GetMediaInfo ( 2193 IN OUT SCSI_DISK_DEV *ScsiDiskDevice, 2194 IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10, 2195 IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16 2196 ) 2197 { 2198 UINT8 *Ptr; 2199 2200 if (!ScsiDiskDevice->Cdb16Byte) { 2201 ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity10->LastLba3 << 24) | 2202 (Capacity10->LastLba2 << 16) | 2203 (Capacity10->LastLba1 << 8) | 2204 Capacity10->LastLba0; 2205 2206 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) | 2207 (Capacity10->BlockSize2 << 16) | 2208 (Capacity10->BlockSize1 << 8) | 2209 Capacity10->BlockSize0; 2210 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0; 2211 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 0; 2212 } else { 2213 Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock; 2214 *Ptr++ = Capacity16->LastLba0; 2215 *Ptr++ = Capacity16->LastLba1; 2216 *Ptr++ = Capacity16->LastLba2; 2217 *Ptr++ = Capacity16->LastLba3; 2218 *Ptr++ = Capacity16->LastLba4; 2219 *Ptr++ = Capacity16->LastLba5; 2220 *Ptr++ = Capacity16->LastLba6; 2221 *Ptr = Capacity16->LastLba7; 2222 2223 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) | 2224 (Capacity16->BlockSize2 << 16) | 2225 (Capacity16->BlockSize1 << 8) | 2226 Capacity16->BlockSize0; 2227 2228 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) | 2229 Capacity16->LowestAlignLogic1; 2230 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = (1 << Capacity16->LogicPerPhysical); 2231 } 2232 2233 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE; 2234 } 2235 2236 /** 2237 Parse Inquiry data. 2238 2239 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV 2240 2241 **/ 2242 VOID 2243 ParseInquiryData ( 2244 IN OUT SCSI_DISK_DEV *ScsiDiskDevice 2245 ) 2246 { 2247 ScsiDiskDevice->FixedDevice = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1); 2248 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice); 2249 } 2250 2251 /** 2252 Read sector from SCSI Disk. 2253 2254 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV 2255 @param Buffer The buffer to fill in the read out data 2256 @param Lba Logic block address 2257 @param NumberOfBlocks The number of blocks to read 2258 2259 @retval EFI_DEVICE_ERROR Indicates a device error. 2260 @retval EFI_SUCCESS Operation is successful. 2261 2262 **/ 2263 EFI_STATUS 2264 ScsiDiskReadSectors ( 2265 IN SCSI_DISK_DEV *ScsiDiskDevice, 2266 OUT VOID *Buffer, 2267 IN EFI_LBA Lba, 2268 IN UINTN NumberOfBlocks 2269 ) 2270 { 2271 UINTN BlocksRemaining; 2272 UINT8 *PtrBuffer; 2273 UINT32 BlockSize; 2274 UINT32 ByteCount; 2275 UINT32 MaxBlock; 2276 UINT32 SectorCount; 2277 UINT32 NextSectorCount; 2278 UINT64 Timeout; 2279 EFI_STATUS Status; 2280 UINT8 Index; 2281 UINT8 MaxRetry; 2282 BOOLEAN NeedRetry; 2283 2284 Status = EFI_SUCCESS; 2285 2286 BlocksRemaining = NumberOfBlocks; 2287 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize; 2288 2289 // 2290 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command 2291 // 2292 if (!ScsiDiskDevice->Cdb16Byte) { 2293 MaxBlock = 0xFFFF; 2294 } else { 2295 MaxBlock = 0xFFFFFFFF; 2296 } 2297 2298 PtrBuffer = Buffer; 2299 2300 while (BlocksRemaining > 0) { 2301 2302 if (BlocksRemaining <= MaxBlock) { 2303 if (!ScsiDiskDevice->Cdb16Byte) { 2304 SectorCount = (UINT16) BlocksRemaining; 2305 } else { 2306 SectorCount = (UINT32) BlocksRemaining; 2307 } 2308 } else { 2309 SectorCount = MaxBlock; 2310 } 2311 2312 ByteCount = SectorCount * BlockSize; 2313 // 2314 // |------------------------|-----------------|------------------|-----------------| 2315 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate | 2316 // |------------------------|-----------------|------------------|-----------------| 2317 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec | 2318 // |------------------------|-----------------|------------------|-----------------| 2319 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec | 2320 // |------------------------|-----------------|------------------|-----------------| 2321 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec | 2322 // |------------------------|-----------------|------------------|-----------------| 2323 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec | 2324 // |------------------------|-----------------|------------------|-----------------| 2325 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec | 2326 // |------------------------|-----------------|------------------|-----------------| 2327 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec | 2328 // |------------------------|-----------------|------------------|-----------------| 2329 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec | 2330 // |------------------------|-----------------|------------------|-----------------| 2331 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec | 2332 // |------------------------|-----------------|------------------|-----------------| 2333 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec | 2334 // |------------------------|-----------------|------------------|-----------------| 2335 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec | 2336 // |------------------------|-----------------|------------------|-----------------| 2337 // 2338 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use 2339 // the lowest transfer rate to calculate the possible maximum timeout value for each operation. 2340 // From the above table, we could know 2.1Mbytes per second is lowest one. 2341 // The timout value is rounded up to nearest integar and here an additional 30s is added 2342 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond 2343 // commands in the Standby/Idle mode. 2344 // 2345 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31); 2346 2347 MaxRetry = 2; 2348 for (Index = 0; Index < MaxRetry; Index++) { 2349 if (!ScsiDiskDevice->Cdb16Byte) { 2350 Status = ScsiDiskRead10 ( 2351 ScsiDiskDevice, 2352 &NeedRetry, 2353 Timeout, 2354 PtrBuffer, 2355 &ByteCount, 2356 (UINT32) Lba, 2357 SectorCount 2358 ); 2359 } else { 2360 Status = ScsiDiskRead16 ( 2361 ScsiDiskDevice, 2362 &NeedRetry, 2363 Timeout, 2364 PtrBuffer, 2365 &ByteCount, 2366 Lba, 2367 SectorCount 2368 ); 2369 } 2370 if (!EFI_ERROR (Status)) { 2371 break; 2372 } 2373 2374 if (!NeedRetry) { 2375 return EFI_DEVICE_ERROR; 2376 } 2377 2378 // 2379 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has 2380 // lowered ByteCount on output, we must make sure that we lower 2381 // SectorCount accordingly. SectorCount will be encoded in the CDB, and 2382 // it is invalid to request more sectors in the CDB than the entire 2383 // transfer (ie. ByteCount) can carry. 2384 // 2385 // In addition, ByteCount is only expected to go down, or stay unchaged. 2386 // Therefore we don't need to update Timeout: the original timeout should 2387 // accommodate shorter transfers too. 2388 // 2389 NextSectorCount = ByteCount / BlockSize; 2390 if (NextSectorCount < SectorCount) { 2391 SectorCount = NextSectorCount; 2392 // 2393 // Account for any rounding down. 2394 // 2395 ByteCount = SectorCount * BlockSize; 2396 } 2397 } 2398 2399 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) { 2400 return EFI_DEVICE_ERROR; 2401 } 2402 2403 // 2404 // actual transferred sectors 2405 // 2406 SectorCount = ByteCount / BlockSize; 2407 2408 Lba += SectorCount; 2409 PtrBuffer = PtrBuffer + SectorCount * BlockSize; 2410 BlocksRemaining -= SectorCount; 2411 } 2412 2413 return EFI_SUCCESS; 2414 } 2415 2416 /** 2417 Write sector to SCSI Disk. 2418 2419 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV 2420 @param Buffer The buffer of data to be written into SCSI Disk 2421 @param Lba Logic block address 2422 @param NumberOfBlocks The number of blocks to read 2423 2424 @retval EFI_DEVICE_ERROR Indicates a device error. 2425 @retval EFI_SUCCESS Operation is successful. 2426 2427 **/ 2428 EFI_STATUS 2429 ScsiDiskWriteSectors ( 2430 IN SCSI_DISK_DEV *ScsiDiskDevice, 2431 IN VOID *Buffer, 2432 IN EFI_LBA Lba, 2433 IN UINTN NumberOfBlocks 2434 ) 2435 { 2436 UINTN BlocksRemaining; 2437 UINT8 *PtrBuffer; 2438 UINT32 BlockSize; 2439 UINT32 ByteCount; 2440 UINT32 MaxBlock; 2441 UINT32 SectorCount; 2442 UINT32 NextSectorCount; 2443 UINT64 Timeout; 2444 EFI_STATUS Status; 2445 UINT8 Index; 2446 UINT8 MaxRetry; 2447 BOOLEAN NeedRetry; 2448 2449 Status = EFI_SUCCESS; 2450 2451 BlocksRemaining = NumberOfBlocks; 2452 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize; 2453 2454 // 2455 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command 2456 // 2457 if (!ScsiDiskDevice->Cdb16Byte) { 2458 MaxBlock = 0xFFFF; 2459 } else { 2460 MaxBlock = 0xFFFFFFFF; 2461 } 2462 2463 PtrBuffer = Buffer; 2464 2465 while (BlocksRemaining > 0) { 2466 2467 if (BlocksRemaining <= MaxBlock) { 2468 if (!ScsiDiskDevice->Cdb16Byte) { 2469 SectorCount = (UINT16) BlocksRemaining; 2470 } else { 2471 SectorCount = (UINT32) BlocksRemaining; 2472 } 2473 } else { 2474 SectorCount = MaxBlock; 2475 } 2476 2477 ByteCount = SectorCount * BlockSize; 2478 // 2479 // |------------------------|-----------------|------------------|-----------------| 2480 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate | 2481 // |------------------------|-----------------|------------------|-----------------| 2482 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec | 2483 // |------------------------|-----------------|------------------|-----------------| 2484 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec | 2485 // |------------------------|-----------------|------------------|-----------------| 2486 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec | 2487 // |------------------------|-----------------|------------------|-----------------| 2488 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec | 2489 // |------------------------|-----------------|------------------|-----------------| 2490 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec | 2491 // |------------------------|-----------------|------------------|-----------------| 2492 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec | 2493 // |------------------------|-----------------|------------------|-----------------| 2494 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec | 2495 // |------------------------|-----------------|------------------|-----------------| 2496 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec | 2497 // |------------------------|-----------------|------------------|-----------------| 2498 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec | 2499 // |------------------------|-----------------|------------------|-----------------| 2500 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec | 2501 // |------------------------|-----------------|------------------|-----------------| 2502 // 2503 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use 2504 // the lowest transfer rate to calculate the possible maximum timeout value for each operation. 2505 // From the above table, we could know 2.1Mbytes per second is lowest one. 2506 // The timout value is rounded up to nearest integar and here an additional 30s is added 2507 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond 2508 // commands in the Standby/Idle mode. 2509 // 2510 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31); 2511 MaxRetry = 2; 2512 for (Index = 0; Index < MaxRetry; Index++) { 2513 if (!ScsiDiskDevice->Cdb16Byte) { 2514 Status = ScsiDiskWrite10 ( 2515 ScsiDiskDevice, 2516 &NeedRetry, 2517 Timeout, 2518 PtrBuffer, 2519 &ByteCount, 2520 (UINT32) Lba, 2521 SectorCount 2522 ); 2523 } else { 2524 Status = ScsiDiskWrite16 ( 2525 ScsiDiskDevice, 2526 &NeedRetry, 2527 Timeout, 2528 PtrBuffer, 2529 &ByteCount, 2530 Lba, 2531 SectorCount 2532 ); 2533 } 2534 if (!EFI_ERROR (Status)) { 2535 break; 2536 } 2537 2538 if (!NeedRetry) { 2539 return EFI_DEVICE_ERROR; 2540 } 2541 2542 // 2543 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16() 2544 // has lowered ByteCount on output, we must make sure that we lower 2545 // SectorCount accordingly. SectorCount will be encoded in the CDB, and 2546 // it is invalid to request more sectors in the CDB than the entire 2547 // transfer (ie. ByteCount) can carry. 2548 // 2549 // In addition, ByteCount is only expected to go down, or stay unchaged. 2550 // Therefore we don't need to update Timeout: the original timeout should 2551 // accommodate shorter transfers too. 2552 // 2553 NextSectorCount = ByteCount / BlockSize; 2554 if (NextSectorCount < SectorCount) { 2555 SectorCount = NextSectorCount; 2556 // 2557 // Account for any rounding down. 2558 // 2559 ByteCount = SectorCount * BlockSize; 2560 } 2561 } 2562 2563 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) { 2564 return EFI_DEVICE_ERROR; 2565 } 2566 // 2567 // actual transferred sectors 2568 // 2569 SectorCount = ByteCount / BlockSize; 2570 2571 Lba += SectorCount; 2572 PtrBuffer = PtrBuffer + SectorCount * BlockSize; 2573 BlocksRemaining -= SectorCount; 2574 } 2575 2576 return EFI_SUCCESS; 2577 } 2578 2579 /** 2580 Asynchronously read sector from SCSI Disk. 2581 2582 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV. 2583 @param Buffer The buffer to fill in the read out data. 2584 @param Lba Logic block address. 2585 @param NumberOfBlocks The number of blocks to read. 2586 @param Token A pointer to the token associated with the 2587 non-blocking read request. 2588 2589 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL. 2590 @retval EFI_DEVICE_ERROR Indicates a device error. 2591 @retval EFI_SUCCESS Operation is successful. 2592 2593 **/ 2594 EFI_STATUS 2595 ScsiDiskAsyncReadSectors ( 2596 IN SCSI_DISK_DEV *ScsiDiskDevice, 2597 OUT VOID *Buffer, 2598 IN EFI_LBA Lba, 2599 IN UINTN NumberOfBlocks, 2600 IN EFI_BLOCK_IO2_TOKEN *Token 2601 ) 2602 { 2603 UINTN BlocksRemaining; 2604 UINT8 *PtrBuffer; 2605 UINT32 BlockSize; 2606 UINT32 ByteCount; 2607 UINT32 MaxBlock; 2608 UINT32 SectorCount; 2609 UINT64 Timeout; 2610 SCSI_BLKIO2_REQUEST *BlkIo2Req; 2611 EFI_STATUS Status; 2612 EFI_TPL OldTpl; 2613 2614 if ((Token == NULL) || (Token->Event == NULL)) { 2615 return EFI_INVALID_PARAMETER; 2616 } 2617 2618 BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST)); 2619 if (BlkIo2Req == NULL) { 2620 return EFI_OUT_OF_RESOURCES; 2621 } 2622 2623 BlkIo2Req->Token = Token; 2624 2625 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 2626 InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link); 2627 gBS->RestoreTPL (OldTpl); 2628 2629 InitializeListHead (&BlkIo2Req->ScsiRWQueue); 2630 2631 Status = EFI_SUCCESS; 2632 2633 BlocksRemaining = NumberOfBlocks; 2634 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize; 2635 2636 // 2637 // Limit the data bytes that can be transferred by one Read(10) or Read(16) 2638 // Command 2639 // 2640 if (!ScsiDiskDevice->Cdb16Byte) { 2641 MaxBlock = 0xFFFF; 2642 } else { 2643 MaxBlock = 0xFFFFFFFF; 2644 } 2645 2646 PtrBuffer = Buffer; 2647 2648 while (BlocksRemaining > 0) { 2649 2650 if (BlocksRemaining <= MaxBlock) { 2651 if (!ScsiDiskDevice->Cdb16Byte) { 2652 SectorCount = (UINT16) BlocksRemaining; 2653 } else { 2654 SectorCount = (UINT32) BlocksRemaining; 2655 } 2656 } else { 2657 SectorCount = MaxBlock; 2658 } 2659 2660 ByteCount = SectorCount * BlockSize; 2661 // 2662 // |------------------------|-----------------|------------------|-----------------| 2663 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate | 2664 // |------------------------|-----------------|------------------|-----------------| 2665 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec | 2666 // |------------------------|-----------------|------------------|-----------------| 2667 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec | 2668 // |------------------------|-----------------|------------------|-----------------| 2669 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec | 2670 // |------------------------|-----------------|------------------|-----------------| 2671 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec | 2672 // |------------------------|-----------------|------------------|-----------------| 2673 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec | 2674 // |------------------------|-----------------|------------------|-----------------| 2675 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec | 2676 // |------------------------|-----------------|------------------|-----------------| 2677 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec | 2678 // |------------------------|-----------------|------------------|-----------------| 2679 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec | 2680 // |------------------------|-----------------|------------------|-----------------| 2681 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec | 2682 // |------------------------|-----------------|------------------|-----------------| 2683 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec | 2684 // |------------------------|-----------------|------------------|-----------------| 2685 // 2686 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, 2687 // we have to use the lowest transfer rate to calculate the possible 2688 // maximum timeout value for each operation. 2689 // From the above table, we could know 2.1Mbytes per second is lowest one. 2690 // The timout value is rounded up to nearest integar and here an additional 2691 // 30s is added to follow ATA spec in which it mentioned that the device 2692 // may take up to 30s to respond commands in the Standby/Idle mode. 2693 // 2694 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31); 2695 2696 if (!ScsiDiskDevice->Cdb16Byte) { 2697 Status = ScsiDiskAsyncRead10 ( 2698 ScsiDiskDevice, 2699 Timeout, 2700 0, 2701 PtrBuffer, 2702 ByteCount, 2703 (UINT32) Lba, 2704 SectorCount, 2705 BlkIo2Req, 2706 Token 2707 ); 2708 } else { 2709 Status = ScsiDiskAsyncRead16 ( 2710 ScsiDiskDevice, 2711 Timeout, 2712 0, 2713 PtrBuffer, 2714 ByteCount, 2715 Lba, 2716 SectorCount, 2717 BlkIo2Req, 2718 Token 2719 ); 2720 } 2721 if (EFI_ERROR (Status)) { 2722 // 2723 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data 2724 // length of a SCSI I/O command is too large. 2725 // In this case, we retry sending the SCSI command with a data length 2726 // half of its previous value. 2727 // 2728 if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) { 2729 if ((MaxBlock > 1) && (SectorCount > 1)) { 2730 MaxBlock = MIN (MaxBlock, SectorCount) >> 1; 2731 continue; 2732 } 2733 } 2734 2735 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 2736 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) { 2737 // 2738 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other 2739 // SCSI sub-task running. Otherwise, it will be freed in the callback 2740 // function ScsiDiskNotify(). 2741 // 2742 RemoveEntryList (&BlkIo2Req->Link); 2743 FreePool (BlkIo2Req); 2744 BlkIo2Req = NULL; 2745 gBS->RestoreTPL (OldTpl); 2746 2747 // 2748 // It is safe to return error status to the caller, since there is no 2749 // previous SCSI sub-task executing. 2750 // 2751 Status = EFI_DEVICE_ERROR; 2752 goto Done; 2753 } else { 2754 gBS->RestoreTPL (OldTpl); 2755 2756 // 2757 // There are previous SCSI commands still running, EFI_SUCCESS should 2758 // be returned to make sure that the caller does not free resources 2759 // still using by these SCSI commands. 2760 // 2761 Status = EFI_SUCCESS; 2762 goto Done; 2763 } 2764 } 2765 2766 // 2767 // Sectors submitted for transfer 2768 // 2769 SectorCount = ByteCount / BlockSize; 2770 2771 Lba += SectorCount; 2772 PtrBuffer = PtrBuffer + SectorCount * BlockSize; 2773 BlocksRemaining -= SectorCount; 2774 } 2775 2776 Status = EFI_SUCCESS; 2777 2778 Done: 2779 if (BlkIo2Req != NULL) { 2780 BlkIo2Req->LastScsiRW = TRUE; 2781 2782 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 2783 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) { 2784 RemoveEntryList (&BlkIo2Req->Link); 2785 FreePool (BlkIo2Req); 2786 BlkIo2Req = NULL; 2787 2788 gBS->SignalEvent (Token->Event); 2789 } 2790 gBS->RestoreTPL (OldTpl); 2791 } 2792 2793 return Status; 2794 } 2795 2796 /** 2797 Asynchronously write sector to SCSI Disk. 2798 2799 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV. 2800 @param Buffer The buffer of data to be written into SCSI Disk. 2801 @param Lba Logic block address. 2802 @param NumberOfBlocks The number of blocks to read. 2803 @param Token A pointer to the token associated with the 2804 non-blocking read request. 2805 2806 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL 2807 @retval EFI_DEVICE_ERROR Indicates a device error. 2808 @retval EFI_SUCCESS Operation is successful. 2809 2810 **/ 2811 EFI_STATUS 2812 ScsiDiskAsyncWriteSectors ( 2813 IN SCSI_DISK_DEV *ScsiDiskDevice, 2814 IN VOID *Buffer, 2815 IN EFI_LBA Lba, 2816 IN UINTN NumberOfBlocks, 2817 IN EFI_BLOCK_IO2_TOKEN *Token 2818 ) 2819 { 2820 UINTN BlocksRemaining; 2821 UINT8 *PtrBuffer; 2822 UINT32 BlockSize; 2823 UINT32 ByteCount; 2824 UINT32 MaxBlock; 2825 UINT32 SectorCount; 2826 UINT64 Timeout; 2827 SCSI_BLKIO2_REQUEST *BlkIo2Req; 2828 EFI_STATUS Status; 2829 EFI_TPL OldTpl; 2830 2831 if ((Token == NULL) || (Token->Event == NULL)) { 2832 return EFI_INVALID_PARAMETER; 2833 } 2834 2835 BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST)); 2836 if (BlkIo2Req == NULL) { 2837 return EFI_OUT_OF_RESOURCES; 2838 } 2839 2840 BlkIo2Req->Token = Token; 2841 2842 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 2843 InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link); 2844 gBS->RestoreTPL (OldTpl); 2845 2846 InitializeListHead (&BlkIo2Req->ScsiRWQueue); 2847 2848 Status = EFI_SUCCESS; 2849 2850 BlocksRemaining = NumberOfBlocks; 2851 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize; 2852 2853 // 2854 // Limit the data bytes that can be transferred by one Read(10) or Read(16) 2855 // Command 2856 // 2857 if (!ScsiDiskDevice->Cdb16Byte) { 2858 MaxBlock = 0xFFFF; 2859 } else { 2860 MaxBlock = 0xFFFFFFFF; 2861 } 2862 2863 PtrBuffer = Buffer; 2864 2865 while (BlocksRemaining > 0) { 2866 2867 if (BlocksRemaining <= MaxBlock) { 2868 if (!ScsiDiskDevice->Cdb16Byte) { 2869 SectorCount = (UINT16) BlocksRemaining; 2870 } else { 2871 SectorCount = (UINT32) BlocksRemaining; 2872 } 2873 } else { 2874 SectorCount = MaxBlock; 2875 } 2876 2877 ByteCount = SectorCount * BlockSize; 2878 // 2879 // |------------------------|-----------------|------------------|-----------------| 2880 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate | 2881 // |------------------------|-----------------|------------------|-----------------| 2882 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec | 2883 // |------------------------|-----------------|------------------|-----------------| 2884 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec | 2885 // |------------------------|-----------------|------------------|-----------------| 2886 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec | 2887 // |------------------------|-----------------|------------------|-----------------| 2888 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec | 2889 // |------------------------|-----------------|------------------|-----------------| 2890 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec | 2891 // |------------------------|-----------------|------------------|-----------------| 2892 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec | 2893 // |------------------------|-----------------|------------------|-----------------| 2894 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec | 2895 // |------------------------|-----------------|------------------|-----------------| 2896 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec | 2897 // |------------------------|-----------------|------------------|-----------------| 2898 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec | 2899 // |------------------------|-----------------|------------------|-----------------| 2900 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec | 2901 // |------------------------|-----------------|------------------|-----------------| 2902 // 2903 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, 2904 // we have to use the lowest transfer rate to calculate the possible 2905 // maximum timeout value for each operation. 2906 // From the above table, we could know 2.1Mbytes per second is lowest one. 2907 // The timout value is rounded up to nearest integar and here an additional 2908 // 30s is added to follow ATA spec in which it mentioned that the device 2909 // may take up to 30s to respond commands in the Standby/Idle mode. 2910 // 2911 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31); 2912 2913 if (!ScsiDiskDevice->Cdb16Byte) { 2914 Status = ScsiDiskAsyncWrite10 ( 2915 ScsiDiskDevice, 2916 Timeout, 2917 0, 2918 PtrBuffer, 2919 ByteCount, 2920 (UINT32) Lba, 2921 SectorCount, 2922 BlkIo2Req, 2923 Token 2924 ); 2925 } else { 2926 Status = ScsiDiskAsyncWrite16 ( 2927 ScsiDiskDevice, 2928 Timeout, 2929 0, 2930 PtrBuffer, 2931 ByteCount, 2932 Lba, 2933 SectorCount, 2934 BlkIo2Req, 2935 Token 2936 ); 2937 } 2938 if (EFI_ERROR (Status)) { 2939 // 2940 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data 2941 // length of a SCSI I/O command is too large. 2942 // In this case, we retry sending the SCSI command with a data length 2943 // half of its previous value. 2944 // 2945 if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) { 2946 if ((MaxBlock > 1) && (SectorCount > 1)) { 2947 MaxBlock = MIN (MaxBlock, SectorCount) >> 1; 2948 continue; 2949 } 2950 } 2951 2952 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 2953 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) { 2954 // 2955 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other 2956 // SCSI sub-task running. Otherwise, it will be freed in the callback 2957 // function ScsiDiskNotify(). 2958 // 2959 RemoveEntryList (&BlkIo2Req->Link); 2960 FreePool (BlkIo2Req); 2961 BlkIo2Req = NULL; 2962 gBS->RestoreTPL (OldTpl); 2963 2964 // 2965 // It is safe to return error status to the caller, since there is no 2966 // previous SCSI sub-task executing. 2967 // 2968 Status = EFI_DEVICE_ERROR; 2969 goto Done; 2970 } else { 2971 gBS->RestoreTPL (OldTpl); 2972 2973 // 2974 // There are previous SCSI commands still running, EFI_SUCCESS should 2975 // be returned to make sure that the caller does not free resources 2976 // still using by these SCSI commands. 2977 // 2978 Status = EFI_SUCCESS; 2979 goto Done; 2980 } 2981 } 2982 2983 // 2984 // Sectors submitted for transfer 2985 // 2986 SectorCount = ByteCount / BlockSize; 2987 2988 Lba += SectorCount; 2989 PtrBuffer = PtrBuffer + SectorCount * BlockSize; 2990 BlocksRemaining -= SectorCount; 2991 } 2992 2993 Status = EFI_SUCCESS; 2994 2995 Done: 2996 if (BlkIo2Req != NULL) { 2997 BlkIo2Req->LastScsiRW = TRUE; 2998 2999 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 3000 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) { 3001 RemoveEntryList (&BlkIo2Req->Link); 3002 FreePool (BlkIo2Req); 3003 BlkIo2Req = NULL; 3004 3005 gBS->SignalEvent (Token->Event); 3006 } 3007 gBS->RestoreTPL (OldTpl); 3008 } 3009 3010 return Status; 3011 } 3012 3013 3014 /** 3015 Submit Read(10) command. 3016 3017 @param ScsiDiskDevice The pointer of ScsiDiskDevice 3018 @param NeedRetry The pointer of flag indicates if needs retry if error happens 3019 @param Timeout The time to complete the command 3020 @param DataBuffer The buffer to fill with the read out data 3021 @param DataLength The length of buffer 3022 @param StartLba The start logic block address 3023 @param SectorCount The number of blocks to read 3024 3025 @return EFI_STATUS is returned by calling ScsiRead10Command(). 3026 **/ 3027 EFI_STATUS 3028 ScsiDiskRead10 ( 3029 IN SCSI_DISK_DEV *ScsiDiskDevice, 3030 OUT BOOLEAN *NeedRetry, 3031 IN UINT64 Timeout, 3032 OUT UINT8 *DataBuffer, 3033 IN OUT UINT32 *DataLength, 3034 IN UINT32 StartLba, 3035 IN UINT32 SectorCount 3036 ) 3037 { 3038 UINT8 SenseDataLength; 3039 EFI_STATUS Status; 3040 EFI_STATUS ReturnStatus; 3041 UINT8 HostAdapterStatus; 3042 UINT8 TargetStatus; 3043 UINTN Action; 3044 3045 // 3046 // Implement a backoff algorithem to resolve some compatibility issues that 3047 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing 3048 // big data in a single operation. 3049 // This algorithem will at first try to execute original request. If the request fails 3050 // with media error sense data or else, it will reduce the transfer length to half and 3051 // try again till the operation succeeds or fails with one sector transfer length. 3052 // 3053 BackOff: 3054 *NeedRetry = FALSE; 3055 Action = ACTION_NO_ACTION; 3056 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA)); 3057 ReturnStatus = ScsiRead10Command ( 3058 ScsiDiskDevice->ScsiIo, 3059 Timeout, 3060 ScsiDiskDevice->SenseData, 3061 &SenseDataLength, 3062 &HostAdapterStatus, 3063 &TargetStatus, 3064 DataBuffer, 3065 DataLength, 3066 StartLba, 3067 SectorCount 3068 ); 3069 3070 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) { 3071 *NeedRetry = TRUE; 3072 return EFI_DEVICE_ERROR; 3073 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) { 3074 *NeedRetry = FALSE; 3075 return ReturnStatus; 3076 } 3077 3078 // 3079 // go ahead to check HostAdapterStatus and TargetStatus 3080 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL) 3081 // 3082 Status = CheckHostAdapterStatus (HostAdapterStatus); 3083 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) { 3084 *NeedRetry = TRUE; 3085 return EFI_DEVICE_ERROR; 3086 } else if (Status == EFI_DEVICE_ERROR) { 3087 // 3088 // reset the scsi channel 3089 // 3090 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); 3091 *NeedRetry = FALSE; 3092 return EFI_DEVICE_ERROR; 3093 } 3094 3095 Status = CheckTargetStatus (TargetStatus); 3096 if (Status == EFI_NOT_READY) { 3097 // 3098 // reset the scsi device 3099 // 3100 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); 3101 *NeedRetry = TRUE; 3102 return EFI_DEVICE_ERROR; 3103 } else if (Status == EFI_DEVICE_ERROR) { 3104 *NeedRetry = FALSE; 3105 return EFI_DEVICE_ERROR; 3106 } 3107 3108 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) { 3109 DEBUG ((EFI_D_ERROR, "ScsiDiskRead10: Check Condition happened!\n")); 3110 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action); 3111 if (Action == ACTION_RETRY_COMMAND_LATER) { 3112 *NeedRetry = TRUE; 3113 return EFI_DEVICE_ERROR; 3114 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) { 3115 if (SectorCount <= 1) { 3116 // 3117 // Jump out if the operation still fails with one sector transfer length. 3118 // 3119 *NeedRetry = FALSE; 3120 return EFI_DEVICE_ERROR; 3121 } 3122 // 3123 // Try again with half length if the sense data shows we need to retry. 3124 // 3125 SectorCount >>= 1; 3126 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize; 3127 goto BackOff; 3128 } else { 3129 *NeedRetry = FALSE; 3130 return EFI_DEVICE_ERROR; 3131 } 3132 } 3133 3134 return ReturnStatus; 3135 } 3136 3137 3138 /** 3139 Submit Write(10) Command. 3140 3141 @param ScsiDiskDevice The pointer of ScsiDiskDevice 3142 @param NeedRetry The pointer of flag indicates if needs retry if error happens 3143 @param Timeout The time to complete the command 3144 @param DataBuffer The buffer to fill with the read out data 3145 @param DataLength The length of buffer 3146 @param StartLba The start logic block address 3147 @param SectorCount The number of blocks to write 3148 3149 @return EFI_STATUS is returned by calling ScsiWrite10Command(). 3150 3151 **/ 3152 EFI_STATUS 3153 ScsiDiskWrite10 ( 3154 IN SCSI_DISK_DEV *ScsiDiskDevice, 3155 OUT BOOLEAN *NeedRetry, 3156 IN UINT64 Timeout, 3157 IN UINT8 *DataBuffer, 3158 IN OUT UINT32 *DataLength, 3159 IN UINT32 StartLba, 3160 IN UINT32 SectorCount 3161 ) 3162 { 3163 EFI_STATUS Status; 3164 EFI_STATUS ReturnStatus; 3165 UINT8 SenseDataLength; 3166 UINT8 HostAdapterStatus; 3167 UINT8 TargetStatus; 3168 UINTN Action; 3169 3170 // 3171 // Implement a backoff algorithem to resolve some compatibility issues that 3172 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing 3173 // big data in a single operation. 3174 // This algorithem will at first try to execute original request. If the request fails 3175 // with media error sense data or else, it will reduce the transfer length to half and 3176 // try again till the operation succeeds or fails with one sector transfer length. 3177 // 3178 BackOff: 3179 *NeedRetry = FALSE; 3180 Action = ACTION_NO_ACTION; 3181 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA)); 3182 ReturnStatus = ScsiWrite10Command ( 3183 ScsiDiskDevice->ScsiIo, 3184 Timeout, 3185 ScsiDiskDevice->SenseData, 3186 &SenseDataLength, 3187 &HostAdapterStatus, 3188 &TargetStatus, 3189 DataBuffer, 3190 DataLength, 3191 StartLba, 3192 SectorCount 3193 ); 3194 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) { 3195 *NeedRetry = TRUE; 3196 return EFI_DEVICE_ERROR; 3197 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) { 3198 *NeedRetry = FALSE; 3199 return ReturnStatus; 3200 } 3201 3202 // 3203 // go ahead to check HostAdapterStatus and TargetStatus 3204 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL) 3205 // 3206 Status = CheckHostAdapterStatus (HostAdapterStatus); 3207 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) { 3208 *NeedRetry = TRUE; 3209 return EFI_DEVICE_ERROR; 3210 } else if (Status == EFI_DEVICE_ERROR) { 3211 // 3212 // reset the scsi channel 3213 // 3214 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); 3215 *NeedRetry = FALSE; 3216 return EFI_DEVICE_ERROR; 3217 } 3218 3219 Status = CheckTargetStatus (TargetStatus); 3220 if (Status == EFI_NOT_READY) { 3221 // 3222 // reset the scsi device 3223 // 3224 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); 3225 *NeedRetry = TRUE; 3226 return EFI_DEVICE_ERROR; 3227 } else if (Status == EFI_DEVICE_ERROR) { 3228 *NeedRetry = FALSE; 3229 return EFI_DEVICE_ERROR; 3230 } 3231 3232 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) { 3233 DEBUG ((EFI_D_ERROR, "ScsiDiskWrite10: Check Condition happened!\n")); 3234 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action); 3235 if (Action == ACTION_RETRY_COMMAND_LATER) { 3236 *NeedRetry = TRUE; 3237 return EFI_DEVICE_ERROR; 3238 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) { 3239 if (SectorCount <= 1) { 3240 // 3241 // Jump out if the operation still fails with one sector transfer length. 3242 // 3243 *NeedRetry = FALSE; 3244 return EFI_DEVICE_ERROR; 3245 } 3246 // 3247 // Try again with half length if the sense data shows we need to retry. 3248 // 3249 SectorCount >>= 1; 3250 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize; 3251 goto BackOff; 3252 } else { 3253 *NeedRetry = FALSE; 3254 return EFI_DEVICE_ERROR; 3255 } 3256 } 3257 3258 return ReturnStatus; 3259 } 3260 3261 3262 /** 3263 Submit Read(16) command. 3264 3265 @param ScsiDiskDevice The pointer of ScsiDiskDevice 3266 @param NeedRetry The pointer of flag indicates if needs retry if error happens 3267 @param Timeout The time to complete the command 3268 @param DataBuffer The buffer to fill with the read out data 3269 @param DataLength The length of buffer 3270 @param StartLba The start logic block address 3271 @param SectorCount The number of blocks to read 3272 3273 @return EFI_STATUS is returned by calling ScsiRead16Command(). 3274 **/ 3275 EFI_STATUS 3276 ScsiDiskRead16 ( 3277 IN SCSI_DISK_DEV *ScsiDiskDevice, 3278 OUT BOOLEAN *NeedRetry, 3279 IN UINT64 Timeout, 3280 OUT UINT8 *DataBuffer, 3281 IN OUT UINT32 *DataLength, 3282 IN UINT64 StartLba, 3283 IN UINT32 SectorCount 3284 ) 3285 { 3286 UINT8 SenseDataLength; 3287 EFI_STATUS Status; 3288 EFI_STATUS ReturnStatus; 3289 UINT8 HostAdapterStatus; 3290 UINT8 TargetStatus; 3291 UINTN Action; 3292 3293 // 3294 // Implement a backoff algorithem to resolve some compatibility issues that 3295 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing 3296 // big data in a single operation. 3297 // This algorithem will at first try to execute original request. If the request fails 3298 // with media error sense data or else, it will reduce the transfer length to half and 3299 // try again till the operation succeeds or fails with one sector transfer length. 3300 // 3301 BackOff: 3302 *NeedRetry = FALSE; 3303 Action = ACTION_NO_ACTION; 3304 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA)); 3305 ReturnStatus = ScsiRead16Command ( 3306 ScsiDiskDevice->ScsiIo, 3307 Timeout, 3308 ScsiDiskDevice->SenseData, 3309 &SenseDataLength, 3310 &HostAdapterStatus, 3311 &TargetStatus, 3312 DataBuffer, 3313 DataLength, 3314 StartLba, 3315 SectorCount 3316 ); 3317 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) { 3318 *NeedRetry = TRUE; 3319 return EFI_DEVICE_ERROR; 3320 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) { 3321 *NeedRetry = FALSE; 3322 return ReturnStatus; 3323 } 3324 3325 // 3326 // go ahead to check HostAdapterStatus and TargetStatus 3327 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL) 3328 // 3329 Status = CheckHostAdapterStatus (HostAdapterStatus); 3330 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) { 3331 *NeedRetry = TRUE; 3332 return EFI_DEVICE_ERROR; 3333 } else if (Status == EFI_DEVICE_ERROR) { 3334 // 3335 // reset the scsi channel 3336 // 3337 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); 3338 *NeedRetry = FALSE; 3339 return EFI_DEVICE_ERROR; 3340 } 3341 3342 Status = CheckTargetStatus (TargetStatus); 3343 if (Status == EFI_NOT_READY) { 3344 // 3345 // reset the scsi device 3346 // 3347 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); 3348 *NeedRetry = TRUE; 3349 return EFI_DEVICE_ERROR; 3350 } else if (Status == EFI_DEVICE_ERROR) { 3351 *NeedRetry = FALSE; 3352 return EFI_DEVICE_ERROR; 3353 } 3354 3355 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) { 3356 DEBUG ((EFI_D_ERROR, "ScsiDiskRead16: Check Condition happened!\n")); 3357 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action); 3358 if (Action == ACTION_RETRY_COMMAND_LATER) { 3359 *NeedRetry = TRUE; 3360 return EFI_DEVICE_ERROR; 3361 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) { 3362 if (SectorCount <= 1) { 3363 // 3364 // Jump out if the operation still fails with one sector transfer length. 3365 // 3366 *NeedRetry = FALSE; 3367 return EFI_DEVICE_ERROR; 3368 } 3369 // 3370 // Try again with half length if the sense data shows we need to retry. 3371 // 3372 SectorCount >>= 1; 3373 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize; 3374 goto BackOff; 3375 } else { 3376 *NeedRetry = FALSE; 3377 return EFI_DEVICE_ERROR; 3378 } 3379 } 3380 3381 return ReturnStatus; 3382 } 3383 3384 3385 /** 3386 Submit Write(16) Command. 3387 3388 @param ScsiDiskDevice The pointer of ScsiDiskDevice 3389 @param NeedRetry The pointer of flag indicates if needs retry if error happens 3390 @param Timeout The time to complete the command 3391 @param DataBuffer The buffer to fill with the read out data 3392 @param DataLength The length of buffer 3393 @param StartLba The start logic block address 3394 @param SectorCount The number of blocks to write 3395 3396 @return EFI_STATUS is returned by calling ScsiWrite16Command(). 3397 3398 **/ 3399 EFI_STATUS 3400 ScsiDiskWrite16 ( 3401 IN SCSI_DISK_DEV *ScsiDiskDevice, 3402 OUT BOOLEAN *NeedRetry, 3403 IN UINT64 Timeout, 3404 IN UINT8 *DataBuffer, 3405 IN OUT UINT32 *DataLength, 3406 IN UINT64 StartLba, 3407 IN UINT32 SectorCount 3408 ) 3409 { 3410 EFI_STATUS Status; 3411 EFI_STATUS ReturnStatus; 3412 UINT8 SenseDataLength; 3413 UINT8 HostAdapterStatus; 3414 UINT8 TargetStatus; 3415 UINTN Action; 3416 3417 // 3418 // Implement a backoff algorithem to resolve some compatibility issues that 3419 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing 3420 // big data in a single operation. 3421 // This algorithem will at first try to execute original request. If the request fails 3422 // with media error sense data or else, it will reduce the transfer length to half and 3423 // try again till the operation succeeds or fails with one sector transfer length. 3424 // 3425 BackOff: 3426 *NeedRetry = FALSE; 3427 Action = ACTION_NO_ACTION; 3428 SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA)); 3429 ReturnStatus = ScsiWrite16Command ( 3430 ScsiDiskDevice->ScsiIo, 3431 Timeout, 3432 ScsiDiskDevice->SenseData, 3433 &SenseDataLength, 3434 &HostAdapterStatus, 3435 &TargetStatus, 3436 DataBuffer, 3437 DataLength, 3438 StartLba, 3439 SectorCount 3440 ); 3441 if (ReturnStatus == EFI_NOT_READY || ReturnStatus == EFI_BAD_BUFFER_SIZE) { 3442 *NeedRetry = TRUE; 3443 return EFI_DEVICE_ERROR; 3444 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) { 3445 *NeedRetry = FALSE; 3446 return ReturnStatus; 3447 } 3448 3449 // 3450 // go ahead to check HostAdapterStatus and TargetStatus 3451 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL) 3452 // 3453 Status = CheckHostAdapterStatus (HostAdapterStatus); 3454 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) { 3455 *NeedRetry = TRUE; 3456 return EFI_DEVICE_ERROR; 3457 } else if (Status == EFI_DEVICE_ERROR) { 3458 // 3459 // reset the scsi channel 3460 // 3461 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); 3462 *NeedRetry = FALSE; 3463 return EFI_DEVICE_ERROR; 3464 } 3465 3466 Status = CheckTargetStatus (TargetStatus); 3467 if (Status == EFI_NOT_READY) { 3468 // 3469 // reset the scsi device 3470 // 3471 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); 3472 *NeedRetry = TRUE; 3473 return EFI_DEVICE_ERROR; 3474 } else if (Status == EFI_DEVICE_ERROR) { 3475 *NeedRetry = FALSE; 3476 return EFI_DEVICE_ERROR; 3477 } 3478 3479 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) { 3480 DEBUG ((EFI_D_ERROR, "ScsiDiskWrite16: Check Condition happened!\n")); 3481 Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action); 3482 if (Action == ACTION_RETRY_COMMAND_LATER) { 3483 *NeedRetry = TRUE; 3484 return EFI_DEVICE_ERROR; 3485 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) { 3486 if (SectorCount <= 1) { 3487 // 3488 // Jump out if the operation still fails with one sector transfer length. 3489 // 3490 *NeedRetry = FALSE; 3491 return EFI_DEVICE_ERROR; 3492 } 3493 // 3494 // Try again with half length if the sense data shows we need to retry. 3495 // 3496 SectorCount >>= 1; 3497 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize; 3498 goto BackOff; 3499 } else { 3500 *NeedRetry = FALSE; 3501 return EFI_DEVICE_ERROR; 3502 } 3503 } 3504 3505 return ReturnStatus; 3506 } 3507 3508 3509 /** 3510 Internal helper notify function in which determine whether retry of a SCSI 3511 Read/Write command is needed and signal the event passed from Block I/O(2) if 3512 the SCSI I/O operation completes. 3513 3514 @param Event The instance of EFI_EVENT. 3515 @param Context The parameter passed in. 3516 3517 **/ 3518 VOID 3519 EFIAPI 3520 ScsiDiskNotify ( 3521 IN EFI_EVENT Event, 3522 IN VOID *Context 3523 ) 3524 { 3525 EFI_STATUS Status; 3526 SCSI_ASYNC_RW_REQUEST *Request; 3527 SCSI_DISK_DEV *ScsiDiskDevice; 3528 EFI_BLOCK_IO2_TOKEN *Token; 3529 UINTN Action; 3530 UINT32 OldDataLength; 3531 UINT32 OldSectorCount; 3532 UINT8 MaxRetry; 3533 3534 gBS->CloseEvent (Event); 3535 3536 Request = (SCSI_ASYNC_RW_REQUEST *) Context; 3537 ScsiDiskDevice = Request->ScsiDiskDevice; 3538 Token = Request->BlkIo2Req->Token; 3539 OldDataLength = Request->DataLength; 3540 OldSectorCount = Request->SectorCount; 3541 MaxRetry = 2; 3542 3543 // 3544 // If previous sub-tasks already fails, no need to process this sub-task. 3545 // 3546 if (Token->TransactionStatus != EFI_SUCCESS) { 3547 goto Exit; 3548 } 3549 3550 // 3551 // Check HostAdapterStatus and TargetStatus 3552 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL) 3553 // 3554 Status = CheckHostAdapterStatus (Request->HostAdapterStatus); 3555 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) { 3556 if (++Request->TimesRetry > MaxRetry) { 3557 Token->TransactionStatus = EFI_DEVICE_ERROR; 3558 goto Exit; 3559 } else { 3560 goto Retry; 3561 } 3562 } else if (Status == EFI_DEVICE_ERROR) { 3563 // 3564 // reset the scsi channel 3565 // 3566 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo); 3567 Token->TransactionStatus = EFI_DEVICE_ERROR; 3568 goto Exit; 3569 } 3570 3571 Status = CheckTargetStatus (Request->TargetStatus); 3572 if (Status == EFI_NOT_READY) { 3573 // 3574 // reset the scsi device 3575 // 3576 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo); 3577 if (++Request->TimesRetry > MaxRetry) { 3578 Token->TransactionStatus = EFI_DEVICE_ERROR; 3579 goto Exit; 3580 } else { 3581 goto Retry; 3582 } 3583 } else if (Status == EFI_DEVICE_ERROR) { 3584 Token->TransactionStatus = EFI_DEVICE_ERROR; 3585 goto Exit; 3586 } 3587 3588 if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) { 3589 DEBUG ((EFI_D_ERROR, "ScsiDiskNotify: Check Condition happened!\n")); 3590 3591 Status = DetectMediaParsingSenseKeys ( 3592 ScsiDiskDevice, 3593 Request->SenseData, 3594 Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), 3595 &Action 3596 ); 3597 if (Action == ACTION_RETRY_COMMAND_LATER) { 3598 if (++Request->TimesRetry > MaxRetry) { 3599 Token->TransactionStatus = EFI_DEVICE_ERROR; 3600 goto Exit; 3601 } else { 3602 goto Retry; 3603 } 3604 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) { 3605 if (Request->SectorCount <= 1) { 3606 // 3607 // Jump out if the operation still fails with one sector transfer 3608 // length. 3609 // 3610 Token->TransactionStatus = EFI_DEVICE_ERROR; 3611 goto Exit; 3612 } 3613 // 3614 // Try again with two half length request if the sense data shows we need 3615 // to retry. 3616 // 3617 Request->SectorCount >>= 1; 3618 Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize; 3619 Request->TimesRetry = 0; 3620 3621 goto Retry; 3622 } else { 3623 Token->TransactionStatus = EFI_DEVICE_ERROR; 3624 goto Exit; 3625 } 3626 } 3627 3628 // 3629 // This sub-task succeeds, no need to retry. 3630 // 3631 goto Exit; 3632 3633 Retry: 3634 if (Request->InBuffer != NULL) { 3635 // 3636 // SCSI read command 3637 // 3638 if (!ScsiDiskDevice->Cdb16Byte) { 3639 Status = ScsiDiskAsyncRead10 ( 3640 ScsiDiskDevice, 3641 Request->Timeout, 3642 Request->TimesRetry, 3643 Request->InBuffer, 3644 Request->DataLength, 3645 (UINT32) Request->StartLba, 3646 Request->SectorCount, 3647 Request->BlkIo2Req, 3648 Token 3649 ); 3650 } else { 3651 Status = ScsiDiskAsyncRead16 ( 3652 ScsiDiskDevice, 3653 Request->Timeout, 3654 Request->TimesRetry, 3655 Request->InBuffer, 3656 Request->DataLength, 3657 Request->StartLba, 3658 Request->SectorCount, 3659 Request->BlkIo2Req, 3660 Token 3661 ); 3662 } 3663 3664 if (EFI_ERROR (Status)) { 3665 Token->TransactionStatus = EFI_DEVICE_ERROR; 3666 goto Exit; 3667 } else if (OldSectorCount != Request->SectorCount) { 3668 // 3669 // Original sub-task will be split into two new sub-tasks with smaller 3670 // DataLength 3671 // 3672 if (!ScsiDiskDevice->Cdb16Byte) { 3673 Status = ScsiDiskAsyncRead10 ( 3674 ScsiDiskDevice, 3675 Request->Timeout, 3676 0, 3677 Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize, 3678 OldDataLength - Request->DataLength, 3679 (UINT32) Request->StartLba + Request->SectorCount, 3680 OldSectorCount - Request->SectorCount, 3681 Request->BlkIo2Req, 3682 Token 3683 ); 3684 } else { 3685 Status = ScsiDiskAsyncRead16 ( 3686 ScsiDiskDevice, 3687 Request->Timeout, 3688 0, 3689 Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize, 3690 OldDataLength - Request->DataLength, 3691 Request->StartLba + Request->SectorCount, 3692 OldSectorCount - Request->SectorCount, 3693 Request->BlkIo2Req, 3694 Token 3695 ); 3696 } 3697 if (EFI_ERROR (Status)) { 3698 Token->TransactionStatus = EFI_DEVICE_ERROR; 3699 goto Exit; 3700 } 3701 } 3702 } else { 3703 // 3704 // SCSI write command 3705 // 3706 if (!ScsiDiskDevice->Cdb16Byte) { 3707 Status = ScsiDiskAsyncWrite10 ( 3708 ScsiDiskDevice, 3709 Request->Timeout, 3710 Request->TimesRetry, 3711 Request->OutBuffer, 3712 Request->DataLength, 3713 (UINT32) Request->StartLba, 3714 Request->SectorCount, 3715 Request->BlkIo2Req, 3716 Token 3717 ); 3718 } else { 3719 Status = ScsiDiskAsyncWrite16 ( 3720 ScsiDiskDevice, 3721 Request->Timeout, 3722 Request->TimesRetry, 3723 Request->OutBuffer, 3724 Request->DataLength, 3725 Request->StartLba, 3726 Request->SectorCount, 3727 Request->BlkIo2Req, 3728 Token 3729 ); 3730 } 3731 3732 if (EFI_ERROR (Status)) { 3733 Token->TransactionStatus = EFI_DEVICE_ERROR; 3734 goto Exit; 3735 } else if (OldSectorCount != Request->SectorCount) { 3736 // 3737 // Original sub-task will be split into two new sub-tasks with smaller 3738 // DataLength 3739 // 3740 if (!ScsiDiskDevice->Cdb16Byte) { 3741 Status = ScsiDiskAsyncWrite10 ( 3742 ScsiDiskDevice, 3743 Request->Timeout, 3744 0, 3745 Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize, 3746 OldDataLength - Request->DataLength, 3747 (UINT32) Request->StartLba + Request->SectorCount, 3748 OldSectorCount - Request->SectorCount, 3749 Request->BlkIo2Req, 3750 Token 3751 ); 3752 } else { 3753 Status = ScsiDiskAsyncWrite16 ( 3754 ScsiDiskDevice, 3755 Request->Timeout, 3756 0, 3757 Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize, 3758 OldDataLength - Request->DataLength, 3759 Request->StartLba + Request->SectorCount, 3760 OldSectorCount - Request->SectorCount, 3761 Request->BlkIo2Req, 3762 Token 3763 ); 3764 } 3765 if (EFI_ERROR (Status)) { 3766 Token->TransactionStatus = EFI_DEVICE_ERROR; 3767 goto Exit; 3768 } 3769 } 3770 } 3771 3772 Exit: 3773 RemoveEntryList (&Request->Link); 3774 if ((IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) && 3775 (Request->BlkIo2Req->LastScsiRW)) { 3776 // 3777 // The last SCSI R/W command of a BlockIo2 request completes 3778 // 3779 RemoveEntryList (&Request->BlkIo2Req->Link); 3780 FreePool (Request->BlkIo2Req); // Should be freed only once 3781 gBS->SignalEvent (Token->Event); 3782 } 3783 3784 FreePool (Request->SenseData); 3785 FreePool (Request); 3786 } 3787 3788 3789 /** 3790 Submit Async Read(10) command. 3791 3792 @param ScsiDiskDevice The pointer of ScsiDiskDevice. 3793 @param Timeout The time to complete the command. 3794 @param TimesRetry The number of times the command has been retried. 3795 @param DataBuffer The buffer to fill with the read out data. 3796 @param DataLength The length of buffer. 3797 @param StartLba The start logic block address. 3798 @param SectorCount The number of blocks to read. 3799 @param BlkIo2Req The upstream BlockIo2 request. 3800 @param Token The pointer to the token associated with the 3801 non-blocking read request. 3802 3803 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a 3804 lack of resources. 3805 @return others Status returned by calling 3806 ScsiRead10CommandEx(). 3807 3808 **/ 3809 EFI_STATUS 3810 ScsiDiskAsyncRead10 ( 3811 IN SCSI_DISK_DEV *ScsiDiskDevice, 3812 IN UINT64 Timeout, 3813 IN UINT8 TimesRetry, 3814 OUT UINT8 *DataBuffer, 3815 IN UINT32 DataLength, 3816 IN UINT32 StartLba, 3817 IN UINT32 SectorCount, 3818 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req, 3819 IN EFI_BLOCK_IO2_TOKEN *Token 3820 ) 3821 { 3822 EFI_STATUS Status; 3823 SCSI_ASYNC_RW_REQUEST *Request; 3824 EFI_EVENT AsyncIoEvent; 3825 EFI_TPL OldTpl; 3826 3827 AsyncIoEvent = NULL; 3828 3829 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST)); 3830 if (Request == NULL) { 3831 return EFI_OUT_OF_RESOURCES; 3832 } 3833 3834 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 3835 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link); 3836 gBS->RestoreTPL (OldTpl); 3837 3838 Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA)); 3839 Request->SenseData = AllocateZeroPool (Request->SenseDataLength); 3840 if (Request->SenseData == NULL) { 3841 Status = EFI_OUT_OF_RESOURCES; 3842 goto ErrorExit; 3843 } 3844 3845 Request->ScsiDiskDevice = ScsiDiskDevice; 3846 Request->Timeout = Timeout; 3847 Request->TimesRetry = TimesRetry; 3848 Request->InBuffer = DataBuffer; 3849 Request->DataLength = DataLength; 3850 Request->StartLba = StartLba; 3851 Request->SectorCount = SectorCount; 3852 Request->BlkIo2Req = BlkIo2Req; 3853 3854 // 3855 // Create Event 3856 // 3857 Status = gBS->CreateEvent ( 3858 EVT_NOTIFY_SIGNAL, 3859 TPL_NOTIFY, 3860 ScsiDiskNotify, 3861 Request, 3862 &AsyncIoEvent 3863 ); 3864 if (EFI_ERROR(Status)) { 3865 goto ErrorExit; 3866 } 3867 3868 Status = ScsiRead10CommandEx ( 3869 ScsiDiskDevice->ScsiIo, 3870 Request->Timeout, 3871 Request->SenseData, 3872 &Request->SenseDataLength, 3873 &Request->HostAdapterStatus, 3874 &Request->TargetStatus, 3875 Request->InBuffer, 3876 &Request->DataLength, 3877 (UINT32) Request->StartLba, 3878 Request->SectorCount, 3879 AsyncIoEvent 3880 ); 3881 if (EFI_ERROR(Status)) { 3882 goto ErrorExit; 3883 } 3884 3885 return EFI_SUCCESS; 3886 3887 ErrorExit: 3888 if (AsyncIoEvent != NULL) { 3889 gBS->CloseEvent (AsyncIoEvent); 3890 } 3891 3892 if (Request != NULL) { 3893 if (Request->SenseData != NULL) { 3894 FreePool (Request->SenseData); 3895 } 3896 3897 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 3898 RemoveEntryList (&Request->Link); 3899 gBS->RestoreTPL (OldTpl); 3900 3901 FreePool (Request); 3902 } 3903 3904 return Status; 3905 } 3906 3907 3908 /** 3909 Submit Async Write(10) command. 3910 3911 @param ScsiDiskDevice The pointer of ScsiDiskDevice. 3912 @param Timeout The time to complete the command. 3913 @param TimesRetry The number of times the command has been retried. 3914 @param DataBuffer The buffer contains the data to write. 3915 @param DataLength The length of buffer. 3916 @param StartLba The start logic block address. 3917 @param SectorCount The number of blocks to write. 3918 @param BlkIo2Req The upstream BlockIo2 request. 3919 @param Token The pointer to the token associated with the 3920 non-blocking read request. 3921 3922 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a 3923 lack of resources. 3924 @return others Status returned by calling 3925 ScsiWrite10CommandEx(). 3926 3927 **/ 3928 EFI_STATUS 3929 ScsiDiskAsyncWrite10 ( 3930 IN SCSI_DISK_DEV *ScsiDiskDevice, 3931 IN UINT64 Timeout, 3932 IN UINT8 TimesRetry, 3933 IN UINT8 *DataBuffer, 3934 IN UINT32 DataLength, 3935 IN UINT32 StartLba, 3936 IN UINT32 SectorCount, 3937 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req, 3938 IN EFI_BLOCK_IO2_TOKEN *Token 3939 ) 3940 { 3941 EFI_STATUS Status; 3942 SCSI_ASYNC_RW_REQUEST *Request; 3943 EFI_EVENT AsyncIoEvent; 3944 EFI_TPL OldTpl; 3945 3946 AsyncIoEvent = NULL; 3947 3948 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST)); 3949 if (Request == NULL) { 3950 return EFI_OUT_OF_RESOURCES; 3951 } 3952 3953 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 3954 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link); 3955 gBS->RestoreTPL (OldTpl); 3956 3957 Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA)); 3958 Request->SenseData = AllocateZeroPool (Request->SenseDataLength); 3959 if (Request->SenseData == NULL) { 3960 Status = EFI_OUT_OF_RESOURCES; 3961 goto ErrorExit; 3962 } 3963 3964 Request->ScsiDiskDevice = ScsiDiskDevice; 3965 Request->Timeout = Timeout; 3966 Request->TimesRetry = TimesRetry; 3967 Request->OutBuffer = DataBuffer; 3968 Request->DataLength = DataLength; 3969 Request->StartLba = StartLba; 3970 Request->SectorCount = SectorCount; 3971 Request->BlkIo2Req = BlkIo2Req; 3972 3973 // 3974 // Create Event 3975 // 3976 Status = gBS->CreateEvent ( 3977 EVT_NOTIFY_SIGNAL, 3978 TPL_NOTIFY, 3979 ScsiDiskNotify, 3980 Request, 3981 &AsyncIoEvent 3982 ); 3983 if (EFI_ERROR(Status)) { 3984 goto ErrorExit; 3985 } 3986 3987 Status = ScsiWrite10CommandEx ( 3988 ScsiDiskDevice->ScsiIo, 3989 Request->Timeout, 3990 Request->SenseData, 3991 &Request->SenseDataLength, 3992 &Request->HostAdapterStatus, 3993 &Request->TargetStatus, 3994 Request->OutBuffer, 3995 &Request->DataLength, 3996 (UINT32) Request->StartLba, 3997 Request->SectorCount, 3998 AsyncIoEvent 3999 ); 4000 if (EFI_ERROR(Status)) { 4001 goto ErrorExit; 4002 } 4003 4004 return EFI_SUCCESS; 4005 4006 ErrorExit: 4007 if (AsyncIoEvent != NULL) { 4008 gBS->CloseEvent (AsyncIoEvent); 4009 } 4010 4011 if (Request != NULL) { 4012 if (Request->SenseData != NULL) { 4013 FreePool (Request->SenseData); 4014 } 4015 4016 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 4017 RemoveEntryList (&Request->Link); 4018 gBS->RestoreTPL (OldTpl); 4019 4020 FreePool (Request); 4021 } 4022 4023 return Status; 4024 } 4025 4026 4027 /** 4028 Submit Async Read(16) command. 4029 4030 @param ScsiDiskDevice The pointer of ScsiDiskDevice. 4031 @param Timeout The time to complete the command. 4032 @param TimesRetry The number of times the command has been retried. 4033 @param DataBuffer The buffer to fill with the read out data. 4034 @param DataLength The length of buffer. 4035 @param StartLba The start logic block address. 4036 @param SectorCount The number of blocks to read. 4037 @param BlkIo2Req The upstream BlockIo2 request. 4038 @param Token The pointer to the token associated with the 4039 non-blocking read request. 4040 4041 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a 4042 lack of resources. 4043 @return others Status returned by calling 4044 ScsiRead16CommandEx(). 4045 4046 **/ 4047 EFI_STATUS 4048 ScsiDiskAsyncRead16 ( 4049 IN SCSI_DISK_DEV *ScsiDiskDevice, 4050 IN UINT64 Timeout, 4051 IN UINT8 TimesRetry, 4052 OUT UINT8 *DataBuffer, 4053 IN UINT32 DataLength, 4054 IN UINT64 StartLba, 4055 IN UINT32 SectorCount, 4056 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req, 4057 IN EFI_BLOCK_IO2_TOKEN *Token 4058 ) 4059 { 4060 EFI_STATUS Status; 4061 SCSI_ASYNC_RW_REQUEST *Request; 4062 EFI_EVENT AsyncIoEvent; 4063 EFI_TPL OldTpl; 4064 4065 AsyncIoEvent = NULL; 4066 4067 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST)); 4068 if (Request == NULL) { 4069 return EFI_OUT_OF_RESOURCES; 4070 } 4071 4072 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 4073 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link); 4074 gBS->RestoreTPL (OldTpl); 4075 4076 Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA)); 4077 Request->SenseData = AllocateZeroPool (Request->SenseDataLength); 4078 if (Request->SenseData == NULL) { 4079 Status = EFI_OUT_OF_RESOURCES; 4080 goto ErrorExit; 4081 } 4082 4083 Request->ScsiDiskDevice = ScsiDiskDevice; 4084 Request->Timeout = Timeout; 4085 Request->TimesRetry = TimesRetry; 4086 Request->InBuffer = DataBuffer; 4087 Request->DataLength = DataLength; 4088 Request->StartLba = StartLba; 4089 Request->SectorCount = SectorCount; 4090 Request->BlkIo2Req = BlkIo2Req; 4091 4092 // 4093 // Create Event 4094 // 4095 Status = gBS->CreateEvent ( 4096 EVT_NOTIFY_SIGNAL, 4097 TPL_NOTIFY, 4098 ScsiDiskNotify, 4099 Request, 4100 &AsyncIoEvent 4101 ); 4102 if (EFI_ERROR(Status)) { 4103 goto ErrorExit; 4104 } 4105 4106 Status = ScsiRead16CommandEx ( 4107 ScsiDiskDevice->ScsiIo, 4108 Request->Timeout, 4109 Request->SenseData, 4110 &Request->SenseDataLength, 4111 &Request->HostAdapterStatus, 4112 &Request->TargetStatus, 4113 Request->InBuffer, 4114 &Request->DataLength, 4115 Request->StartLba, 4116 Request->SectorCount, 4117 AsyncIoEvent 4118 ); 4119 if (EFI_ERROR(Status)) { 4120 goto ErrorExit; 4121 } 4122 4123 return EFI_SUCCESS; 4124 4125 ErrorExit: 4126 if (AsyncIoEvent != NULL) { 4127 gBS->CloseEvent (AsyncIoEvent); 4128 } 4129 4130 if (Request != NULL) { 4131 if (Request->SenseData != NULL) { 4132 FreePool (Request->SenseData); 4133 } 4134 4135 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 4136 RemoveEntryList (&Request->Link); 4137 gBS->RestoreTPL (OldTpl); 4138 4139 FreePool (Request); 4140 } 4141 4142 return Status; 4143 } 4144 4145 4146 /** 4147 Submit Async Write(16) command. 4148 4149 @param ScsiDiskDevice The pointer of ScsiDiskDevice. 4150 @param Timeout The time to complete the command. 4151 @param TimesRetry The number of times the command has been retried. 4152 @param DataBuffer The buffer contains the data to write. 4153 @param DataLength The length of buffer. 4154 @param StartLba The start logic block address. 4155 @param SectorCount The number of blocks to write. 4156 @param BlkIo2Req The upstream BlockIo2 request. 4157 @param Token The pointer to the token associated with the 4158 non-blocking read request. 4159 4160 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a 4161 lack of resources. 4162 @return others Status returned by calling 4163 ScsiWrite16CommandEx(). 4164 4165 **/ 4166 EFI_STATUS 4167 ScsiDiskAsyncWrite16 ( 4168 IN SCSI_DISK_DEV *ScsiDiskDevice, 4169 IN UINT64 Timeout, 4170 IN UINT8 TimesRetry, 4171 IN UINT8 *DataBuffer, 4172 IN UINT32 DataLength, 4173 IN UINT64 StartLba, 4174 IN UINT32 SectorCount, 4175 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req, 4176 IN EFI_BLOCK_IO2_TOKEN *Token 4177 ) 4178 { 4179 EFI_STATUS Status; 4180 SCSI_ASYNC_RW_REQUEST *Request; 4181 EFI_EVENT AsyncIoEvent; 4182 EFI_TPL OldTpl; 4183 4184 AsyncIoEvent = NULL; 4185 4186 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST)); 4187 if (Request == NULL) { 4188 return EFI_OUT_OF_RESOURCES; 4189 } 4190 4191 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 4192 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link); 4193 gBS->RestoreTPL (OldTpl); 4194 4195 Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA)); 4196 Request->SenseData = AllocateZeroPool (Request->SenseDataLength); 4197 if (Request->SenseData == NULL) { 4198 Status = EFI_OUT_OF_RESOURCES; 4199 goto ErrorExit; 4200 } 4201 4202 Request->ScsiDiskDevice = ScsiDiskDevice; 4203 Request->Timeout = Timeout; 4204 Request->TimesRetry = TimesRetry; 4205 Request->OutBuffer = DataBuffer; 4206 Request->DataLength = DataLength; 4207 Request->StartLba = StartLba; 4208 Request->SectorCount = SectorCount; 4209 Request->BlkIo2Req = BlkIo2Req; 4210 4211 // 4212 // Create Event 4213 // 4214 Status = gBS->CreateEvent ( 4215 EVT_NOTIFY_SIGNAL, 4216 TPL_NOTIFY, 4217 ScsiDiskNotify, 4218 Request, 4219 &AsyncIoEvent 4220 ); 4221 if (EFI_ERROR(Status)) { 4222 goto ErrorExit; 4223 } 4224 4225 Status = ScsiWrite16CommandEx ( 4226 ScsiDiskDevice->ScsiIo, 4227 Request->Timeout, 4228 Request->SenseData, 4229 &Request->SenseDataLength, 4230 &Request->HostAdapterStatus, 4231 &Request->TargetStatus, 4232 Request->OutBuffer, 4233 &Request->DataLength, 4234 Request->StartLba, 4235 Request->SectorCount, 4236 AsyncIoEvent 4237 ); 4238 if (EFI_ERROR(Status)) { 4239 goto ErrorExit; 4240 } 4241 4242 return EFI_SUCCESS; 4243 4244 ErrorExit: 4245 if (AsyncIoEvent != NULL) { 4246 gBS->CloseEvent (AsyncIoEvent); 4247 } 4248 4249 if (Request != NULL) { 4250 if (Request->SenseData != NULL) { 4251 FreePool (Request->SenseData); 4252 } 4253 4254 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); 4255 RemoveEntryList (&Request->Link); 4256 gBS->RestoreTPL (OldTpl); 4257 4258 FreePool (Request); 4259 } 4260 4261 return Status; 4262 } 4263 4264 4265 /** 4266 Check sense key to find if media presents. 4267 4268 @param SenseData The pointer of EFI_SCSI_SENSE_DATA 4269 @param SenseCounts The number of sense key 4270 4271 @retval TRUE NOT any media 4272 @retval FALSE Media presents 4273 **/ 4274 BOOLEAN 4275 ScsiDiskIsNoMedia ( 4276 IN EFI_SCSI_SENSE_DATA *SenseData, 4277 IN UINTN SenseCounts 4278 ) 4279 { 4280 EFI_SCSI_SENSE_DATA *SensePtr; 4281 UINTN Index; 4282 BOOLEAN IsNoMedia; 4283 4284 IsNoMedia = FALSE; 4285 SensePtr = SenseData; 4286 4287 for (Index = 0; Index < SenseCounts; Index++) { 4288 // 4289 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2), 4290 // Additional Sense Code is ASC_NO_MEDIA (0x3A) 4291 // 4292 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) && 4293 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) { 4294 IsNoMedia = TRUE; 4295 } 4296 SensePtr++; 4297 } 4298 4299 return IsNoMedia; 4300 } 4301 4302 4303 /** 4304 Parse sense key. 4305 4306 @param SenseData The pointer of EFI_SCSI_SENSE_DATA 4307 @param SenseCounts The number of sense key 4308 4309 @retval TRUE Error 4310 @retval FALSE NOT error 4311 4312 **/ 4313 BOOLEAN 4314 ScsiDiskIsMediaError ( 4315 IN EFI_SCSI_SENSE_DATA *SenseData, 4316 IN UINTN SenseCounts 4317 ) 4318 { 4319 EFI_SCSI_SENSE_DATA *SensePtr; 4320 UINTN Index; 4321 BOOLEAN IsError; 4322 4323 IsError = FALSE; 4324 SensePtr = SenseData; 4325 4326 for (Index = 0; Index < SenseCounts; Index++) { 4327 4328 switch (SensePtr->Sense_Key) { 4329 4330 case EFI_SCSI_SK_MEDIUM_ERROR: 4331 // 4332 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3) 4333 // 4334 switch (SensePtr->Addnl_Sense_Code) { 4335 4336 // 4337 // fall through 4338 // 4339 case EFI_SCSI_ASC_MEDIA_ERR1: 4340 4341 // 4342 // fall through 4343 // 4344 case EFI_SCSI_ASC_MEDIA_ERR2: 4345 4346 // 4347 // fall through 4348 // 4349 case EFI_SCSI_ASC_MEDIA_ERR3: 4350 case EFI_SCSI_ASC_MEDIA_ERR4: 4351 IsError = TRUE; 4352 break; 4353 4354 default: 4355 break; 4356 } 4357 4358 break; 4359 4360 case EFI_SCSI_SK_NOT_READY: 4361 // 4362 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2) 4363 // 4364 switch (SensePtr->Addnl_Sense_Code) { 4365 // 4366 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6) 4367 // 4368 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN: 4369 IsError = TRUE; 4370 break; 4371 4372 default: 4373 break; 4374 } 4375 break; 4376 4377 default: 4378 break; 4379 } 4380 4381 SensePtr++; 4382 } 4383 4384 return IsError; 4385 } 4386 4387 4388 /** 4389 Check sense key to find if hardware error happens. 4390 4391 @param SenseData The pointer of EFI_SCSI_SENSE_DATA 4392 @param SenseCounts The number of sense key 4393 4394 @retval TRUE Hardware error exits. 4395 @retval FALSE NO error. 4396 4397 **/ 4398 BOOLEAN 4399 ScsiDiskIsHardwareError ( 4400 IN EFI_SCSI_SENSE_DATA *SenseData, 4401 IN UINTN SenseCounts 4402 ) 4403 { 4404 EFI_SCSI_SENSE_DATA *SensePtr; 4405 UINTN Index; 4406 BOOLEAN IsError; 4407 4408 IsError = FALSE; 4409 SensePtr = SenseData; 4410 4411 for (Index = 0; Index < SenseCounts; Index++) { 4412 4413 // 4414 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4) 4415 // 4416 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) { 4417 IsError = TRUE; 4418 } 4419 4420 SensePtr++; 4421 } 4422 4423 return IsError; 4424 } 4425 4426 4427 /** 4428 Check sense key to find if media has changed. 4429 4430 @param SenseData The pointer of EFI_SCSI_SENSE_DATA 4431 @param SenseCounts The number of sense key 4432 4433 @retval TRUE Media is changed. 4434 @retval FALSE Media is NOT changed. 4435 **/ 4436 BOOLEAN 4437 ScsiDiskIsMediaChange ( 4438 IN EFI_SCSI_SENSE_DATA *SenseData, 4439 IN UINTN SenseCounts 4440 ) 4441 { 4442 EFI_SCSI_SENSE_DATA *SensePtr; 4443 UINTN Index; 4444 BOOLEAN IsMediaChanged; 4445 4446 IsMediaChanged = FALSE; 4447 SensePtr = SenseData; 4448 4449 for (Index = 0; Index < SenseCounts; Index++) { 4450 // 4451 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6), 4452 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28) 4453 // 4454 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) && 4455 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) { 4456 IsMediaChanged = TRUE; 4457 } 4458 4459 SensePtr++; 4460 } 4461 4462 return IsMediaChanged; 4463 } 4464 4465 /** 4466 Check sense key to find if reset happens. 4467 4468 @param SenseData The pointer of EFI_SCSI_SENSE_DATA 4469 @param SenseCounts The number of sense key 4470 4471 @retval TRUE It is reset before. 4472 @retval FALSE It is NOT reset before. 4473 4474 **/ 4475 BOOLEAN 4476 ScsiDiskIsResetBefore ( 4477 IN EFI_SCSI_SENSE_DATA *SenseData, 4478 IN UINTN SenseCounts 4479 ) 4480 { 4481 EFI_SCSI_SENSE_DATA *SensePtr; 4482 UINTN Index; 4483 BOOLEAN IsResetBefore; 4484 4485 IsResetBefore = FALSE; 4486 SensePtr = SenseData; 4487 4488 for (Index = 0; Index < SenseCounts; Index++) { 4489 4490 // 4491 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6) 4492 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29) 4493 // 4494 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) && 4495 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) { 4496 IsResetBefore = TRUE; 4497 } 4498 4499 SensePtr++; 4500 } 4501 4502 return IsResetBefore; 4503 } 4504 4505 /** 4506 Check sense key to find if the drive is ready. 4507 4508 @param SenseData The pointer of EFI_SCSI_SENSE_DATA 4509 @param SenseCounts The number of sense key 4510 @param RetryLater The flag means if need a retry 4511 4512 @retval TRUE Drive is ready. 4513 @retval FALSE Drive is NOT ready. 4514 4515 **/ 4516 BOOLEAN 4517 ScsiDiskIsDriveReady ( 4518 IN EFI_SCSI_SENSE_DATA *SenseData, 4519 IN UINTN SenseCounts, 4520 OUT BOOLEAN *RetryLater 4521 ) 4522 { 4523 EFI_SCSI_SENSE_DATA *SensePtr; 4524 UINTN Index; 4525 BOOLEAN IsReady; 4526 4527 IsReady = TRUE; 4528 *RetryLater = FALSE; 4529 SensePtr = SenseData; 4530 4531 for (Index = 0; Index < SenseCounts; Index++) { 4532 4533 switch (SensePtr->Sense_Key) { 4534 4535 case EFI_SCSI_SK_NOT_READY: 4536 // 4537 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2) 4538 // 4539 switch (SensePtr->Addnl_Sense_Code) { 4540 case EFI_SCSI_ASC_NOT_READY: 4541 // 4542 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4) 4543 // 4544 switch (SensePtr->Addnl_Sense_Code_Qualifier) { 4545 case EFI_SCSI_ASCQ_IN_PROGRESS: 4546 // 4547 // Additional Sense Code Qualifier is 4548 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1) 4549 // 4550 IsReady = FALSE; 4551 *RetryLater = TRUE; 4552 break; 4553 4554 default: 4555 IsReady = FALSE; 4556 *RetryLater = FALSE; 4557 break; 4558 } 4559 break; 4560 4561 default: 4562 break; 4563 } 4564 break; 4565 4566 default: 4567 break; 4568 } 4569 4570 SensePtr++; 4571 } 4572 4573 return IsReady; 4574 } 4575 4576 /** 4577 Check sense key to find if it has sense key. 4578 4579 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA 4580 @param SenseCounts - The number of sense key 4581 4582 @retval TRUE It has sense key. 4583 @retval FALSE It has NOT any sense key. 4584 4585 **/ 4586 BOOLEAN 4587 ScsiDiskHaveSenseKey ( 4588 IN EFI_SCSI_SENSE_DATA *SenseData, 4589 IN UINTN SenseCounts 4590 ) 4591 { 4592 EFI_SCSI_SENSE_DATA *SensePtr; 4593 UINTN Index; 4594 BOOLEAN HaveSenseKey; 4595 4596 if (SenseCounts == 0) { 4597 HaveSenseKey = FALSE; 4598 } else { 4599 HaveSenseKey = TRUE; 4600 } 4601 4602 SensePtr = SenseData; 4603 4604 for (Index = 0; Index < SenseCounts; Index++) { 4605 4606 // 4607 // Sense Key is SK_NO_SENSE (0x0) 4608 // 4609 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) && 4610 (Index == 0)) { 4611 HaveSenseKey = FALSE; 4612 } 4613 4614 SensePtr++; 4615 } 4616 4617 return HaveSenseKey; 4618 } 4619 4620 /** 4621 Release resource about disk device. 4622 4623 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV 4624 4625 **/ 4626 VOID 4627 ReleaseScsiDiskDeviceResources ( 4628 IN SCSI_DISK_DEV *ScsiDiskDevice 4629 ) 4630 { 4631 if (ScsiDiskDevice == NULL) { 4632 return ; 4633 } 4634 4635 if (ScsiDiskDevice->SenseData != NULL) { 4636 FreePool (ScsiDiskDevice->SenseData); 4637 ScsiDiskDevice->SenseData = NULL; 4638 } 4639 4640 if (ScsiDiskDevice->ControllerNameTable != NULL) { 4641 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable); 4642 ScsiDiskDevice->ControllerNameTable = NULL; 4643 } 4644 4645 FreePool (ScsiDiskDevice); 4646 4647 ScsiDiskDevice = NULL; 4648 } 4649 4650 /** 4651 Determine if Block Io & Block Io2 should be produced. 4652 4653 4654 @param ChildHandle Child Handle to retrieve Parent information. 4655 4656 @retval TRUE Should produce Block Io & Block Io2. 4657 @retval FALSE Should not produce Block Io & Block Io2. 4658 4659 **/ 4660 BOOLEAN 4661 DetermineInstallBlockIo ( 4662 IN EFI_HANDLE ChildHandle 4663 ) 4664 { 4665 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru; 4666 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru; 4667 4668 // 4669 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence, 4670 // check its attribute, logic or physical. 4671 // 4672 ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle); 4673 if (ExtScsiPassThru != NULL) { 4674 if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) { 4675 return TRUE; 4676 } 4677 } 4678 4679 // 4680 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence, 4681 // check its attribute, logic or physical. 4682 // 4683 ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle); 4684 if (ScsiPassThru != NULL) { 4685 if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) { 4686 return TRUE; 4687 } 4688 } 4689 4690 return FALSE; 4691 } 4692 4693 /** 4694 Search protocol database and check to see if the protocol 4695 specified by ProtocolGuid is present on a ControllerHandle and opened by 4696 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. 4697 If the ControllerHandle is found, then the protocol specified by ProtocolGuid 4698 will be opened on it. 4699 4700 4701 @param ProtocolGuid ProtocolGuid pointer. 4702 @param ChildHandle Child Handle to retrieve Parent information. 4703 4704 **/ 4705 VOID * 4706 EFIAPI 4707 GetParentProtocol ( 4708 IN EFI_GUID *ProtocolGuid, 4709 IN EFI_HANDLE ChildHandle 4710 ) 4711 { 4712 UINTN Index; 4713 UINTN HandleCount; 4714 VOID *Interface; 4715 EFI_STATUS Status; 4716 EFI_HANDLE *HandleBuffer; 4717 4718 // 4719 // Retrieve the list of all handles from the handle database 4720 // 4721 Status = gBS->LocateHandleBuffer ( 4722 ByProtocol, 4723 ProtocolGuid, 4724 NULL, 4725 &HandleCount, 4726 &HandleBuffer 4727 ); 4728 4729 if (EFI_ERROR (Status)) { 4730 return NULL; 4731 } 4732 4733 // 4734 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle 4735 // 4736 for (Index = 0; Index < HandleCount; Index++) { 4737 Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid); 4738 if (!EFI_ERROR (Status)) { 4739 Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface); 4740 if (!EFI_ERROR (Status)) { 4741 gBS->FreePool (HandleBuffer); 4742 return Interface; 4743 } 4744 } 4745 } 4746 4747 gBS->FreePool (HandleBuffer); 4748 return NULL; 4749 } 4750 4751 /** 4752 Provides inquiry information for the controller type. 4753 4754 This function is used by the IDE bus driver to get inquiry data. Data format 4755 of Identify data is defined by the Interface GUID. 4756 4757 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance. 4758 @param[in, out] InquiryData Pointer to a buffer for the inquiry data. 4759 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size. 4760 4761 @retval EFI_SUCCESS The command was accepted without any errors. 4762 @retval EFI_NOT_FOUND Device does not support this data class 4763 @retval EFI_DEVICE_ERROR Error reading InquiryData from device 4764 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough 4765 4766 **/ 4767 EFI_STATUS 4768 EFIAPI 4769 ScsiDiskInfoInquiry ( 4770 IN EFI_DISK_INFO_PROTOCOL *This, 4771 IN OUT VOID *InquiryData, 4772 IN OUT UINT32 *InquiryDataSize 4773 ) 4774 { 4775 EFI_STATUS Status; 4776 SCSI_DISK_DEV *ScsiDiskDevice; 4777 4778 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This); 4779 4780 Status = EFI_BUFFER_TOO_SMALL; 4781 if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) { 4782 Status = EFI_SUCCESS; 4783 CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData)); 4784 } 4785 *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData); 4786 return Status; 4787 } 4788 4789 4790 /** 4791 Provides identify information for the controller type. 4792 4793 This function is used by the IDE bus driver to get identify data. Data format 4794 of Identify data is defined by the Interface GUID. 4795 4796 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL 4797 instance. 4798 @param[in, out] IdentifyData Pointer to a buffer for the identify data. 4799 @param[in, out] IdentifyDataSize Pointer to the value for the identify data 4800 size. 4801 4802 @retval EFI_SUCCESS The command was accepted without any errors. 4803 @retval EFI_NOT_FOUND Device does not support this data class 4804 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device 4805 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough 4806 4807 **/ 4808 EFI_STATUS 4809 EFIAPI 4810 ScsiDiskInfoIdentify ( 4811 IN EFI_DISK_INFO_PROTOCOL *This, 4812 IN OUT VOID *IdentifyData, 4813 IN OUT UINT32 *IdentifyDataSize 4814 ) 4815 { 4816 EFI_STATUS Status; 4817 SCSI_DISK_DEV *ScsiDiskDevice; 4818 4819 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) { 4820 // 4821 // Physical SCSI bus does not support this data class. 4822 // 4823 return EFI_NOT_FOUND; 4824 } 4825 4826 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This); 4827 4828 Status = EFI_BUFFER_TOO_SMALL; 4829 if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) { 4830 Status = EFI_SUCCESS; 4831 CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData)); 4832 } 4833 *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData); 4834 return Status; 4835 } 4836 4837 /** 4838 Provides sense data information for the controller type. 4839 4840 This function is used by the IDE bus driver to get sense data. 4841 Data format of Sense data is defined by the Interface GUID. 4842 4843 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance. 4844 @param[in, out] SenseData Pointer to the SenseData. 4845 @param[in, out] SenseDataSize Size of SenseData in bytes. 4846 @param[out] SenseDataNumber Pointer to the value for the sense data size. 4847 4848 @retval EFI_SUCCESS The command was accepted without any errors. 4849 @retval EFI_NOT_FOUND Device does not support this data class. 4850 @retval EFI_DEVICE_ERROR Error reading SenseData from device. 4851 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough. 4852 4853 **/ 4854 EFI_STATUS 4855 EFIAPI 4856 ScsiDiskInfoSenseData ( 4857 IN EFI_DISK_INFO_PROTOCOL *This, 4858 IN OUT VOID *SenseData, 4859 IN OUT UINT32 *SenseDataSize, 4860 OUT UINT8 *SenseDataNumber 4861 ) 4862 { 4863 return EFI_NOT_FOUND; 4864 } 4865 4866 4867 /** 4868 This function is used by the IDE bus driver to get controller information. 4869 4870 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance. 4871 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary. 4872 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave. 4873 4874 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid. 4875 @retval EFI_UNSUPPORTED This is not an IDE device. 4876 4877 **/ 4878 EFI_STATUS 4879 EFIAPI 4880 ScsiDiskInfoWhichIde ( 4881 IN EFI_DISK_INFO_PROTOCOL *This, 4882 OUT UINT32 *IdeChannel, 4883 OUT UINT32 *IdeDevice 4884 ) 4885 { 4886 SCSI_DISK_DEV *ScsiDiskDevice; 4887 4888 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) { 4889 // 4890 // This is not an IDE physical device. 4891 // 4892 return EFI_UNSUPPORTED; 4893 } 4894 4895 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This); 4896 *IdeChannel = ScsiDiskDevice->Channel; 4897 *IdeDevice = ScsiDiskDevice->Device; 4898 4899 return EFI_SUCCESS; 4900 } 4901 4902 4903 /** 4904 Issues ATA IDENTIFY DEVICE command to identify ATAPI device. 4905 4906 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to 4907 implement Identify() interface for DiskInfo protocol. The ATA command is sent 4908 via SCSI Request Packet. 4909 4910 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV 4911 4912 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully. 4913 @retval others Some error occurred during the identification that ATAPI device. 4914 4915 **/ 4916 EFI_STATUS 4917 AtapiIdentifyDevice ( 4918 IN OUT SCSI_DISK_DEV *ScsiDiskDevice 4919 ) 4920 { 4921 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket; 4922 UINT8 Cdb[6]; 4923 4924 // 4925 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb 4926 // 4927 ZeroMem (&CommandPacket, sizeof (CommandPacket)); 4928 ZeroMem (Cdb, sizeof (Cdb)); 4929 4930 Cdb[0] = ATA_CMD_IDENTIFY_DEVICE; 4931 CommandPacket.Timeout = SCSI_DISK_TIMEOUT; 4932 CommandPacket.Cdb = Cdb; 4933 CommandPacket.CdbLength = (UINT8) sizeof (Cdb); 4934 CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData; 4935 CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData); 4936 4937 return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL); 4938 } 4939 4940 4941 /** 4942 Initialize the installation of DiskInfo protocol. 4943 4944 This function prepares for the installation of DiskInfo protocol on the child handle. 4945 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further 4946 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID 4947 to be IDE/AHCI interface GUID. 4948 4949 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV. 4950 @param ChildHandle Child handle to install DiskInfo protocol. 4951 4952 **/ 4953 VOID 4954 InitializeInstallDiskInfo ( 4955 IN SCSI_DISK_DEV *ScsiDiskDevice, 4956 IN EFI_HANDLE ChildHandle 4957 ) 4958 { 4959 EFI_STATUS Status; 4960 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; 4961 EFI_DEVICE_PATH_PROTOCOL *ChildDevicePathNode; 4962 ATAPI_DEVICE_PATH *AtapiDevicePath; 4963 SATA_DEVICE_PATH *SataDevicePath; 4964 UINTN IdentifyRetry; 4965 4966 Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePathNode); 4967 // 4968 // Device Path protocol must be installed on the device handle. 4969 // 4970 ASSERT_EFI_ERROR (Status); 4971 // 4972 // Copy the DiskInfo protocol template. 4973 // 4974 CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate)); 4975 4976 while (!IsDevicePathEnd (DevicePathNode)) { 4977 ChildDevicePathNode = NextDevicePathNode (DevicePathNode); 4978 if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) && 4979 (DevicePathSubType (DevicePathNode) == HW_PCI_DP) && 4980 (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) && 4981 ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) || 4982 (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP))) { 4983 4984 IdentifyRetry = 3; 4985 do { 4986 // 4987 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol 4988 // with IDE/AHCI interface GUID. 4989 // 4990 Status = AtapiIdentifyDevice (ScsiDiskDevice); 4991 if (!EFI_ERROR (Status)) { 4992 if (DevicePathSubType(ChildDevicePathNode) == MSG_ATAPI_DP) { 4993 // 4994 // We find the valid ATAPI device path 4995 // 4996 AtapiDevicePath = (ATAPI_DEVICE_PATH *) ChildDevicePathNode; 4997 ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary; 4998 ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster; 4999 // 5000 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device. 5001 // 5002 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid); 5003 } else { 5004 // 5005 // We find the valid SATA device path 5006 // 5007 SataDevicePath = (SATA_DEVICE_PATH *) ChildDevicePathNode; 5008 ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber; 5009 ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber; 5010 // 5011 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device. 5012 // 5013 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid); 5014 } 5015 return; 5016 } 5017 } while (--IdentifyRetry > 0); 5018 } else if ((DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) && 5019 (DevicePathSubType (ChildDevicePathNode) == MSG_UFS_DP)) { 5020 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoUfsInterfaceGuid); 5021 break; 5022 } 5023 DevicePathNode = ChildDevicePathNode; 5024 } 5025 5026 return; 5027 } 5028