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