2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 1985 - 2022, American Megatrends International LLC.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
12 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding
= {
13 ScsiDiskDriverBindingSupported
,
14 ScsiDiskDriverBindingStart
,
15 ScsiDiskDriverBindingStop
,
21 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate
= {
22 EFI_DISK_INFO_SCSI_INTERFACE_GUID
,
25 ScsiDiskInfoSenseData
,
30 Allocates an aligned buffer for SCSI disk.
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.
35 @param ScsiDiskDevice The SCSI disk involved for the operation.
36 @param BufferSize The request buffer size.
38 @return A pointer to the aligned buffer or NULL if the allocation fails.
42 AllocateAlignedBuffer (
43 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
47 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), ScsiDiskDevice
->ScsiIo
->IoAlign
);
51 Frees an aligned buffer for SCSI disk.
53 This function frees an aligned buffer for the SCSI disk to perform
56 @param Buffer The aligned buffer to be freed.
57 @param BufferSize The request buffer size.
67 FreeAlignedPages (Buffer
, EFI_SIZE_TO_PAGES (BufferSize
));
72 Remove trailing spaces from the string.
74 @param String The ASCII string to remove the trailing spaces.
76 @retval the new length of the string.
79 RemoveTrailingSpaces (
85 Length
= AsciiStrLen (String
);
90 while ((Length
> 0) && (String
[Length
-1] == ' ')) {
94 String
[Length
] = '\0';
99 The user Entry Point for module ScsiDisk.
101 The user code starts with this function.
103 @param ImageHandle The firmware allocated handle for the EFI image.
104 @param SystemTable A pointer to the EFI System Table.
106 @retval EFI_SUCCESS The entry point is executed successfully.
107 @retval other Some error occurs when executing this entry point.
113 IN EFI_HANDLE ImageHandle
,
114 IN EFI_SYSTEM_TABLE
*SystemTable
120 // Install driver model protocol(s).
122 Status
= EfiLibInstallDriverBindingComponentName2 (
125 &gScsiDiskDriverBinding
,
127 &gScsiDiskComponentName
,
128 &gScsiDiskComponentName2
130 ASSERT_EFI_ERROR (Status
);
136 Test to see if this driver supports ControllerHandle.
138 This service is called by the EFI boot service ConnectController(). In order
139 to make drivers as small as possible, there are a few calling restrictions for
140 this service. ConnectController() must follow these calling restrictions.
141 If any other agent wishes to call Supported() it must also follow these
142 calling restrictions.
144 @param This Protocol instance pointer.
145 @param ControllerHandle Handle of device to test
146 @param RemainingDevicePath Optional parameter use to pick a specific child
149 @retval EFI_SUCCESS This driver supports this device
150 @retval EFI_ALREADY_STARTED This driver is already running on this device
151 @retval other This driver does not support this device
156 ScsiDiskDriverBindingSupported (
157 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
158 IN EFI_HANDLE Controller
,
159 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
163 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
166 Status
= gBS
->OpenProtocol (
168 &gEfiScsiIoProtocolGuid
,
170 This
->DriverBindingHandle
,
172 EFI_OPEN_PROTOCOL_BY_DRIVER
174 if (EFI_ERROR (Status
)) {
178 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
179 if (!EFI_ERROR (Status
)) {
180 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) ||
181 (DeviceType
== EFI_SCSI_TYPE_CDROM
) ||
182 (DeviceType
== EFI_SCSI_TYPE_WLUN
))
184 Status
= EFI_SUCCESS
;
186 Status
= EFI_UNSUPPORTED
;
192 &gEfiScsiIoProtocolGuid
,
193 This
->DriverBindingHandle
,
200 Start this driver on ControllerHandle.
202 This service is called by the EFI boot service ConnectController(). In order
203 to make drivers as small as possible, there are a few calling restrictions for
204 this service. ConnectController() must follow these calling restrictions. If
205 any other agent wishes to call Start() it must also follow these calling
208 @param This Protocol instance pointer.
209 @param ControllerHandle Handle of device to bind driver to
210 @param RemainingDevicePath Optional parameter use to pick a specific child
213 @retval EFI_SUCCESS This driver is added to ControllerHandle
214 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
215 @retval other This driver does not support this device
220 ScsiDiskDriverBindingStart (
221 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
222 IN EFI_HANDLE Controller
,
223 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
227 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
228 SCSI_DISK_DEV
*ScsiDiskDevice
;
233 BOOLEAN MustReadCapacity
;
234 CHAR8 VendorStr
[VENDOR_IDENTIFICATION_LENGTH
+ 1];
235 CHAR8 ProductStr
[PRODUCT_IDENTIFICATION_LENGTH
+ 1];
236 CHAR16 DeviceStr
[VENDOR_IDENTIFICATION_LENGTH
+ PRODUCT_IDENTIFICATION_LENGTH
+ 2];
238 MustReadCapacity
= TRUE
;
240 ScsiDiskDevice
= (SCSI_DISK_DEV
*)AllocateZeroPool (sizeof (SCSI_DISK_DEV
));
241 if (ScsiDiskDevice
== NULL
) {
242 return EFI_OUT_OF_RESOURCES
;
245 Status
= gBS
->OpenProtocol (
247 &gEfiScsiIoProtocolGuid
,
249 This
->DriverBindingHandle
,
251 EFI_OPEN_PROTOCOL_BY_DRIVER
253 if (EFI_ERROR (Status
)) {
254 FreePool (ScsiDiskDevice
);
258 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
259 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
260 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION3
;
261 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
262 ScsiDiskDevice
->BlkIo
.Media
->IoAlign
= ScsiIo
->IoAlign
;
263 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
264 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
265 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
266 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
267 ScsiDiskDevice
->BlkIo2
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
268 ScsiDiskDevice
->BlkIo2
.Reset
= ScsiDiskResetEx
;
269 ScsiDiskDevice
->BlkIo2
.ReadBlocksEx
= ScsiDiskReadBlocksEx
;
270 ScsiDiskDevice
->BlkIo2
.WriteBlocksEx
= ScsiDiskWriteBlocksEx
;
271 ScsiDiskDevice
->BlkIo2
.FlushBlocksEx
= ScsiDiskFlushBlocksEx
;
272 ScsiDiskDevice
->StorageSecurity
.ReceiveData
= ScsiDiskReceiveData
;
273 ScsiDiskDevice
->StorageSecurity
.SendData
= ScsiDiskSendData
;
274 ScsiDiskDevice
->EraseBlock
.Revision
= EFI_ERASE_BLOCK_PROTOCOL_REVISION
;
275 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
= 1;
276 ScsiDiskDevice
->EraseBlock
.EraseBlocks
= ScsiDiskEraseBlocks
;
277 ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
= 1;
278 ScsiDiskDevice
->BlockLimitsVpdSupported
= FALSE
;
279 ScsiDiskDevice
->Handle
= Controller
;
280 InitializeListHead (&ScsiDiskDevice
->AsyncTaskQueue
);
282 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
283 switch (ScsiDiskDevice
->DeviceType
) {
284 case EFI_SCSI_TYPE_DISK
:
285 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
286 MustReadCapacity
= TRUE
;
289 case EFI_SCSI_TYPE_CDROM
:
290 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
291 ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
= TRUE
;
292 MustReadCapacity
= FALSE
;
295 case EFI_SCSI_TYPE_WLUN
:
296 MustReadCapacity
= FALSE
;
301 // The Sense Data Array's initial size is 6
303 ScsiDiskDevice
->SenseDataNumber
= 6;
304 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*)AllocateZeroPool (
305 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
307 if (ScsiDiskDevice
->SenseData
== NULL
) {
310 &gEfiScsiIoProtocolGuid
,
311 This
->DriverBindingHandle
,
314 FreePool (ScsiDiskDevice
);
315 return EFI_OUT_OF_RESOURCES
;
319 // Retrieve device information
322 for (Index
= 0; Index
< MaxRetry
; Index
++) {
323 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
324 if (!EFI_ERROR (Status
)) {
329 FreePool (ScsiDiskDevice
->SenseData
);
332 &gEfiScsiIoProtocolGuid
,
333 This
->DriverBindingHandle
,
336 FreePool (ScsiDiskDevice
);
337 return EFI_DEVICE_ERROR
;
342 // The second parameter "TRUE" means must
343 // retrieve media capacity
345 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, MustReadCapacity
, &Temp
);
346 if (!EFI_ERROR (Status
)) {
348 // Determine if Block IO & Block IO2 should be produced on this controller
351 if (DetermineInstallBlockIo (Controller
)) {
352 InitializeInstallDiskInfo (ScsiDiskDevice
, Controller
);
353 Status
= gBS
->InstallMultipleProtocolInterfaces (
355 &gEfiBlockIoProtocolGuid
,
356 &ScsiDiskDevice
->BlkIo
,
357 &gEfiBlockIo2ProtocolGuid
,
358 &ScsiDiskDevice
->BlkIo2
,
359 &gEfiDiskInfoProtocolGuid
,
360 &ScsiDiskDevice
->DiskInfo
,
363 if (!EFI_ERROR (Status
)) {
364 if (DetermineInstallEraseBlock (ScsiDiskDevice
, Controller
)) {
365 Status
= gBS
->InstallProtocolInterface (
367 &gEfiEraseBlockProtocolGuid
,
368 EFI_NATIVE_INTERFACE
,
369 &ScsiDiskDevice
->EraseBlock
371 if (EFI_ERROR (Status
)) {
372 DEBUG ((DEBUG_ERROR
, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", Status
));
376 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, Controller
)) {
377 Status
= gBS
->InstallProtocolInterface (
379 &gEfiStorageSecurityCommandProtocolGuid
,
380 EFI_NATIVE_INTERFACE
,
381 &ScsiDiskDevice
->StorageSecurity
383 if (EFI_ERROR (Status
)) {
384 DEBUG ((DEBUG_ERROR
, "ScsiDisk: Failed to install the Storage Security Command Protocol! Status = %r\n", Status
));
390 &ScsiDiskDevice
->InquiryData
.Reserved_5_95
[VENDOR_IDENTIFICATION_OFFSET
],
391 VENDOR_IDENTIFICATION_LENGTH
393 VendorStr
[VENDOR_IDENTIFICATION_LENGTH
] = 0;
394 RemoveTrailingSpaces (VendorStr
);
398 &ScsiDiskDevice
->InquiryData
.Reserved_5_95
[PRODUCT_IDENTIFICATION_OFFSET
],
399 PRODUCT_IDENTIFICATION_LENGTH
401 ProductStr
[PRODUCT_IDENTIFICATION_LENGTH
] = 0;
402 RemoveTrailingSpaces (ProductStr
);
404 UnicodeSPrint (DeviceStr
, sizeof (DeviceStr
), L
"%a %a", VendorStr
, ProductStr
);
406 ScsiDiskDevice
->ControllerNameTable
= NULL
;
409 gScsiDiskComponentName
.SupportedLanguages
,
410 &ScsiDiskDevice
->ControllerNameTable
,
416 gScsiDiskComponentName2
.SupportedLanguages
,
417 &ScsiDiskDevice
->ControllerNameTable
,
426 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
427 gBS
->FreePool (ScsiDiskDevice
);
430 &gEfiScsiIoProtocolGuid
,
431 This
->DriverBindingHandle
,
438 Stop this driver on ControllerHandle.
440 This service is called by the EFI boot service DisconnectController().
441 In order to make drivers as small as possible, there are a few calling
442 restrictions for this service. DisconnectController() must follow these
443 calling restrictions. If any other agent wishes to call Stop() it must
444 also follow these calling restrictions.
446 @param This Protocol instance pointer.
447 @param ControllerHandle Handle of device to stop driver on
448 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
449 children is zero stop the entire bus driver.
450 @param ChildHandleBuffer List of Child Handles to Stop.
452 @retval EFI_SUCCESS This driver is removed ControllerHandle
453 @retval other This driver was not removed from this device
458 ScsiDiskDriverBindingStop (
459 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
460 IN EFI_HANDLE Controller
,
461 IN UINTN NumberOfChildren
,
462 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
465 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
466 EFI_ERASE_BLOCK_PROTOCOL
*EraseBlock
;
467 SCSI_DISK_DEV
*ScsiDiskDevice
;
470 Status
= gBS
->OpenProtocol (
472 &gEfiBlockIoProtocolGuid
,
474 This
->DriverBindingHandle
,
476 EFI_OPEN_PROTOCOL_GET_PROTOCOL
478 if (EFI_ERROR (Status
)) {
482 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (BlkIo
);
485 // Wait for the BlockIo2 requests queue to become empty
487 while (!IsListEmpty (&ScsiDiskDevice
->AsyncTaskQueue
)) {
491 // If Erase Block Protocol is installed, then uninstall this protocol.
493 Status
= gBS
->OpenProtocol (
495 &gEfiEraseBlockProtocolGuid
,
496 (VOID
**)&EraseBlock
,
497 This
->DriverBindingHandle
,
499 EFI_OPEN_PROTOCOL_GET_PROTOCOL
502 if (!EFI_ERROR (Status
)) {
503 Status
= gBS
->UninstallProtocolInterface (
505 &gEfiEraseBlockProtocolGuid
,
506 &ScsiDiskDevice
->EraseBlock
508 if (EFI_ERROR (Status
)) {
513 Status
= gBS
->UninstallMultipleProtocolInterfaces (
515 &gEfiBlockIoProtocolGuid
,
516 &ScsiDiskDevice
->BlkIo
,
517 &gEfiBlockIo2ProtocolGuid
,
518 &ScsiDiskDevice
->BlkIo2
,
519 &gEfiDiskInfoProtocolGuid
,
520 &ScsiDiskDevice
->DiskInfo
,
523 if (!EFI_ERROR (Status
)) {
526 &gEfiScsiIoProtocolGuid
,
527 This
->DriverBindingHandle
,
531 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
546 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
547 @param ExtendedVerification The flag about if extend verificate
549 @retval EFI_SUCCESS The device was reset.
550 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
552 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
558 IN EFI_BLOCK_IO_PROTOCOL
*This
,
559 IN BOOLEAN ExtendedVerification
563 SCSI_DISK_DEV
*ScsiDiskDevice
;
566 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
568 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
570 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
572 if (EFI_ERROR (Status
)) {
573 if (Status
== EFI_UNSUPPORTED
) {
574 Status
= EFI_SUCCESS
;
576 Status
= EFI_DEVICE_ERROR
;
581 if (!ExtendedVerification
) {
585 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
587 if (EFI_ERROR (Status
)) {
588 Status
= EFI_DEVICE_ERROR
;
593 gBS
->RestoreTPL (OldTpl
);
598 The function is to Read Block from SCSI Disk.
600 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
601 @param MediaId The Id of Media detected
602 @param Lba The logic block address
603 @param BufferSize The size of Buffer
604 @param Buffer The buffer to fill the read out data
606 @retval EFI_SUCCESS Successfully to read out block.
607 @retval EFI_DEVICE_ERROR Fail to detect media.
608 @retval EFI_NO_MEDIA Media is not present.
609 @retval EFI_MEDIA_CHANGED Media has changed.
610 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
611 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
617 IN EFI_BLOCK_IO_PROTOCOL
*This
,
624 SCSI_DISK_DEV
*ScsiDiskDevice
;
625 EFI_BLOCK_IO_MEDIA
*Media
;
628 UINTN NumberOfBlocks
;
633 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
634 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
635 Media
= ScsiDiskDevice
->BlkIo
.Media
;
637 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
638 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
639 if (EFI_ERROR (Status
)) {
640 Status
= EFI_DEVICE_ERROR
;
645 gBS
->ReinstallProtocolInterface (
646 ScsiDiskDevice
->Handle
,
647 &gEfiBlockIoProtocolGuid
,
648 &ScsiDiskDevice
->BlkIo
,
649 &ScsiDiskDevice
->BlkIo
651 gBS
->ReinstallProtocolInterface (
652 ScsiDiskDevice
->Handle
,
653 &gEfiBlockIo2ProtocolGuid
,
654 &ScsiDiskDevice
->BlkIo2
,
655 &ScsiDiskDevice
->BlkIo2
657 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
658 gBS
->ReinstallProtocolInterface (
659 ScsiDiskDevice
->Handle
,
660 &gEfiEraseBlockProtocolGuid
,
661 &ScsiDiskDevice
->EraseBlock
,
662 &ScsiDiskDevice
->EraseBlock
666 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
667 gBS
->ReinstallProtocolInterface (
668 ScsiDiskDevice
->Handle
,
669 &gEfiStorageSecurityCommandProtocolGuid
,
670 &ScsiDiskDevice
->StorageSecurity
,
671 &ScsiDiskDevice
->StorageSecurity
675 if (Media
->MediaPresent
) {
676 Status
= EFI_MEDIA_CHANGED
;
678 Status
= EFI_NO_MEDIA
;
686 // Get the intrinsic block size
688 BlockSize
= Media
->BlockSize
;
690 if (BlockSize
== 0) {
691 Status
= EFI_DEVICE_ERROR
;
695 NumberOfBlocks
= BufferSize
/ BlockSize
;
697 if (!(Media
->MediaPresent
)) {
698 Status
= EFI_NO_MEDIA
;
702 if (MediaId
!= Media
->MediaId
) {
703 Status
= EFI_MEDIA_CHANGED
;
707 if (Buffer
== NULL
) {
708 Status
= EFI_INVALID_PARAMETER
;
712 if (BufferSize
== 0) {
713 Status
= EFI_SUCCESS
;
717 if (BufferSize
% BlockSize
!= 0) {
718 Status
= EFI_BAD_BUFFER_SIZE
;
722 if (Lba
> Media
->LastBlock
) {
723 Status
= EFI_INVALID_PARAMETER
;
727 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
728 Status
= EFI_INVALID_PARAMETER
;
732 if ((Media
->IoAlign
> 1) && (((UINTN
)Buffer
& (Media
->IoAlign
- 1)) != 0)) {
733 Status
= EFI_INVALID_PARAMETER
;
738 // If all the parameters are valid, then perform read sectors command
739 // to transfer data from device to host.
741 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
744 gBS
->RestoreTPL (OldTpl
);
749 The function is to Write Block to SCSI Disk.
751 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
752 @param MediaId The Id of Media detected
753 @param Lba The logic block address
754 @param BufferSize The size of Buffer
755 @param Buffer The buffer to fill the read out data
757 @retval EFI_SUCCESS Successfully to read out block.
758 @retval EFI_WRITE_PROTECTED The device can not be written to.
759 @retval EFI_DEVICE_ERROR Fail to detect media.
760 @retval EFI_NO_MEDIA Media is not present.
761 @retval EFI_MEDIA_CHANGED Media has changed.
762 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
763 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
768 ScsiDiskWriteBlocks (
769 IN EFI_BLOCK_IO_PROTOCOL
*This
,
776 SCSI_DISK_DEV
*ScsiDiskDevice
;
777 EFI_BLOCK_IO_MEDIA
*Media
;
780 UINTN NumberOfBlocks
;
785 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
786 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
787 Media
= ScsiDiskDevice
->BlkIo
.Media
;
789 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
790 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
791 if (EFI_ERROR (Status
)) {
792 Status
= EFI_DEVICE_ERROR
;
797 gBS
->ReinstallProtocolInterface (
798 ScsiDiskDevice
->Handle
,
799 &gEfiBlockIoProtocolGuid
,
800 &ScsiDiskDevice
->BlkIo
,
801 &ScsiDiskDevice
->BlkIo
803 gBS
->ReinstallProtocolInterface (
804 ScsiDiskDevice
->Handle
,
805 &gEfiBlockIo2ProtocolGuid
,
806 &ScsiDiskDevice
->BlkIo2
,
807 &ScsiDiskDevice
->BlkIo2
809 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
810 gBS
->ReinstallProtocolInterface (
811 ScsiDiskDevice
->Handle
,
812 &gEfiEraseBlockProtocolGuid
,
813 &ScsiDiskDevice
->EraseBlock
,
814 &ScsiDiskDevice
->EraseBlock
818 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
819 gBS
->ReinstallProtocolInterface (
820 ScsiDiskDevice
->Handle
,
821 &gEfiStorageSecurityCommandProtocolGuid
,
822 &ScsiDiskDevice
->StorageSecurity
,
823 &ScsiDiskDevice
->StorageSecurity
827 if (Media
->MediaPresent
) {
828 Status
= EFI_MEDIA_CHANGED
;
830 Status
= EFI_NO_MEDIA
;
838 // Get the intrinsic block size
840 BlockSize
= Media
->BlockSize
;
842 if (BlockSize
== 0) {
843 Status
= EFI_DEVICE_ERROR
;
847 NumberOfBlocks
= BufferSize
/ BlockSize
;
849 if (!(Media
->MediaPresent
)) {
850 Status
= EFI_NO_MEDIA
;
854 if (MediaId
!= Media
->MediaId
) {
855 Status
= EFI_MEDIA_CHANGED
;
859 if (Media
->ReadOnly
) {
860 Status
= EFI_WRITE_PROTECTED
;
864 if (BufferSize
== 0) {
865 Status
= EFI_SUCCESS
;
869 if (Buffer
== NULL
) {
870 Status
= EFI_INVALID_PARAMETER
;
874 if (BufferSize
% BlockSize
!= 0) {
875 Status
= EFI_BAD_BUFFER_SIZE
;
879 if (Lba
> Media
->LastBlock
) {
880 Status
= EFI_INVALID_PARAMETER
;
884 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
885 Status
= EFI_INVALID_PARAMETER
;
889 if ((Media
->IoAlign
> 1) && (((UINTN
)Buffer
& (Media
->IoAlign
- 1)) != 0)) {
890 Status
= EFI_INVALID_PARAMETER
;
895 // if all the parameters are valid, then perform read sectors command
896 // to transfer data from device to host.
898 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
901 gBS
->RestoreTPL (OldTpl
);
908 EFI_SUCCESS is returned directly.
910 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
912 @retval EFI_SUCCESS All outstanding data was written to the device
917 ScsiDiskFlushBlocks (
918 IN EFI_BLOCK_IO_PROTOCOL
*This
930 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
931 @param ExtendedVerification The flag about if extend verificate.
933 @retval EFI_SUCCESS The device was reset.
934 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
936 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
942 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
943 IN BOOLEAN ExtendedVerification
947 SCSI_DISK_DEV
*ScsiDiskDevice
;
950 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
952 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
954 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
956 if (EFI_ERROR (Status
)) {
957 if (Status
== EFI_UNSUPPORTED
) {
958 Status
= EFI_SUCCESS
;
960 Status
= EFI_DEVICE_ERROR
;
965 if (!ExtendedVerification
) {
969 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
971 if (EFI_ERROR (Status
)) {
972 Status
= EFI_DEVICE_ERROR
;
977 gBS
->RestoreTPL (OldTpl
);
982 The function is to Read Block from SCSI Disk.
984 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
985 @param MediaId The Id of Media detected.
986 @param Lba The logic block address.
987 @param Token A pointer to the token associated with the transaction.
988 @param BufferSize The size of Buffer.
989 @param Buffer The buffer to fill the read out data.
991 @retval EFI_SUCCESS The read request was queued if Token-> Event is
992 not NULL. The data was read correctly from the
993 device if theToken-> Event is NULL.
994 @retval EFI_DEVICE_ERROR The device reported an error while attempting
995 to perform the read operation.
996 @retval EFI_NO_MEDIA There is no media in the device.
997 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
998 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
999 the intrinsic block size of the device.
1000 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
1001 valid, or the buffer is not on proper
1003 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
1009 ScsiDiskReadBlocksEx (
1010 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1013 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1014 IN UINTN BufferSize
,
1018 SCSI_DISK_DEV
*ScsiDiskDevice
;
1019 EFI_BLOCK_IO_MEDIA
*Media
;
1022 UINTN NumberOfBlocks
;
1023 BOOLEAN MediaChange
;
1026 MediaChange
= FALSE
;
1027 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1028 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1029 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1031 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
1032 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1033 if (EFI_ERROR (Status
)) {
1034 Status
= EFI_DEVICE_ERROR
;
1039 gBS
->ReinstallProtocolInterface (
1040 ScsiDiskDevice
->Handle
,
1041 &gEfiBlockIoProtocolGuid
,
1042 &ScsiDiskDevice
->BlkIo
,
1043 &ScsiDiskDevice
->BlkIo
1045 gBS
->ReinstallProtocolInterface (
1046 ScsiDiskDevice
->Handle
,
1047 &gEfiBlockIo2ProtocolGuid
,
1048 &ScsiDiskDevice
->BlkIo2
,
1049 &ScsiDiskDevice
->BlkIo2
1051 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1052 gBS
->ReinstallProtocolInterface (
1053 ScsiDiskDevice
->Handle
,
1054 &gEfiEraseBlockProtocolGuid
,
1055 &ScsiDiskDevice
->EraseBlock
,
1056 &ScsiDiskDevice
->EraseBlock
1060 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1061 gBS
->ReinstallProtocolInterface (
1062 ScsiDiskDevice
->Handle
,
1063 &gEfiStorageSecurityCommandProtocolGuid
,
1064 &ScsiDiskDevice
->StorageSecurity
,
1065 &ScsiDiskDevice
->StorageSecurity
1069 if (Media
->MediaPresent
) {
1070 Status
= EFI_MEDIA_CHANGED
;
1072 Status
= EFI_NO_MEDIA
;
1080 // Get the intrinsic block size
1082 BlockSize
= Media
->BlockSize
;
1084 if (BlockSize
== 0) {
1085 Status
= EFI_DEVICE_ERROR
;
1089 NumberOfBlocks
= BufferSize
/ BlockSize
;
1091 if (!(Media
->MediaPresent
)) {
1092 Status
= EFI_NO_MEDIA
;
1096 if (MediaId
!= Media
->MediaId
) {
1097 Status
= EFI_MEDIA_CHANGED
;
1101 if (Buffer
== NULL
) {
1102 Status
= EFI_INVALID_PARAMETER
;
1106 if (BufferSize
== 0) {
1107 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1108 Token
->TransactionStatus
= EFI_SUCCESS
;
1109 gBS
->SignalEvent (Token
->Event
);
1112 Status
= EFI_SUCCESS
;
1116 if (BufferSize
% BlockSize
!= 0) {
1117 Status
= EFI_BAD_BUFFER_SIZE
;
1121 if (Lba
> Media
->LastBlock
) {
1122 Status
= EFI_INVALID_PARAMETER
;
1126 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1127 Status
= EFI_INVALID_PARAMETER
;
1131 if ((Media
->IoAlign
> 1) && (((UINTN
)Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1132 Status
= EFI_INVALID_PARAMETER
;
1137 // If all the parameters are valid, then perform read sectors command
1138 // to transfer data from device to host.
1140 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1141 Token
->TransactionStatus
= EFI_SUCCESS
;
1142 Status
= ScsiDiskAsyncReadSectors (
1150 Status
= ScsiDiskReadSectors (
1159 gBS
->RestoreTPL (OldTpl
);
1164 The function is to Write Block to SCSI Disk.
1166 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
1167 @param MediaId The Id of Media detected.
1168 @param Lba The logic block address.
1169 @param Token A pointer to the token associated with the transaction.
1170 @param BufferSize The size of Buffer.
1171 @param Buffer The buffer to fill the read out data.
1173 @retval EFI_SUCCESS The data were written correctly to the device.
1174 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1175 @retval EFI_NO_MEDIA There is no media in the device.
1176 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1177 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1178 to perform the write operation.
1179 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
1180 the intrinsic block size of the device.
1181 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
1182 valid, or the buffer is not on proper
1188 ScsiDiskWriteBlocksEx (
1189 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1192 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1193 IN UINTN BufferSize
,
1197 SCSI_DISK_DEV
*ScsiDiskDevice
;
1198 EFI_BLOCK_IO_MEDIA
*Media
;
1201 UINTN NumberOfBlocks
;
1202 BOOLEAN MediaChange
;
1205 MediaChange
= FALSE
;
1206 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1207 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1208 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1210 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
1211 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1212 if (EFI_ERROR (Status
)) {
1213 Status
= EFI_DEVICE_ERROR
;
1218 gBS
->ReinstallProtocolInterface (
1219 ScsiDiskDevice
->Handle
,
1220 &gEfiBlockIoProtocolGuid
,
1221 &ScsiDiskDevice
->BlkIo
,
1222 &ScsiDiskDevice
->BlkIo
1224 gBS
->ReinstallProtocolInterface (
1225 ScsiDiskDevice
->Handle
,
1226 &gEfiBlockIo2ProtocolGuid
,
1227 &ScsiDiskDevice
->BlkIo2
,
1228 &ScsiDiskDevice
->BlkIo2
1230 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1231 gBS
->ReinstallProtocolInterface (
1232 ScsiDiskDevice
->Handle
,
1233 &gEfiEraseBlockProtocolGuid
,
1234 &ScsiDiskDevice
->EraseBlock
,
1235 &ScsiDiskDevice
->EraseBlock
1239 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1240 gBS
->ReinstallProtocolInterface (
1241 ScsiDiskDevice
->Handle
,
1242 &gEfiStorageSecurityCommandProtocolGuid
,
1243 &ScsiDiskDevice
->StorageSecurity
,
1244 &ScsiDiskDevice
->StorageSecurity
1248 if (Media
->MediaPresent
) {
1249 Status
= EFI_MEDIA_CHANGED
;
1251 Status
= EFI_NO_MEDIA
;
1259 // Get the intrinsic block size
1261 BlockSize
= Media
->BlockSize
;
1263 if (BlockSize
== 0) {
1264 Status
= EFI_DEVICE_ERROR
;
1268 NumberOfBlocks
= BufferSize
/ BlockSize
;
1270 if (!(Media
->MediaPresent
)) {
1271 Status
= EFI_NO_MEDIA
;
1275 if (MediaId
!= Media
->MediaId
) {
1276 Status
= EFI_MEDIA_CHANGED
;
1280 if (Media
->ReadOnly
) {
1281 Status
= EFI_WRITE_PROTECTED
;
1285 if (BufferSize
== 0) {
1286 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1287 Token
->TransactionStatus
= EFI_SUCCESS
;
1288 gBS
->SignalEvent (Token
->Event
);
1291 Status
= EFI_SUCCESS
;
1295 if (Buffer
== NULL
) {
1296 Status
= EFI_INVALID_PARAMETER
;
1300 if (BufferSize
% BlockSize
!= 0) {
1301 Status
= EFI_BAD_BUFFER_SIZE
;
1305 if (Lba
> Media
->LastBlock
) {
1306 Status
= EFI_INVALID_PARAMETER
;
1310 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1311 Status
= EFI_INVALID_PARAMETER
;
1315 if ((Media
->IoAlign
> 1) && (((UINTN
)Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1316 Status
= EFI_INVALID_PARAMETER
;
1321 // if all the parameters are valid, then perform write sectors command
1322 // to transfer data from device to host.
1324 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1325 Token
->TransactionStatus
= EFI_SUCCESS
;
1326 Status
= ScsiDiskAsyncWriteSectors (
1334 Status
= ScsiDiskWriteSectors (
1343 gBS
->RestoreTPL (OldTpl
);
1348 Flush the Block Device.
1350 @param This Indicates a pointer to the calling context.
1351 @param Token A pointer to the token associated with the transaction.
1353 @retval EFI_SUCCESS All outstanding data was written to the device.
1354 @retval EFI_DEVICE_ERROR The device reported an error while attempting to
1356 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1357 @retval EFI_NO_MEDIA There is no media in the device.
1358 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1363 ScsiDiskFlushBlocksEx (
1364 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1365 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1368 SCSI_DISK_DEV
*ScsiDiskDevice
;
1369 EFI_BLOCK_IO_MEDIA
*Media
;
1371 BOOLEAN MediaChange
;
1374 MediaChange
= FALSE
;
1375 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1376 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1377 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1379 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
1380 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1381 if (EFI_ERROR (Status
)) {
1382 Status
= EFI_DEVICE_ERROR
;
1387 gBS
->ReinstallProtocolInterface (
1388 ScsiDiskDevice
->Handle
,
1389 &gEfiBlockIoProtocolGuid
,
1390 &ScsiDiskDevice
->BlkIo
,
1391 &ScsiDiskDevice
->BlkIo
1393 gBS
->ReinstallProtocolInterface (
1394 ScsiDiskDevice
->Handle
,
1395 &gEfiBlockIo2ProtocolGuid
,
1396 &ScsiDiskDevice
->BlkIo2
,
1397 &ScsiDiskDevice
->BlkIo2
1399 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1400 gBS
->ReinstallProtocolInterface (
1401 ScsiDiskDevice
->Handle
,
1402 &gEfiEraseBlockProtocolGuid
,
1403 &ScsiDiskDevice
->EraseBlock
,
1404 &ScsiDiskDevice
->EraseBlock
1408 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1409 gBS
->ReinstallProtocolInterface (
1410 ScsiDiskDevice
->Handle
,
1411 &gEfiStorageSecurityCommandProtocolGuid
,
1412 &ScsiDiskDevice
->StorageSecurity
,
1413 &ScsiDiskDevice
->StorageSecurity
1417 if (Media
->MediaPresent
) {
1418 Status
= EFI_MEDIA_CHANGED
;
1420 Status
= EFI_NO_MEDIA
;
1427 if (!(Media
->MediaPresent
)) {
1428 Status
= EFI_NO_MEDIA
;
1432 if (Media
->ReadOnly
) {
1433 Status
= EFI_WRITE_PROTECTED
;
1438 // Wait for the BlockIo2 requests queue to become empty
1440 while (!IsListEmpty (&ScsiDiskDevice
->AsyncTaskQueue
)) {
1443 Status
= EFI_SUCCESS
;
1446 // Signal caller event
1448 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1449 Token
->TransactionStatus
= EFI_SUCCESS
;
1450 gBS
->SignalEvent (Token
->Event
);
1454 gBS
->RestoreTPL (OldTpl
);
1459 Internal helper notify function which process the result of an asynchronous
1460 SCSI UNMAP Command and signal the event passed from EraseBlocks.
1462 @param Event The instance of EFI_EVENT.
1463 @param Context The parameter passed in.
1468 ScsiDiskAsyncUnmapNotify (
1473 SCSI_ERASEBLK_REQUEST
*EraseBlkReq
;
1474 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*CommandPacket
;
1475 EFI_ERASE_BLOCK_TOKEN
*Token
;
1478 gBS
->CloseEvent (Event
);
1480 EraseBlkReq
= (SCSI_ERASEBLK_REQUEST
*)Context
;
1481 CommandPacket
= &EraseBlkReq
->CommandPacket
;
1482 Token
= EraseBlkReq
->Token
;
1483 Token
->TransactionStatus
= EFI_SUCCESS
;
1485 Status
= CheckHostAdapterStatus (CommandPacket
->HostAdapterStatus
);
1486 if (EFI_ERROR (Status
)) {
1489 "ScsiDiskAsyncUnmapNotify: Host adapter indicating error status 0x%x.\n",
1490 CommandPacket
->HostAdapterStatus
1493 Token
->TransactionStatus
= Status
;
1497 Status
= CheckTargetStatus (CommandPacket
->TargetStatus
);
1498 if (EFI_ERROR (Status
)) {
1501 "ScsiDiskAsyncUnmapNotify: Target indicating error status 0x%x.\n",
1502 CommandPacket
->HostAdapterStatus
1505 Token
->TransactionStatus
= Status
;
1510 RemoveEntryList (&EraseBlkReq
->Link
);
1511 FreePool (CommandPacket
->OutDataBuffer
);
1512 FreePool (EraseBlkReq
->CommandPacket
.Cdb
);
1513 FreePool (EraseBlkReq
);
1515 gBS
->SignalEvent (Token
->Event
);
1519 Require the device server to cause one or more LBAs to be unmapped.
1521 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
1522 @param Lba The start block number.
1523 @param Blocks Total block number to be unmapped.
1524 @param Token The pointer to the token associated with the
1525 non-blocking erase block request.
1527 @retval EFI_SUCCESS Target blocks have been successfully unmapped.
1528 @retval EFI_DEVICE_ERROR Fail to unmap the target blocks.
1533 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1536 IN EFI_ERASE_BLOCK_TOKEN
*Token OPTIONAL
1539 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
1540 SCSI_ERASEBLK_REQUEST
*EraseBlkReq
;
1541 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*CommandPacket
;
1542 EFI_SCSI_DISK_UNMAP_BLOCK_DESP
*BlkDespPtr
;
1544 EFI_STATUS ReturnStatus
;
1547 UINT32 MaxBlkDespCnt
;
1549 UINT16 UnmapParamListLen
;
1550 VOID
*UnmapParamList
;
1551 EFI_EVENT AsyncUnmapEvent
;
1554 ScsiIo
= ScsiDiskDevice
->ScsiIo
;
1555 MaxLbaCnt
= ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
;
1556 MaxBlkDespCnt
= ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
;
1558 UnmapParamList
= NULL
;
1559 AsyncUnmapEvent
= NULL
;
1560 ReturnStatus
= EFI_SUCCESS
;
1562 if (Blocks
/ (UINTN
)MaxLbaCnt
> MaxBlkDespCnt
) {
1563 ReturnStatus
= EFI_DEVICE_ERROR
;
1567 EraseBlkReq
= AllocateZeroPool (sizeof (SCSI_ERASEBLK_REQUEST
));
1568 if (EraseBlkReq
== NULL
) {
1569 ReturnStatus
= EFI_DEVICE_ERROR
;
1573 EraseBlkReq
->CommandPacket
.Cdb
= AllocateZeroPool (0xA);
1574 if (EraseBlkReq
->CommandPacket
.Cdb
== NULL
) {
1575 ReturnStatus
= EFI_DEVICE_ERROR
;
1579 BlkDespCnt
= (UINT32
)((Blocks
- 1) / MaxLbaCnt
+ 1);
1580 UnmapParamListLen
= (UINT16
)(sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
)
1581 + BlkDespCnt
* sizeof (EFI_SCSI_DISK_UNMAP_BLOCK_DESP
));
1582 UnmapParamList
= AllocateZeroPool (UnmapParamListLen
);
1583 if (UnmapParamList
== NULL
) {
1584 ReturnStatus
= EFI_DEVICE_ERROR
;
1588 *((UINT16
*)UnmapParamList
) = SwapBytes16 (UnmapParamListLen
- 2);
1589 *((UINT16
*)UnmapParamList
+ 1) = SwapBytes16 (UnmapParamListLen
- sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
));
1591 BlkDespPtr
= (EFI_SCSI_DISK_UNMAP_BLOCK_DESP
*)((UINT8
*)UnmapParamList
+ sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
));
1592 while (Blocks
> 0) {
1593 if (Blocks
> MaxLbaCnt
) {
1594 *(UINT64
*)(&BlkDespPtr
->Lba
) = SwapBytes64 (Lba
);
1595 *(UINT32
*)(&BlkDespPtr
->BlockNum
) = SwapBytes32 (MaxLbaCnt
);
1596 Blocks
-= MaxLbaCnt
;
1599 *(UINT64
*)(&BlkDespPtr
->Lba
) = SwapBytes64 (Lba
);
1600 *(UINT32
*)(&BlkDespPtr
->BlockNum
) = SwapBytes32 ((UINT32
)Blocks
);
1607 CommandPacket
= &EraseBlkReq
->CommandPacket
;
1608 CommandPacket
->Timeout
= SCSI_DISK_TIMEOUT
;
1609 CommandPacket
->OutDataBuffer
= UnmapParamList
;
1610 CommandPacket
->OutTransferLength
= UnmapParamListLen
;
1611 CommandPacket
->CdbLength
= 0xA;
1612 CommandPacket
->DataDirection
= EFI_SCSI_DATA_OUT
;
1614 // Fill Cdb for UNMAP Command
1616 Cdb
= CommandPacket
->Cdb
;
1617 Cdb
[0] = EFI_SCSI_OP_UNMAP
;
1618 WriteUnaligned16 ((UINT16
*)&Cdb
[7], SwapBytes16 (UnmapParamListLen
));
1620 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1622 // Non-blocking UNMAP request
1624 Status
= gBS
->CreateEvent (
1627 ScsiDiskAsyncUnmapNotify
,
1631 if (EFI_ERROR (Status
)) {
1632 ReturnStatus
= EFI_DEVICE_ERROR
;
1636 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1637 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &EraseBlkReq
->Link
);
1638 gBS
->RestoreTPL (OldTpl
);
1640 EraseBlkReq
->Token
= Token
;
1642 Status
= ScsiIo
->ExecuteScsiCommand (
1647 if (EFI_ERROR (Status
)) {
1648 ReturnStatus
= EFI_DEVICE_ERROR
;
1650 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1651 RemoveEntryList (&EraseBlkReq
->Link
);
1652 gBS
->RestoreTPL (OldTpl
);
1657 // Directly return if the non-blocking UNMAP request is queued.
1663 // Blocking UNMAP request
1665 Status
= ScsiIo
->ExecuteScsiCommand (
1670 if (EFI_ERROR (Status
)) {
1671 ReturnStatus
= EFI_DEVICE_ERROR
;
1677 // Only blocking UNMAP request will reach here.
1679 Status
= CheckHostAdapterStatus (CommandPacket
->HostAdapterStatus
);
1680 if (EFI_ERROR (Status
)) {
1683 "ScsiDiskUnmap: Host adapter indicating error status 0x%x.\n",
1684 CommandPacket
->HostAdapterStatus
1687 ReturnStatus
= EFI_DEVICE_ERROR
;
1691 Status
= CheckTargetStatus (CommandPacket
->TargetStatus
);
1692 if (EFI_ERROR (Status
)) {
1695 "ScsiDiskUnmap: Target indicating error status 0x%x.\n",
1696 CommandPacket
->HostAdapterStatus
1699 ReturnStatus
= EFI_DEVICE_ERROR
;
1704 if (EraseBlkReq
!= NULL
) {
1705 if (EraseBlkReq
->CommandPacket
.Cdb
!= NULL
) {
1706 FreePool (EraseBlkReq
->CommandPacket
.Cdb
);
1709 FreePool (EraseBlkReq
);
1712 if (UnmapParamList
!= NULL
) {
1713 FreePool (UnmapParamList
);
1716 if (AsyncUnmapEvent
!= NULL
) {
1717 gBS
->CloseEvent (AsyncUnmapEvent
);
1720 return ReturnStatus
;
1724 Erase a specified number of device blocks.
1726 @param[in] This Indicates a pointer to the calling context.
1727 @param[in] MediaId The media ID that the erase request is for.
1728 @param[in] Lba The starting logical block address to be
1729 erased. The caller is responsible for erasing
1730 only legitimate locations.
1731 @param[in, out] Token A pointer to the token associated with the
1733 @param[in] Size The size in bytes to be erased. This must be
1734 a multiple of the physical block size of the
1737 @retval EFI_SUCCESS The erase request was queued if Event is not
1738 NULL. The data was erased correctly to the
1739 device if the Event is NULL.to the device.
1740 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
1742 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1743 to perform the erase operation.
1744 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
1746 @retval EFI_NO_MEDIA There is no media in the device.
1747 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1752 ScsiDiskEraseBlocks (
1753 IN EFI_ERASE_BLOCK_PROTOCOL
*This
,
1756 IN OUT EFI_ERASE_BLOCK_TOKEN
*Token
,
1760 SCSI_DISK_DEV
*ScsiDiskDevice
;
1761 EFI_BLOCK_IO_MEDIA
*Media
;
1764 UINTN NumberOfBlocks
;
1765 BOOLEAN MediaChange
;
1768 MediaChange
= FALSE
;
1769 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1770 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_ERASEBLK (This
);
1772 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
1773 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1774 if (EFI_ERROR (Status
)) {
1775 Status
= EFI_DEVICE_ERROR
;
1780 gBS
->ReinstallProtocolInterface (
1781 ScsiDiskDevice
->Handle
,
1782 &gEfiBlockIoProtocolGuid
,
1783 &ScsiDiskDevice
->BlkIo
,
1784 &ScsiDiskDevice
->BlkIo
1786 gBS
->ReinstallProtocolInterface (
1787 ScsiDiskDevice
->Handle
,
1788 &gEfiBlockIo2ProtocolGuid
,
1789 &ScsiDiskDevice
->BlkIo2
,
1790 &ScsiDiskDevice
->BlkIo2
1792 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1793 gBS
->ReinstallProtocolInterface (
1794 ScsiDiskDevice
->Handle
,
1795 &gEfiEraseBlockProtocolGuid
,
1796 &ScsiDiskDevice
->EraseBlock
,
1797 &ScsiDiskDevice
->EraseBlock
1801 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1802 gBS
->ReinstallProtocolInterface (
1803 ScsiDiskDevice
->Handle
,
1804 &gEfiStorageSecurityCommandProtocolGuid
,
1805 &ScsiDiskDevice
->StorageSecurity
,
1806 &ScsiDiskDevice
->StorageSecurity
1810 Status
= EFI_MEDIA_CHANGED
;
1816 // Get the intrinsic block size
1818 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1820 if (!(Media
->MediaPresent
)) {
1821 Status
= EFI_NO_MEDIA
;
1825 if (MediaId
!= Media
->MediaId
) {
1826 Status
= EFI_MEDIA_CHANGED
;
1830 if (Media
->ReadOnly
) {
1831 Status
= EFI_WRITE_PROTECTED
;
1836 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1837 Token
->TransactionStatus
= EFI_SUCCESS
;
1838 gBS
->SignalEvent (Token
->Event
);
1841 Status
= EFI_SUCCESS
;
1845 BlockSize
= Media
->BlockSize
;
1846 if ((Size
% BlockSize
) != 0) {
1847 Status
= EFI_INVALID_PARAMETER
;
1851 NumberOfBlocks
= Size
/ BlockSize
;
1852 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1853 Status
= EFI_INVALID_PARAMETER
;
1857 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1858 Status
= ScsiDiskUnmap (ScsiDiskDevice
, Lba
, NumberOfBlocks
, Token
);
1860 Status
= ScsiDiskUnmap (ScsiDiskDevice
, Lba
, NumberOfBlocks
, NULL
);
1864 gBS
->RestoreTPL (OldTpl
);
1869 Send a security protocol command to a device that receives data and/or the result
1870 of one or more commands sent by SendData.
1872 The ReceiveData function sends a security protocol command to the given MediaId.
1873 The security protocol command sent is defined by SecurityProtocolId and contains
1874 the security protocol specific data SecurityProtocolSpecificData. The function
1875 returns the data from the security protocol command in PayloadBuffer.
1877 For devices supporting the SCSI command set, the security protocol command is sent
1878 using the SECURITY PROTOCOL IN command defined in SPC-4.
1880 If PayloadBufferSize is too small to store the available data from the security
1881 protocol command, the function shall copy PayloadBufferSize bytes into the
1882 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
1884 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
1885 the function shall return EFI_INVALID_PARAMETER.
1887 If the given MediaId does not support security protocol commands, the function shall
1888 return EFI_UNSUPPORTED. If there is no media in the device, the function returns
1889 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
1890 the function returns EFI_MEDIA_CHANGED.
1892 If the security protocol fails to complete within the Timeout period, the function
1893 shall return EFI_TIMEOUT.
1895 If the security protocol command completes without an error, the function shall
1896 return EFI_SUCCESS. If the security protocol command completes with an error, the
1897 function shall return EFI_DEVICE_ERROR.
1899 @param This Indicates a pointer to the calling context.
1900 @param MediaId ID of the medium to receive data from.
1901 @param Timeout The timeout, in 100ns units, to use for the execution
1902 of the security protocol command. A Timeout value of 0
1903 means that this function will wait indefinitely for the
1904 security protocol command to execute. If Timeout is greater
1905 than zero, then this function will return EFI_TIMEOUT if the
1906 time required to execute the receive data command is greater than Timeout.
1907 @param SecurityProtocolId The value of the "Security Protocol" parameter of
1908 the security protocol command to be sent.
1909 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1910 of the security protocol command to be sent.
1911 @param PayloadBufferSize Size in bytes of the payload data buffer.
1912 @param PayloadBuffer A pointer to a destination buffer to store the security
1913 protocol command specific payload data for the security
1914 protocol command. The caller is responsible for having
1915 either implicit or explicit ownership of the buffer.
1916 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
1917 data written to the payload data buffer.
1919 @retval EFI_SUCCESS The security protocol command completed successfully.
1920 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
1921 data from the device. The PayloadBuffer contains the truncated data.
1922 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1923 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1924 @retval EFI_NO_MEDIA There is no media in the device.
1925 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1926 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
1927 PayloadBufferSize is non-zero.
1928 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1929 protocol command to execute.
1934 ScsiDiskReceiveData (
1935 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
1936 IN UINT32 MediaId OPTIONAL
,
1938 IN UINT8 SecurityProtocolId
,
1939 IN UINT16 SecurityProtocolSpecificData
,
1940 IN UINTN PayloadBufferSize
,
1941 OUT VOID
*PayloadBuffer
,
1942 OUT UINTN
*PayloadTransferSize
1945 SCSI_DISK_DEV
*ScsiDiskDevice
;
1946 EFI_BLOCK_IO_MEDIA
*Media
;
1948 BOOLEAN MediaChange
;
1950 UINT8 SenseDataLength
;
1951 UINT8 HostAdapterStatus
;
1953 VOID
*AlignedBuffer
;
1954 BOOLEAN AlignedBufferAllocated
;
1956 AlignedBuffer
= NULL
;
1957 MediaChange
= FALSE
;
1958 AlignedBufferAllocated
= FALSE
;
1959 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1960 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_STORSEC (This
);
1961 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1963 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
1965 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
1966 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1967 if (EFI_ERROR (Status
)) {
1968 Status
= EFI_DEVICE_ERROR
;
1973 gBS
->ReinstallProtocolInterface (
1974 ScsiDiskDevice
->Handle
,
1975 &gEfiBlockIoProtocolGuid
,
1976 &ScsiDiskDevice
->BlkIo
,
1977 &ScsiDiskDevice
->BlkIo
1979 gBS
->ReinstallProtocolInterface (
1980 ScsiDiskDevice
->Handle
,
1981 &gEfiBlockIo2ProtocolGuid
,
1982 &ScsiDiskDevice
->BlkIo2
,
1983 &ScsiDiskDevice
->BlkIo2
1985 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1986 gBS
->ReinstallProtocolInterface (
1987 ScsiDiskDevice
->Handle
,
1988 &gEfiEraseBlockProtocolGuid
,
1989 &ScsiDiskDevice
->EraseBlock
,
1990 &ScsiDiskDevice
->EraseBlock
1994 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1995 gBS
->ReinstallProtocolInterface (
1996 ScsiDiskDevice
->Handle
,
1997 &gEfiStorageSecurityCommandProtocolGuid
,
1998 &ScsiDiskDevice
->StorageSecurity
,
1999 &ScsiDiskDevice
->StorageSecurity
2003 if (Media
->MediaPresent
) {
2004 Status
= EFI_MEDIA_CHANGED
;
2006 Status
= EFI_NO_MEDIA
;
2016 if (!(Media
->MediaPresent
)) {
2017 Status
= EFI_NO_MEDIA
;
2021 if ((MediaId
!= 0) && (MediaId
!= Media
->MediaId
)) {
2022 Status
= EFI_MEDIA_CHANGED
;
2026 if (PayloadBufferSize
!= 0) {
2027 if ((PayloadBuffer
== NULL
) || (PayloadTransferSize
== NULL
)) {
2028 Status
= EFI_INVALID_PARAMETER
;
2032 if ((ScsiDiskDevice
->ScsiIo
->IoAlign
> 1) && !IS_ALIGNED (PayloadBuffer
, ScsiDiskDevice
->ScsiIo
->IoAlign
)) {
2033 AlignedBuffer
= AllocateAlignedBuffer (ScsiDiskDevice
, PayloadBufferSize
);
2034 if (AlignedBuffer
== NULL
) {
2035 Status
= EFI_OUT_OF_RESOURCES
;
2039 ZeroMem (AlignedBuffer
, PayloadBufferSize
);
2040 AlignedBufferAllocated
= TRUE
;
2042 AlignedBuffer
= PayloadBuffer
;
2046 Status
= ScsiSecurityProtocolInCommand (
2047 ScsiDiskDevice
->ScsiIo
,
2049 ScsiDiskDevice
->SenseData
,
2054 SecurityProtocolSpecificData
,
2060 if (EFI_ERROR (Status
)) {
2064 if (AlignedBufferAllocated
) {
2065 CopyMem (PayloadBuffer
, AlignedBuffer
, PayloadBufferSize
);
2068 if (PayloadBufferSize
< *PayloadTransferSize
) {
2069 Status
= EFI_WARN_BUFFER_TOO_SMALL
;
2073 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2074 if (EFI_ERROR (Status
)) {
2078 Status
= CheckTargetStatus (TargetStatus
);
2079 if (EFI_ERROR (Status
)) {
2084 if (AlignedBufferAllocated
) {
2085 ZeroMem (AlignedBuffer
, PayloadBufferSize
);
2086 FreeAlignedBuffer (AlignedBuffer
, PayloadBufferSize
);
2089 gBS
->RestoreTPL (OldTpl
);
2094 Send a security protocol command to a device.
2096 The SendData function sends a security protocol command containing the payload
2097 PayloadBuffer to the given MediaId. The security protocol command sent is
2098 defined by SecurityProtocolId and contains the security protocol specific data
2099 SecurityProtocolSpecificData. If the underlying protocol command requires a
2100 specific padding for the command payload, the SendData function shall add padding
2101 bytes to the command payload to satisfy the padding requirements.
2103 For devices supporting the SCSI command set, the security protocol command is sent
2104 using the SECURITY PROTOCOL OUT command defined in SPC-4.
2106 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
2107 return EFI_INVALID_PARAMETER.
2109 If the given MediaId does not support security protocol commands, the function
2110 shall return EFI_UNSUPPORTED. If there is no media in the device, the function
2111 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
2112 device, the function returns EFI_MEDIA_CHANGED.
2114 If the security protocol fails to complete within the Timeout period, the function
2115 shall return EFI_TIMEOUT.
2117 If the security protocol command completes without an error, the function shall return
2118 EFI_SUCCESS. If the security protocol command completes with an error, the function
2119 shall return EFI_DEVICE_ERROR.
2121 @param This Indicates a pointer to the calling context.
2122 @param MediaId ID of the medium to receive data from.
2123 @param Timeout The timeout, in 100ns units, to use for the execution
2124 of the security protocol command. A Timeout value of 0
2125 means that this function will wait indefinitely for the
2126 security protocol command to execute. If Timeout is greater
2127 than zero, then this function will return EFI_TIMEOUT if the
2128 time required to execute the receive data command is greater than Timeout.
2129 @param SecurityProtocolId The value of the "Security Protocol" parameter of
2130 the security protocol command to be sent.
2131 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
2132 of the security protocol command to be sent.
2133 @param PayloadBufferSize Size in bytes of the payload data buffer.
2134 @param PayloadBuffer A pointer to a destination buffer to store the security
2135 protocol command specific payload data for the security
2138 @retval EFI_SUCCESS The security protocol command completed successfully.
2139 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
2140 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
2141 @retval EFI_NO_MEDIA There is no media in the device.
2142 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
2143 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
2144 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
2145 protocol command to execute.
2151 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
2152 IN UINT32 MediaId OPTIONAL
,
2154 IN UINT8 SecurityProtocolId
,
2155 IN UINT16 SecurityProtocolSpecificData
,
2156 IN UINTN PayloadBufferSize
,
2157 OUT VOID
*PayloadBuffer
2160 SCSI_DISK_DEV
*ScsiDiskDevice
;
2161 EFI_BLOCK_IO_MEDIA
*Media
;
2163 BOOLEAN MediaChange
;
2165 UINT8 SenseDataLength
;
2166 UINT8 HostAdapterStatus
;
2168 VOID
*AlignedBuffer
;
2169 BOOLEAN AlignedBufferAllocated
;
2171 AlignedBuffer
= NULL
;
2172 MediaChange
= FALSE
;
2173 AlignedBufferAllocated
= FALSE
;
2174 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
2175 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_STORSEC (This
);
2176 Media
= ScsiDiskDevice
->BlkIo
.Media
;
2178 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2180 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
2181 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
2182 if (EFI_ERROR (Status
)) {
2183 Status
= EFI_DEVICE_ERROR
;
2188 gBS
->ReinstallProtocolInterface (
2189 ScsiDiskDevice
->Handle
,
2190 &gEfiBlockIoProtocolGuid
,
2191 &ScsiDiskDevice
->BlkIo
,
2192 &ScsiDiskDevice
->BlkIo
2194 gBS
->ReinstallProtocolInterface (
2195 ScsiDiskDevice
->Handle
,
2196 &gEfiBlockIo2ProtocolGuid
,
2197 &ScsiDiskDevice
->BlkIo2
,
2198 &ScsiDiskDevice
->BlkIo2
2200 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
2201 gBS
->ReinstallProtocolInterface (
2202 ScsiDiskDevice
->Handle
,
2203 &gEfiEraseBlockProtocolGuid
,
2204 &ScsiDiskDevice
->EraseBlock
,
2205 &ScsiDiskDevice
->EraseBlock
2209 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
2210 gBS
->ReinstallProtocolInterface (
2211 ScsiDiskDevice
->Handle
,
2212 &gEfiStorageSecurityCommandProtocolGuid
,
2213 &ScsiDiskDevice
->StorageSecurity
,
2214 &ScsiDiskDevice
->StorageSecurity
2218 if (Media
->MediaPresent
) {
2219 Status
= EFI_MEDIA_CHANGED
;
2221 Status
= EFI_NO_MEDIA
;
2231 if (!(Media
->MediaPresent
)) {
2232 Status
= EFI_NO_MEDIA
;
2236 if ((MediaId
!= 0) && (MediaId
!= Media
->MediaId
)) {
2237 Status
= EFI_MEDIA_CHANGED
;
2241 if (Media
->ReadOnly
) {
2242 Status
= EFI_WRITE_PROTECTED
;
2246 if (PayloadBufferSize
!= 0) {
2247 if (PayloadBuffer
== NULL
) {
2248 Status
= EFI_INVALID_PARAMETER
;
2252 if ((ScsiDiskDevice
->ScsiIo
->IoAlign
> 1) && !IS_ALIGNED (PayloadBuffer
, ScsiDiskDevice
->ScsiIo
->IoAlign
)) {
2253 AlignedBuffer
= AllocateAlignedBuffer (ScsiDiskDevice
, PayloadBufferSize
);
2254 if (AlignedBuffer
== NULL
) {
2255 Status
= EFI_OUT_OF_RESOURCES
;
2259 CopyMem (AlignedBuffer
, PayloadBuffer
, PayloadBufferSize
);
2260 AlignedBufferAllocated
= TRUE
;
2262 AlignedBuffer
= PayloadBuffer
;
2266 Status
= ScsiSecurityProtocolOutCommand (
2267 ScsiDiskDevice
->ScsiIo
,
2269 ScsiDiskDevice
->SenseData
,
2274 SecurityProtocolSpecificData
,
2279 if (EFI_ERROR (Status
)) {
2283 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2284 if (EFI_ERROR (Status
)) {
2288 Status
= CheckTargetStatus (TargetStatus
);
2289 if (EFI_ERROR (Status
)) {
2294 if (AlignedBufferAllocated
) {
2295 ZeroMem (AlignedBuffer
, PayloadBufferSize
);
2296 FreeAlignedBuffer (AlignedBuffer
, PayloadBufferSize
);
2299 gBS
->RestoreTPL (OldTpl
);
2304 Detect Device and read out capacity ,if error occurs, parse the sense key.
2306 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2307 @param MustReadCapacity The flag about reading device capacity
2308 @param MediaChange The pointer of flag indicates if media has changed
2310 @retval EFI_DEVICE_ERROR Indicates that error occurs
2311 @retval EFI_SUCCESS Successfully to detect media
2315 ScsiDiskDetectMedia (
2316 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2317 IN BOOLEAN MustReadCapacity
,
2318 OUT BOOLEAN
*MediaChange
2322 EFI_SCSI_SENSE_DATA
*SenseData
;
2323 UINTN NumberOfSenseKeys
;
2325 BOOLEAN NeedReadCapacity
;
2328 EFI_BLOCK_IO_MEDIA OldMedia
;
2330 EFI_EVENT TimeoutEvt
;
2332 Status
= EFI_SUCCESS
;
2334 NumberOfSenseKeys
= 0;
2337 Action
= ACTION_NO_ACTION
;
2338 NeedReadCapacity
= FALSE
;
2339 *MediaChange
= FALSE
;
2342 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
2344 Status
= gBS
->CreateEvent (
2351 if (EFI_ERROR (Status
)) {
2355 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS (120));
2356 if (EFI_ERROR (Status
)) {
2361 // Sending Test_Unit cmd to poll device status.
2362 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
2363 // We limit the upper boundary to 120 seconds.
2365 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
2366 Status
= ScsiDiskTestUnitReady (
2372 if (!EFI_ERROR (Status
)) {
2373 Status
= DetectMediaParsingSenseKeys (
2379 if (EFI_ERROR (Status
)) {
2381 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2388 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
2394 if (EFI_ERROR (Status
)) {
2399 // ACTION_NO_ACTION: need not read capacity
2400 // other action code: need read capacity
2402 if (Action
== ACTION_READ_CAPACITY
) {
2403 NeedReadCapacity
= TRUE
;
2407 // READ_CAPACITY command is not supported by any of the UFS WLUNs.
2409 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_WLUN
) {
2410 NeedReadCapacity
= FALSE
;
2411 MustReadCapacity
= FALSE
;
2412 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
2416 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
2417 // retrieve capacity via Read Capacity command
2419 if (NeedReadCapacity
|| MustReadCapacity
) {
2421 // retrieve media information
2423 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
2424 Status
= ScsiDiskReadCapacity (
2430 if (!EFI_ERROR (Status
)) {
2432 // analyze sense key to action
2434 Status
= DetectMediaParsingSenseKeys (
2440 if (EFI_ERROR (Status
)) {
2442 // if Status is error, it may indicate crisis error,
2443 // so return without retry.
2446 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2454 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
2460 if (EFI_ERROR (Status
)) {
2465 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
2467 // Media change information got from the device
2469 *MediaChange
= TRUE
;
2472 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
2473 *MediaChange
= TRUE
;
2474 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
2477 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
2478 *MediaChange
= TRUE
;
2479 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
2482 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
2483 *MediaChange
= TRUE
;
2484 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
2487 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
2488 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
2490 // when change from no media to media present, reset the MediaId to 1.
2492 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
2495 // when no media, reset the MediaId to zero.
2497 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
2500 *MediaChange
= TRUE
;
2504 if (TimeoutEvt
!= NULL
) {
2505 gBS
->CloseEvent (TimeoutEvt
);
2512 Send out Inquiry command to Device.
2514 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2515 @param NeedRetry Indicates if needs try again when error happens
2517 @retval EFI_DEVICE_ERROR Indicates that error occurs
2518 @retval EFI_SUCCESS Successfully to detect media
2522 ScsiDiskInquiryDevice (
2523 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2524 OUT BOOLEAN
*NeedRetry
2527 UINT32 InquiryDataLength
;
2528 UINT8 SenseDataLength
;
2529 UINT8 HostAdapterStatus
;
2531 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
2532 UINTN NumberOfSenseKeys
;
2536 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
2537 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
2540 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
2541 SenseDataLength
= 0;
2543 Status
= ScsiInquiryCommand (
2544 ScsiDiskDevice
->ScsiIo
,
2550 (VOID
*)&(ScsiDiskDevice
->InquiryData
),
2555 // no need to check HostAdapterStatus and TargetStatus
2557 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
2558 ParseInquiryData (ScsiDiskDevice
);
2560 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
2562 // Check whether the device supports Block Limits VPD page (0xB0)
2564 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2565 if (SupportedVpdPages
== NULL
) {
2567 return EFI_DEVICE_ERROR
;
2570 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2571 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
2572 SenseDataLength
= 0;
2573 Status
= ScsiInquiryCommandEx (
2574 ScsiDiskDevice
->ScsiIo
,
2580 (VOID
*)SupportedVpdPages
,
2583 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
2585 if (!EFI_ERROR (Status
)) {
2586 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
2587 | SupportedVpdPages
->PageLength1
;
2590 // Sanity checks for coping with broken devices
2592 if (PageLength
> sizeof SupportedVpdPages
->SupportedVpdPageList
) {
2595 "%a: invalid PageLength (%u) in Supported VPD Pages page\n",
2602 if ((PageLength
> 0) &&
2603 (SupportedVpdPages
->SupportedVpdPageList
[0] !=
2604 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
))
2608 "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",
2610 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
2616 // Locate the code for the Block Limits VPD page
2618 for (Index
= 0; Index
< PageLength
; Index
++) {
2623 (SupportedVpdPages
->SupportedVpdPageList
[Index
] <=
2624 SupportedVpdPages
->SupportedVpdPageList
[Index
- 1]))
2628 "%a: non-ascending code in Supported VPD Pages page @ %u\n",
2637 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
2643 // Query the Block Limits VPD page
2645 if (Index
< PageLength
) {
2646 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2647 if (BlockLimits
== NULL
) {
2648 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2650 return EFI_DEVICE_ERROR
;
2653 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2654 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
2655 SenseDataLength
= 0;
2656 Status
= ScsiInquiryCommandEx (
2657 ScsiDiskDevice
->ScsiIo
,
2663 (VOID
*)BlockLimits
,
2666 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
2668 if (!EFI_ERROR (Status
)) {
2669 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
2670 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
2671 BlockLimits
->OptimalTransferLengthGranularity1
;
2673 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
=
2674 (BlockLimits
->MaximumUnmapLbaCount4
<< 24) |
2675 (BlockLimits
->MaximumUnmapLbaCount3
<< 16) |
2676 (BlockLimits
->MaximumUnmapLbaCount2
<< 8) |
2677 BlockLimits
->MaximumUnmapLbaCount1
;
2678 ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
=
2679 (BlockLimits
->MaximumUnmapBlockDescriptorCount4
<< 24) |
2680 (BlockLimits
->MaximumUnmapBlockDescriptorCount3
<< 16) |
2681 (BlockLimits
->MaximumUnmapBlockDescriptorCount2
<< 8) |
2682 BlockLimits
->MaximumUnmapBlockDescriptorCount1
;
2683 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
=
2684 (BlockLimits
->OptimalUnmapGranularity4
<< 24) |
2685 (BlockLimits
->OptimalUnmapGranularity3
<< 16) |
2686 (BlockLimits
->OptimalUnmapGranularity2
<< 8) |
2687 BlockLimits
->OptimalUnmapGranularity1
;
2688 if (BlockLimits
->UnmapGranularityAlignmentValid
!= 0) {
2689 ScsiDiskDevice
->UnmapInfo
.GranularityAlignment
=
2690 (BlockLimits
->UnmapGranularityAlignment4
<< 24) |
2691 (BlockLimits
->UnmapGranularityAlignment3
<< 16) |
2692 (BlockLimits
->UnmapGranularityAlignment2
<< 8) |
2693 BlockLimits
->UnmapGranularityAlignment1
;
2696 if (ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
== 0) {
2698 // A value of 0 indicates that the optimal unmap granularity is
2701 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
= 1;
2704 ScsiDiskDevice
->BlockLimitsVpdSupported
= TRUE
;
2707 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2711 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2715 if (!EFI_ERROR (Status
)) {
2717 } else if (Status
== EFI_NOT_READY
) {
2719 return EFI_DEVICE_ERROR
;
2720 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2722 return EFI_DEVICE_ERROR
;
2726 // go ahead to check HostAdapterStatus and TargetStatus
2727 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
2730 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2731 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2733 return EFI_DEVICE_ERROR
;
2734 } else if (Status
== EFI_DEVICE_ERROR
) {
2736 // reset the scsi channel
2738 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2740 return EFI_DEVICE_ERROR
;
2743 Status
= CheckTargetStatus (TargetStatus
);
2744 if (Status
== EFI_NOT_READY
) {
2746 // reset the scsi device
2748 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2750 return EFI_DEVICE_ERROR
;
2751 } else if (Status
== EFI_DEVICE_ERROR
) {
2753 return EFI_DEVICE_ERROR
;
2757 // if goes here, meant ScsiInquiryCommand() failed.
2758 // if ScsiDiskRequestSenseKeys() succeeds at last,
2759 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
2762 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2763 Status
= ScsiDiskRequestSenseKeys (
2770 if (!EFI_ERROR (Status
)) {
2772 return EFI_DEVICE_ERROR
;
2776 return EFI_DEVICE_ERROR
;
2781 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2782 // set *NeedRetry = FALSE to avoid the outside caller try again.
2785 return EFI_DEVICE_ERROR
;
2791 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
2792 When Test Unit Ready command encounters any error caused by host adapter or
2793 target, return error without retrieving Sense Keys.
2795 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2796 @param NeedRetry The pointer of flag indicates try again
2797 @param SenseDataArray The pointer of an array of sense data
2798 @param NumberOfSenseKeys The pointer of the number of sense data array
2800 @retval EFI_DEVICE_ERROR Indicates that error occurs
2801 @retval EFI_SUCCESS Successfully to test unit
2805 ScsiDiskTestUnitReady (
2806 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2807 OUT BOOLEAN
*NeedRetry
,
2808 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2809 OUT UINTN
*NumberOfSenseKeys
2813 UINT8 SenseDataLength
;
2814 UINT8 HostAdapterStatus
;
2819 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2820 *NumberOfSenseKeys
= 0;
2823 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
2825 Status
= ScsiTestUnitReadyCommand (
2826 ScsiDiskDevice
->ScsiIo
,
2828 ScsiDiskDevice
->SenseData
,
2834 // no need to check HostAdapterStatus and TargetStatus
2836 if (Status
== EFI_NOT_READY
) {
2838 return EFI_DEVICE_ERROR
;
2839 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2841 return EFI_DEVICE_ERROR
;
2845 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
2848 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2849 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2851 return EFI_DEVICE_ERROR
;
2852 } else if (Status
== EFI_DEVICE_ERROR
) {
2854 // reset the scsi channel
2856 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2858 return EFI_DEVICE_ERROR
;
2861 Status
= CheckTargetStatus (TargetStatus
);
2862 if (Status
== EFI_NOT_READY
) {
2864 // reset the scsi device
2866 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2868 return EFI_DEVICE_ERROR
;
2869 } else if (Status
== EFI_DEVICE_ERROR
) {
2871 return EFI_DEVICE_ERROR
;
2874 if (SenseDataLength
!= 0) {
2875 *NumberOfSenseKeys
= SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
);
2876 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2881 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2882 Status
= ScsiDiskRequestSenseKeys (
2889 if (!EFI_ERROR (Status
)) {
2894 return EFI_DEVICE_ERROR
;
2899 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2900 // set *NeedRetry = FALSE to avoid the outside caller try again.
2903 return EFI_DEVICE_ERROR
;
2907 Parsing Sense Keys which got from request sense command.
2909 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2910 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2911 @param NumberOfSenseKeys The number of sense key
2912 @param Action The pointer of action which indicates what is need to do next
2914 @retval EFI_DEVICE_ERROR Indicates that error occurs
2915 @retval EFI_SUCCESS Successfully to complete the parsing
2919 DetectMediaParsingSenseKeys (
2920 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2921 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2922 IN UINTN NumberOfSenseKeys
,
2929 // Default is to read capacity, unless..
2931 *Action
= ACTION_READ_CAPACITY
;
2933 if (NumberOfSenseKeys
== 0) {
2934 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
2935 *Action
= ACTION_NO_ACTION
;
2941 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
2943 // No Sense Key returned from last submitted command
2945 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
2946 *Action
= ACTION_NO_ACTION
;
2952 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
2953 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
2954 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
2955 *Action
= ACTION_NO_ACTION
;
2956 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
2960 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
2961 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
2962 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
2966 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
2967 *Action
= ACTION_RETRY_COMMAND_LATER
;
2968 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
2972 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
2973 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
2974 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2975 return EFI_DEVICE_ERROR
;
2978 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
2979 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
2980 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2981 return EFI_DEVICE_ERROR
;
2984 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
2986 *Action
= ACTION_RETRY_COMMAND_LATER
;
2987 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
2991 *Action
= ACTION_NO_ACTION
;
2992 return EFI_DEVICE_ERROR
;
2995 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2996 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
3001 Send read capacity command to device and get the device parameter.
3003 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3004 @param NeedRetry The pointer of flag indicates if need a retry
3005 @param SenseDataArray The pointer of an array of sense data
3006 @param NumberOfSenseKeys The number of sense key
3008 @retval EFI_DEVICE_ERROR Indicates that error occurs
3009 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
3013 ScsiDiskReadCapacity (
3014 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
3015 OUT BOOLEAN
*NeedRetry
,
3016 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
3017 OUT UINTN
*NumberOfSenseKeys
3020 UINT8 HostAdapterStatus
;
3022 EFI_STATUS CommandStatus
;
3026 UINT8 SenseDataLength
;
3027 UINT32 DataLength10
;
3028 UINT32 DataLength16
;
3029 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
3030 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
3032 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
3033 if (CapacityData10
== NULL
) {
3035 return EFI_DEVICE_ERROR
;
3038 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
3039 if (CapacityData16
== NULL
) {
3040 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
3042 return EFI_DEVICE_ERROR
;
3045 SenseDataLength
= 0;
3046 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
3047 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
3048 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
3049 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
3051 *NumberOfSenseKeys
= 0;
3055 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
3056 // 16 byte command should be used to access large hard disk >2TB
3058 CommandStatus
= ScsiReadCapacityCommand (
3059 ScsiDiskDevice
->ScsiIo
,
3065 (VOID
*)CapacityData10
,
3070 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
3071 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
3072 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff))
3075 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
3077 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
3079 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
3080 // and LowestAlignedLba
3082 CommandStatus
= ScsiReadCapacity16Command (
3083 ScsiDiskDevice
->ScsiIo
,
3089 (VOID
*)CapacityData16
,
3096 // no need to check HostAdapterStatus and TargetStatus
3098 if (CommandStatus
== EFI_SUCCESS
) {
3099 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
3100 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
3101 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
3105 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
3106 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
3108 if (CommandStatus
== EFI_NOT_READY
) {
3110 return EFI_DEVICE_ERROR
;
3111 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
3113 return EFI_DEVICE_ERROR
;
3117 // go ahead to check HostAdapterStatus and TargetStatus
3118 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3121 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3122 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3124 return EFI_DEVICE_ERROR
;
3125 } else if (Status
== EFI_DEVICE_ERROR
) {
3127 // reset the scsi channel
3129 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3131 return EFI_DEVICE_ERROR
;
3134 Status
= CheckTargetStatus (TargetStatus
);
3135 if (Status
== EFI_NOT_READY
) {
3137 // reset the scsi device
3139 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3141 return EFI_DEVICE_ERROR
;
3142 } else if (Status
== EFI_DEVICE_ERROR
) {
3144 return EFI_DEVICE_ERROR
;
3148 // if goes here, meant ScsiReadCapacityCommand() failed.
3149 // if ScsiDiskRequestSenseKeys() succeeds at last,
3150 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
3153 for (Index
= 0; Index
< MaxRetry
; Index
++) {
3154 Status
= ScsiDiskRequestSenseKeys (
3161 if (!EFI_ERROR (Status
)) {
3166 return EFI_DEVICE_ERROR
;
3171 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
3172 // set *NeedRetry = FALSE to avoid the outside caller try again.
3175 return EFI_DEVICE_ERROR
;
3179 Check the HostAdapter status and re-interpret it in EFI_STATUS.
3181 @param HostAdapterStatus Host Adapter status
3183 @retval EFI_SUCCESS Host adapter is OK.
3184 @retval EFI_TIMEOUT Timeout.
3185 @retval EFI_NOT_READY Adapter NOT ready.
3186 @retval EFI_DEVICE_ERROR Adapter device error.
3190 CheckHostAdapterStatus (
3191 IN UINT8 HostAdapterStatus
3194 switch (HostAdapterStatus
) {
3195 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
3198 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
3199 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
3200 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
3203 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
3204 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
3205 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
3206 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
3207 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
3208 return EFI_NOT_READY
;
3210 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
3211 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
3212 return EFI_DEVICE_ERROR
;
3220 Check the target status and re-interpret it in EFI_STATUS.
3222 @param TargetStatus Target status
3224 @retval EFI_NOT_READY Device is NOT ready.
3225 @retval EFI_DEVICE_ERROR
3231 IN UINT8 TargetStatus
3234 switch (TargetStatus
) {
3235 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
3236 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
3237 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
3240 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
3241 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
3242 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
3243 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
3244 return EFI_NOT_READY
;
3246 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
3247 return EFI_DEVICE_ERROR
;
3255 Retrieve all sense keys from the device.
3257 When encountering error during the process, if retrieve sense keys before
3258 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
3259 and NeedRetry set to FALSE; otherwise, return the proper return status.
3261 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3262 @param NeedRetry The pointer of flag indicates if need a retry
3263 @param SenseDataArray The pointer of an array of sense data
3264 @param NumberOfSenseKeys The number of sense key
3265 @param AskResetIfError The flag indicates if need reset when error occurs
3267 @retval EFI_DEVICE_ERROR Indicates that error occurs
3268 @retval EFI_SUCCESS Successfully to request sense key
3272 ScsiDiskRequestSenseKeys (
3273 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
3274 OUT BOOLEAN
*NeedRetry
,
3275 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
3276 OUT UINTN
*NumberOfSenseKeys
,
3277 IN BOOLEAN AskResetIfError
3280 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
3281 UINT8 SenseDataLength
;
3284 EFI_STATUS FallStatus
;
3285 UINT8 HostAdapterStatus
;
3288 FallStatus
= EFI_SUCCESS
;
3289 SenseDataLength
= (UINT8
)sizeof (EFI_SCSI_SENSE_DATA
);
3292 ScsiDiskDevice
->SenseData
,
3293 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
3296 *NumberOfSenseKeys
= 0;
3297 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
3298 Status
= EFI_SUCCESS
;
3299 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
3300 if (PtrSenseData
== NULL
) {
3301 return EFI_DEVICE_ERROR
;
3304 for (SenseReq
= TRUE
; SenseReq
;) {
3305 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
3306 Status
= ScsiRequestSenseCommand (
3307 ScsiDiskDevice
->ScsiIo
,
3314 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
3315 FallStatus
= EFI_SUCCESS
;
3316 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3318 FallStatus
= EFI_DEVICE_ERROR
;
3319 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
3321 FallStatus
= EFI_DEVICE_ERROR
;
3322 } else if (Status
== EFI_DEVICE_ERROR
) {
3323 if (AskResetIfError
) {
3324 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3327 FallStatus
= EFI_DEVICE_ERROR
;
3330 if (EFI_ERROR (FallStatus
)) {
3331 if (*NumberOfSenseKeys
!= 0) {
3333 Status
= EFI_SUCCESS
;
3336 Status
= EFI_DEVICE_ERROR
;
3341 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
3342 (*NumberOfSenseKeys
) += 1;
3345 // no more sense key or number of sense keys exceeds predefined,
3348 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
3349 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
))
3356 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
3361 Get information from media read capacity command.
3363 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3364 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
3365 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
3370 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
3371 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
3372 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
3377 if (!ScsiDiskDevice
->Cdb16Byte
) {
3378 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= ((UINT32
)Capacity10
->LastLba3
<< 24) |
3379 (Capacity10
->LastLba2
<< 16) |
3380 (Capacity10
->LastLba1
<< 8) |
3381 Capacity10
->LastLba0
;
3383 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
3384 (Capacity10
->BlockSize2
<< 16) |
3385 (Capacity10
->BlockSize1
<< 8) |
3386 Capacity10
->BlockSize0
;
3387 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
3388 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
3389 if (!ScsiDiskDevice
->BlockLimitsVpdSupported
) {
3390 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
)ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
3393 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
3394 *Ptr
++ = Capacity16
->LastLba0
;
3395 *Ptr
++ = Capacity16
->LastLba1
;
3396 *Ptr
++ = Capacity16
->LastLba2
;
3397 *Ptr
++ = Capacity16
->LastLba3
;
3398 *Ptr
++ = Capacity16
->LastLba4
;
3399 *Ptr
++ = Capacity16
->LastLba5
;
3400 *Ptr
++ = Capacity16
->LastLba6
;
3401 *Ptr
= Capacity16
->LastLba7
;
3403 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
3404 (Capacity16
->BlockSize2
<< 16) |
3405 (Capacity16
->BlockSize1
<< 8) |
3406 Capacity16
->BlockSize0
;
3408 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
3409 Capacity16
->LowestAlignLogic1
;
3410 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
3411 if (!ScsiDiskDevice
->BlockLimitsVpdSupported
) {
3412 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
> (UINT32
)-1) {
3413 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
)-1;
3415 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
)ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
3420 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
3426 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3431 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
3434 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
)((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
3435 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
)(!ScsiDiskDevice
->FixedDevice
);
3439 Read sector from SCSI Disk.
3441 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3442 @param Buffer The buffer to fill in the read out data
3443 @param Lba Logic block address
3444 @param NumberOfBlocks The number of blocks to read
3446 @retval EFI_DEVICE_ERROR Indicates a device error.
3447 @retval EFI_SUCCESS Operation is successful.
3451 ScsiDiskReadSectors (
3452 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3455 IN UINTN NumberOfBlocks
3458 UINTN BlocksRemaining
;
3464 UINT32 NextSectorCount
;
3471 Status
= EFI_SUCCESS
;
3473 BlocksRemaining
= NumberOfBlocks
;
3474 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3477 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3479 if (!ScsiDiskDevice
->Cdb16Byte
) {
3482 MaxBlock
= 0xFFFFFFFF;
3487 while (BlocksRemaining
> 0) {
3488 if (BlocksRemaining
<= MaxBlock
) {
3489 if (!ScsiDiskDevice
->Cdb16Byte
) {
3490 SectorCount
= (UINT16
)BlocksRemaining
;
3492 SectorCount
= (UINT32
)BlocksRemaining
;
3495 SectorCount
= MaxBlock
;
3498 ByteCount
= SectorCount
* BlockSize
;
3500 // |------------------------|-----------------|------------------|-----------------|
3501 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3502 // |------------------------|-----------------|------------------|-----------------|
3503 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3504 // |------------------------|-----------------|------------------|-----------------|
3505 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3506 // |------------------------|-----------------|------------------|-----------------|
3507 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3508 // |------------------------|-----------------|------------------|-----------------|
3509 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3510 // |------------------------|-----------------|------------------|-----------------|
3511 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3512 // |------------------------|-----------------|------------------|-----------------|
3513 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3514 // |------------------------|-----------------|------------------|-----------------|
3515 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3516 // |------------------------|-----------------|------------------|-----------------|
3517 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3518 // |------------------------|-----------------|------------------|-----------------|
3519 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3520 // |------------------------|-----------------|------------------|-----------------|
3521 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3522 // |------------------------|-----------------|------------------|-----------------|
3524 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3525 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3526 // From the above table, we could know 2.1Mbytes per second is lowest one.
3527 // The timeout value is rounded up to nearest integer and here an additional 30s is added
3528 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3529 // commands in the Standby/Idle mode.
3531 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3534 for (Index
= 0; Index
< MaxRetry
; Index
++) {
3535 if (!ScsiDiskDevice
->Cdb16Byte
) {
3536 Status
= ScsiDiskRead10 (
3546 Status
= ScsiDiskRead16 (
3557 if (!EFI_ERROR (Status
)) {
3562 return EFI_DEVICE_ERROR
;
3566 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
3567 // lowered ByteCount on output, we must make sure that we lower
3568 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3569 // it is invalid to request more sectors in the CDB than the entire
3570 // transfer (ie. ByteCount) can carry.
3572 // In addition, ByteCount is only expected to go down, or stay unchanged.
3573 // Therefore we don't need to update Timeout: the original timeout should
3574 // accommodate shorter transfers too.
3576 NextSectorCount
= ByteCount
/ BlockSize
;
3577 if (NextSectorCount
< SectorCount
) {
3578 SectorCount
= NextSectorCount
;
3580 // Account for any rounding down.
3582 ByteCount
= SectorCount
* BlockSize
;
3586 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
3587 return EFI_DEVICE_ERROR
;
3591 // actual transferred sectors
3593 SectorCount
= ByteCount
/ BlockSize
;
3596 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3597 BlocksRemaining
-= SectorCount
;
3604 Write sector to SCSI Disk.
3606 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3607 @param Buffer The buffer of data to be written into SCSI Disk
3608 @param Lba Logic block address
3609 @param NumberOfBlocks The number of blocks to read
3611 @retval EFI_DEVICE_ERROR Indicates a device error.
3612 @retval EFI_SUCCESS Operation is successful.
3616 ScsiDiskWriteSectors (
3617 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3620 IN UINTN NumberOfBlocks
3623 UINTN BlocksRemaining
;
3629 UINT32 NextSectorCount
;
3636 Status
= EFI_SUCCESS
;
3638 BlocksRemaining
= NumberOfBlocks
;
3639 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3642 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3644 if (!ScsiDiskDevice
->Cdb16Byte
) {
3647 MaxBlock
= 0xFFFFFFFF;
3652 while (BlocksRemaining
> 0) {
3653 if (BlocksRemaining
<= MaxBlock
) {
3654 if (!ScsiDiskDevice
->Cdb16Byte
) {
3655 SectorCount
= (UINT16
)BlocksRemaining
;
3657 SectorCount
= (UINT32
)BlocksRemaining
;
3660 SectorCount
= MaxBlock
;
3663 ByteCount
= SectorCount
* BlockSize
;
3665 // |------------------------|-----------------|------------------|-----------------|
3666 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3667 // |------------------------|-----------------|------------------|-----------------|
3668 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3669 // |------------------------|-----------------|------------------|-----------------|
3670 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3671 // |------------------------|-----------------|------------------|-----------------|
3672 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3673 // |------------------------|-----------------|------------------|-----------------|
3674 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3675 // |------------------------|-----------------|------------------|-----------------|
3676 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3677 // |------------------------|-----------------|------------------|-----------------|
3678 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3679 // |------------------------|-----------------|------------------|-----------------|
3680 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3681 // |------------------------|-----------------|------------------|-----------------|
3682 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3683 // |------------------------|-----------------|------------------|-----------------|
3684 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3685 // |------------------------|-----------------|------------------|-----------------|
3686 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3687 // |------------------------|-----------------|------------------|-----------------|
3689 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3690 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3691 // From the above table, we could know 2.1Mbytes per second is lowest one.
3692 // The timeout value is rounded up to nearest integer and here an additional 30s is added
3693 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3694 // commands in the Standby/Idle mode.
3696 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3698 for (Index
= 0; Index
< MaxRetry
; Index
++) {
3699 if (!ScsiDiskDevice
->Cdb16Byte
) {
3700 Status
= ScsiDiskWrite10 (
3710 Status
= ScsiDiskWrite16 (
3721 if (!EFI_ERROR (Status
)) {
3726 return EFI_DEVICE_ERROR
;
3730 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
3731 // has lowered ByteCount on output, we must make sure that we lower
3732 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3733 // it is invalid to request more sectors in the CDB than the entire
3734 // transfer (ie. ByteCount) can carry.
3736 // In addition, ByteCount is only expected to go down, or stay unchanged.
3737 // Therefore we don't need to update Timeout: the original timeout should
3738 // accommodate shorter transfers too.
3740 NextSectorCount
= ByteCount
/ BlockSize
;
3741 if (NextSectorCount
< SectorCount
) {
3742 SectorCount
= NextSectorCount
;
3744 // Account for any rounding down.
3746 ByteCount
= SectorCount
* BlockSize
;
3750 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
3751 return EFI_DEVICE_ERROR
;
3755 // actual transferred sectors
3757 SectorCount
= ByteCount
/ BlockSize
;
3760 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3761 BlocksRemaining
-= SectorCount
;
3768 Asynchronously read sector from SCSI Disk.
3770 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3771 @param Buffer The buffer to fill in the read out data.
3772 @param Lba Logic block address.
3773 @param NumberOfBlocks The number of blocks to read.
3774 @param Token A pointer to the token associated with the
3775 non-blocking read request.
3777 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
3778 @retval EFI_DEVICE_ERROR Indicates a device error.
3779 @retval EFI_SUCCESS Operation is successful.
3783 ScsiDiskAsyncReadSectors (
3784 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3787 IN UINTN NumberOfBlocks
,
3788 IN EFI_BLOCK_IO2_TOKEN
*Token
3791 UINTN BlocksRemaining
;
3798 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
3802 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
3803 return EFI_INVALID_PARAMETER
;
3806 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
3807 if (BlkIo2Req
== NULL
) {
3808 return EFI_OUT_OF_RESOURCES
;
3811 BlkIo2Req
->Token
= Token
;
3813 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3814 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &BlkIo2Req
->Link
);
3815 gBS
->RestoreTPL (OldTpl
);
3817 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
3819 Status
= EFI_SUCCESS
;
3821 BlocksRemaining
= NumberOfBlocks
;
3822 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3825 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3828 if (!ScsiDiskDevice
->Cdb16Byte
) {
3831 MaxBlock
= 0xFFFFFFFF;
3836 while (BlocksRemaining
> 0) {
3837 if (BlocksRemaining
<= MaxBlock
) {
3838 if (!ScsiDiskDevice
->Cdb16Byte
) {
3839 SectorCount
= (UINT16
)BlocksRemaining
;
3841 SectorCount
= (UINT32
)BlocksRemaining
;
3844 SectorCount
= MaxBlock
;
3847 ByteCount
= SectorCount
* BlockSize
;
3849 // |------------------------|-----------------|------------------|-----------------|
3850 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3851 // |------------------------|-----------------|------------------|-----------------|
3852 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3853 // |------------------------|-----------------|------------------|-----------------|
3854 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3855 // |------------------------|-----------------|------------------|-----------------|
3856 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3857 // |------------------------|-----------------|------------------|-----------------|
3858 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3859 // |------------------------|-----------------|------------------|-----------------|
3860 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3861 // |------------------------|-----------------|------------------|-----------------|
3862 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3863 // |------------------------|-----------------|------------------|-----------------|
3864 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3865 // |------------------------|-----------------|------------------|-----------------|
3866 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3867 // |------------------------|-----------------|------------------|-----------------|
3868 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3869 // |------------------------|-----------------|------------------|-----------------|
3870 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3871 // |------------------------|-----------------|------------------|-----------------|
3873 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3874 // we have to use the lowest transfer rate to calculate the possible
3875 // maximum timeout value for each operation.
3876 // From the above table, we could know 2.1Mbytes per second is lowest one.
3877 // The timeout value is rounded up to nearest integer and here an additional
3878 // 30s is added to follow ATA spec in which it mentioned that the device
3879 // may take up to 30s to respond commands in the Standby/Idle mode.
3881 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3883 if (!ScsiDiskDevice
->Cdb16Byte
) {
3884 Status
= ScsiDiskAsyncRead10 (
3896 Status
= ScsiDiskAsyncRead16 (
3909 if (EFI_ERROR (Status
)) {
3911 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3912 // length of a SCSI I/O command is too large.
3913 // In this case, we retry sending the SCSI command with a data length
3914 // half of its previous value.
3916 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
3917 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
3918 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
3923 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3924 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3926 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3927 // SCSI sub-task running. Otherwise, it will be freed in the callback
3928 // function ScsiDiskNotify().
3930 RemoveEntryList (&BlkIo2Req
->Link
);
3931 FreePool (BlkIo2Req
);
3933 gBS
->RestoreTPL (OldTpl
);
3936 // It is safe to return error status to the caller, since there is no
3937 // previous SCSI sub-task executing.
3939 Status
= EFI_DEVICE_ERROR
;
3942 gBS
->RestoreTPL (OldTpl
);
3945 // There are previous SCSI commands still running, EFI_SUCCESS should
3946 // be returned to make sure that the caller does not free resources
3947 // still using by these SCSI commands.
3949 Status
= EFI_SUCCESS
;
3955 // Sectors submitted for transfer
3957 SectorCount
= ByteCount
/ BlockSize
;
3960 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3961 BlocksRemaining
-= SectorCount
;
3964 Status
= EFI_SUCCESS
;
3967 if (BlkIo2Req
!= NULL
) {
3968 BlkIo2Req
->LastScsiRW
= TRUE
;
3970 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3971 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3972 RemoveEntryList (&BlkIo2Req
->Link
);
3973 FreePool (BlkIo2Req
);
3976 gBS
->SignalEvent (Token
->Event
);
3979 gBS
->RestoreTPL (OldTpl
);
3986 Asynchronously write sector to SCSI Disk.
3988 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3989 @param Buffer The buffer of data to be written into SCSI Disk.
3990 @param Lba Logic block address.
3991 @param NumberOfBlocks The number of blocks to read.
3992 @param Token A pointer to the token associated with the
3993 non-blocking read request.
3995 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
3996 @retval EFI_DEVICE_ERROR Indicates a device error.
3997 @retval EFI_SUCCESS Operation is successful.
4001 ScsiDiskAsyncWriteSectors (
4002 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4005 IN UINTN NumberOfBlocks
,
4006 IN EFI_BLOCK_IO2_TOKEN
*Token
4009 UINTN BlocksRemaining
;
4016 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
4020 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
4021 return EFI_INVALID_PARAMETER
;
4024 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
4025 if (BlkIo2Req
== NULL
) {
4026 return EFI_OUT_OF_RESOURCES
;
4029 BlkIo2Req
->Token
= Token
;
4031 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4032 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &BlkIo2Req
->Link
);
4033 gBS
->RestoreTPL (OldTpl
);
4035 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
4037 Status
= EFI_SUCCESS
;
4039 BlocksRemaining
= NumberOfBlocks
;
4040 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4043 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
4046 if (!ScsiDiskDevice
->Cdb16Byte
) {
4049 MaxBlock
= 0xFFFFFFFF;
4054 while (BlocksRemaining
> 0) {
4055 if (BlocksRemaining
<= MaxBlock
) {
4056 if (!ScsiDiskDevice
->Cdb16Byte
) {
4057 SectorCount
= (UINT16
)BlocksRemaining
;
4059 SectorCount
= (UINT32
)BlocksRemaining
;
4062 SectorCount
= MaxBlock
;
4065 ByteCount
= SectorCount
* BlockSize
;
4067 // |------------------------|-----------------|------------------|-----------------|
4068 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
4069 // |------------------------|-----------------|------------------|-----------------|
4070 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
4071 // |------------------------|-----------------|------------------|-----------------|
4072 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
4073 // |------------------------|-----------------|------------------|-----------------|
4074 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
4075 // |------------------------|-----------------|------------------|-----------------|
4076 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
4077 // |------------------------|-----------------|------------------|-----------------|
4078 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
4079 // |------------------------|-----------------|------------------|-----------------|
4080 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
4081 // |------------------------|-----------------|------------------|-----------------|
4082 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
4083 // |------------------------|-----------------|------------------|-----------------|
4084 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
4085 // |------------------------|-----------------|------------------|-----------------|
4086 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
4087 // |------------------------|-----------------|------------------|-----------------|
4088 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
4089 // |------------------------|-----------------|------------------|-----------------|
4091 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
4092 // we have to use the lowest transfer rate to calculate the possible
4093 // maximum timeout value for each operation.
4094 // From the above table, we could know 2.1Mbytes per second is lowest one.
4095 // The timeout value is rounded up to nearest integer and here an additional
4096 // 30s is added to follow ATA spec in which it mentioned that the device
4097 // may take up to 30s to respond commands in the Standby/Idle mode.
4099 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
4101 if (!ScsiDiskDevice
->Cdb16Byte
) {
4102 Status
= ScsiDiskAsyncWrite10 (
4114 Status
= ScsiDiskAsyncWrite16 (
4127 if (EFI_ERROR (Status
)) {
4129 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
4130 // length of a SCSI I/O command is too large.
4131 // In this case, we retry sending the SCSI command with a data length
4132 // half of its previous value.
4134 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
4135 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
4136 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
4141 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4142 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
4144 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
4145 // SCSI sub-task running. Otherwise, it will be freed in the callback
4146 // function ScsiDiskNotify().
4148 RemoveEntryList (&BlkIo2Req
->Link
);
4149 FreePool (BlkIo2Req
);
4151 gBS
->RestoreTPL (OldTpl
);
4154 // It is safe to return error status to the caller, since there is no
4155 // previous SCSI sub-task executing.
4157 Status
= EFI_DEVICE_ERROR
;
4160 gBS
->RestoreTPL (OldTpl
);
4163 // There are previous SCSI commands still running, EFI_SUCCESS should
4164 // be returned to make sure that the caller does not free resources
4165 // still using by these SCSI commands.
4167 Status
= EFI_SUCCESS
;
4173 // Sectors submitted for transfer
4175 SectorCount
= ByteCount
/ BlockSize
;
4178 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
4179 BlocksRemaining
-= SectorCount
;
4182 Status
= EFI_SUCCESS
;
4185 if (BlkIo2Req
!= NULL
) {
4186 BlkIo2Req
->LastScsiRW
= TRUE
;
4188 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4189 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
4190 RemoveEntryList (&BlkIo2Req
->Link
);
4191 FreePool (BlkIo2Req
);
4194 gBS
->SignalEvent (Token
->Event
);
4197 gBS
->RestoreTPL (OldTpl
);
4204 Submit Read(10) command.
4206 @param ScsiDiskDevice The pointer of ScsiDiskDevice
4207 @param NeedRetry The pointer of flag indicates if needs retry if error happens
4208 @param Timeout The time to complete the command
4209 @param DataBuffer The buffer to fill with the read out data
4210 @param DataLength The length of buffer
4211 @param StartLba The start logic block address
4212 @param SectorCount The number of blocks to read
4214 @return EFI_STATUS is returned by calling ScsiRead10Command().
4218 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4219 OUT BOOLEAN
*NeedRetry
,
4221 OUT UINT8
*DataBuffer
,
4222 IN OUT UINT32
*DataLength
,
4224 IN UINT32 SectorCount
4227 UINT8 SenseDataLength
;
4229 EFI_STATUS ReturnStatus
;
4230 UINT8 HostAdapterStatus
;
4235 // Implement a backoff algorithm to resolve some compatibility issues that
4236 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4237 // big data in a single operation.
4238 // This algorithm will at first try to execute original request. If the request fails
4239 // with media error sense data or else, it will reduce the transfer length to half and
4240 // try again till the operation succeeds or fails with one sector transfer length.
4244 Action
= ACTION_NO_ACTION
;
4245 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
4246 ReturnStatus
= ScsiRead10Command (
4247 ScsiDiskDevice
->ScsiIo
,
4249 ScsiDiskDevice
->SenseData
,
4259 if ((ReturnStatus
== EFI_NOT_READY
) || (ReturnStatus
== EFI_BAD_BUFFER_SIZE
)) {
4261 return EFI_DEVICE_ERROR
;
4262 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
4264 return ReturnStatus
;
4268 // go ahead to check HostAdapterStatus and TargetStatus
4269 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4271 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
4272 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4274 return EFI_DEVICE_ERROR
;
4275 } else if (Status
== EFI_DEVICE_ERROR
) {
4277 // reset the scsi channel
4279 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4281 return EFI_DEVICE_ERROR
;
4284 Status
= CheckTargetStatus (TargetStatus
);
4285 if (Status
== EFI_NOT_READY
) {
4287 // reset the scsi device
4289 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4291 return EFI_DEVICE_ERROR
;
4292 } else if (Status
== EFI_DEVICE_ERROR
) {
4294 return EFI_DEVICE_ERROR
;
4297 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
4298 DEBUG ((DEBUG_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
4299 DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
4300 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4302 return EFI_DEVICE_ERROR
;
4303 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4304 if (SectorCount
<= 1) {
4306 // Jump out if the operation still fails with one sector transfer length.
4309 return EFI_DEVICE_ERROR
;
4313 // Try again with half length if the sense data shows we need to retry.
4316 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4320 return EFI_DEVICE_ERROR
;
4324 return ReturnStatus
;
4328 Submit Write(10) Command.
4330 @param ScsiDiskDevice The pointer of ScsiDiskDevice
4331 @param NeedRetry The pointer of flag indicates if needs retry if error happens
4332 @param Timeout The time to complete the command
4333 @param DataBuffer The buffer to fill with the read out data
4334 @param DataLength The length of buffer
4335 @param StartLba The start logic block address
4336 @param SectorCount The number of blocks to write
4338 @return EFI_STATUS is returned by calling ScsiWrite10Command().
4343 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4344 OUT BOOLEAN
*NeedRetry
,
4346 IN UINT8
*DataBuffer
,
4347 IN OUT UINT32
*DataLength
,
4349 IN UINT32 SectorCount
4353 EFI_STATUS ReturnStatus
;
4354 UINT8 SenseDataLength
;
4355 UINT8 HostAdapterStatus
;
4360 // Implement a backoff algorithm to resolve some compatibility issues that
4361 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4362 // big data in a single operation.
4363 // This algorithm will at first try to execute original request. If the request fails
4364 // with media error sense data or else, it will reduce the transfer length to half and
4365 // try again till the operation succeeds or fails with one sector transfer length.
4369 Action
= ACTION_NO_ACTION
;
4370 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
4371 ReturnStatus
= ScsiWrite10Command (
4372 ScsiDiskDevice
->ScsiIo
,
4374 ScsiDiskDevice
->SenseData
,
4383 if ((ReturnStatus
== EFI_NOT_READY
) || (ReturnStatus
== EFI_BAD_BUFFER_SIZE
)) {
4385 return EFI_DEVICE_ERROR
;
4386 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
4388 return ReturnStatus
;
4392 // go ahead to check HostAdapterStatus and TargetStatus
4393 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4395 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
4396 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4398 return EFI_DEVICE_ERROR
;
4399 } else if (Status
== EFI_DEVICE_ERROR
) {
4401 // reset the scsi channel
4403 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4405 return EFI_DEVICE_ERROR
;
4408 Status
= CheckTargetStatus (TargetStatus
);
4409 if (Status
== EFI_NOT_READY
) {
4411 // reset the scsi device
4413 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4415 return EFI_DEVICE_ERROR
;
4416 } else if (Status
== EFI_DEVICE_ERROR
) {
4418 return EFI_DEVICE_ERROR
;
4421 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
4422 DEBUG ((DEBUG_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
4423 DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
4424 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4426 return EFI_DEVICE_ERROR
;
4427 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4428 if (SectorCount
<= 1) {
4430 // Jump out if the operation still fails with one sector transfer length.
4433 return EFI_DEVICE_ERROR
;
4437 // Try again with half length if the sense data shows we need to retry.
4440 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4444 return EFI_DEVICE_ERROR
;
4448 return ReturnStatus
;
4452 Submit Read(16) command.
4454 @param ScsiDiskDevice The pointer of ScsiDiskDevice
4455 @param NeedRetry The pointer of flag indicates if needs retry if error happens
4456 @param Timeout The time to complete the command
4457 @param DataBuffer The buffer to fill with the read out data
4458 @param DataLength The length of buffer
4459 @param StartLba The start logic block address
4460 @param SectorCount The number of blocks to read
4462 @return EFI_STATUS is returned by calling ScsiRead16Command().
4466 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4467 OUT BOOLEAN
*NeedRetry
,
4469 OUT UINT8
*DataBuffer
,
4470 IN OUT UINT32
*DataLength
,
4472 IN UINT32 SectorCount
4475 UINT8 SenseDataLength
;
4477 EFI_STATUS ReturnStatus
;
4478 UINT8 HostAdapterStatus
;
4483 // Implement a backoff algorithm to resolve some compatibility issues that
4484 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4485 // big data in a single operation.
4486 // This algorithm will at first try to execute original request. If the request fails
4487 // with media error sense data or else, it will reduce the transfer length to half and
4488 // try again till the operation succeeds or fails with one sector transfer length.
4492 Action
= ACTION_NO_ACTION
;
4493 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
4494 ReturnStatus
= ScsiRead16Command (
4495 ScsiDiskDevice
->ScsiIo
,
4497 ScsiDiskDevice
->SenseData
,
4506 if ((ReturnStatus
== EFI_NOT_READY
) || (ReturnStatus
== EFI_BAD_BUFFER_SIZE
)) {
4508 return EFI_DEVICE_ERROR
;
4509 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
4511 return ReturnStatus
;
4515 // go ahead to check HostAdapterStatus and TargetStatus
4516 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4518 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
4519 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4521 return EFI_DEVICE_ERROR
;
4522 } else if (Status
== EFI_DEVICE_ERROR
) {
4524 // reset the scsi channel
4526 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4528 return EFI_DEVICE_ERROR
;
4531 Status
= CheckTargetStatus (TargetStatus
);
4532 if (Status
== EFI_NOT_READY
) {
4534 // reset the scsi device
4536 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4538 return EFI_DEVICE_ERROR
;
4539 } else if (Status
== EFI_DEVICE_ERROR
) {
4541 return EFI_DEVICE_ERROR
;
4544 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
4545 DEBUG ((DEBUG_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
4546 DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
4547 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4549 return EFI_DEVICE_ERROR
;
4550 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4551 if (SectorCount
<= 1) {
4553 // Jump out if the operation still fails with one sector transfer length.
4556 return EFI_DEVICE_ERROR
;
4560 // Try again with half length if the sense data shows we need to retry.
4563 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4567 return EFI_DEVICE_ERROR
;
4571 return ReturnStatus
;
4575 Submit Write(16) Command.
4577 @param ScsiDiskDevice The pointer of ScsiDiskDevice
4578 @param NeedRetry The pointer of flag indicates if needs retry if error happens
4579 @param Timeout The time to complete the command
4580 @param DataBuffer The buffer to fill with the read out data
4581 @param DataLength The length of buffer
4582 @param StartLba The start logic block address
4583 @param SectorCount The number of blocks to write
4585 @return EFI_STATUS is returned by calling ScsiWrite16Command().
4590 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4591 OUT BOOLEAN
*NeedRetry
,
4593 IN UINT8
*DataBuffer
,
4594 IN OUT UINT32
*DataLength
,
4596 IN UINT32 SectorCount
4600 EFI_STATUS ReturnStatus
;
4601 UINT8 SenseDataLength
;
4602 UINT8 HostAdapterStatus
;
4607 // Implement a backoff algorithm to resolve some compatibility issues that
4608 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4609 // big data in a single operation.
4610 // This algorithm will at first try to execute original request. If the request fails
4611 // with media error sense data or else, it will reduce the transfer length to half and
4612 // try again till the operation succeeds or fails with one sector transfer length.
4616 Action
= ACTION_NO_ACTION
;
4617 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
4618 ReturnStatus
= ScsiWrite16Command (
4619 ScsiDiskDevice
->ScsiIo
,
4621 ScsiDiskDevice
->SenseData
,
4630 if ((ReturnStatus
== EFI_NOT_READY
) || (ReturnStatus
== EFI_BAD_BUFFER_SIZE
)) {
4632 return EFI_DEVICE_ERROR
;
4633 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
4635 return ReturnStatus
;
4639 // go ahead to check HostAdapterStatus and TargetStatus
4640 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4642 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
4643 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4645 return EFI_DEVICE_ERROR
;
4646 } else if (Status
== EFI_DEVICE_ERROR
) {
4648 // reset the scsi channel
4650 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4652 return EFI_DEVICE_ERROR
;
4655 Status
= CheckTargetStatus (TargetStatus
);
4656 if (Status
== EFI_NOT_READY
) {
4658 // reset the scsi device
4660 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4662 return EFI_DEVICE_ERROR
;
4663 } else if (Status
== EFI_DEVICE_ERROR
) {
4665 return EFI_DEVICE_ERROR
;
4668 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
4669 DEBUG ((DEBUG_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
4670 DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
4671 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4673 return EFI_DEVICE_ERROR
;
4674 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4675 if (SectorCount
<= 1) {
4677 // Jump out if the operation still fails with one sector transfer length.
4680 return EFI_DEVICE_ERROR
;
4684 // Try again with half length if the sense data shows we need to retry.
4687 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4691 return EFI_DEVICE_ERROR
;
4695 return ReturnStatus
;
4699 Internal helper notify function in which determine whether retry of a SCSI
4700 Read/Write command is needed and signal the event passed from Block I/O(2) if
4701 the SCSI I/O operation completes.
4703 @param Event The instance of EFI_EVENT.
4704 @param Context The parameter passed in.
4715 SCSI_ASYNC_RW_REQUEST
*Request
;
4716 SCSI_DISK_DEV
*ScsiDiskDevice
;
4717 EFI_BLOCK_IO2_TOKEN
*Token
;
4719 UINT32 OldDataLength
;
4720 UINT32 OldSectorCount
;
4723 gBS
->CloseEvent (Event
);
4725 Request
= (SCSI_ASYNC_RW_REQUEST
*)Context
;
4726 ScsiDiskDevice
= Request
->ScsiDiskDevice
;
4727 Token
= Request
->BlkIo2Req
->Token
;
4728 OldDataLength
= Request
->DataLength
;
4729 OldSectorCount
= Request
->SectorCount
;
4733 // If previous sub-tasks already fails, no need to process this sub-task.
4735 if (Token
->TransactionStatus
!= EFI_SUCCESS
) {
4740 // Check HostAdapterStatus and TargetStatus
4741 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4743 Status
= CheckHostAdapterStatus (Request
->HostAdapterStatus
);
4744 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4745 if (++Request
->TimesRetry
> MaxRetry
) {
4746 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4751 } else if (Status
== EFI_DEVICE_ERROR
) {
4753 // reset the scsi channel
4755 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4756 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4760 Status
= CheckTargetStatus (Request
->TargetStatus
);
4761 if (Status
== EFI_NOT_READY
) {
4763 // reset the scsi device
4765 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4766 if (++Request
->TimesRetry
> MaxRetry
) {
4767 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4772 } else if (Status
== EFI_DEVICE_ERROR
) {
4773 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4777 if (Request
->TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) {
4778 DEBUG ((DEBUG_ERROR
, "ScsiDiskNotify: Check Condition happened!\n"));
4780 DetectMediaParsingSenseKeys (
4783 Request
->SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
),
4786 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4787 if (++Request
->TimesRetry
> MaxRetry
) {
4788 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4793 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4794 if (Request
->SectorCount
<= 1) {
4796 // Jump out if the operation still fails with one sector transfer
4799 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4804 // Try again with two half length request if the sense data shows we need
4807 Request
->SectorCount
>>= 1;
4808 Request
->DataLength
= Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4809 Request
->TimesRetry
= 0;
4813 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4819 // This sub-task succeeds, no need to retry.
4824 if (Request
->InBuffer
!= NULL
) {
4826 // SCSI read command
4828 if (!ScsiDiskDevice
->Cdb16Byte
) {
4829 Status
= ScsiDiskAsyncRead10 (
4832 Request
->TimesRetry
,
4834 Request
->DataLength
,
4835 (UINT32
)Request
->StartLba
,
4836 Request
->SectorCount
,
4841 Status
= ScsiDiskAsyncRead16 (
4844 Request
->TimesRetry
,
4846 Request
->DataLength
,
4848 Request
->SectorCount
,
4854 if (EFI_ERROR (Status
)) {
4855 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4857 } else if (OldSectorCount
!= Request
->SectorCount
) {
4859 // Original sub-task will be split into two new sub-tasks with smaller
4862 if (!ScsiDiskDevice
->Cdb16Byte
) {
4863 Status
= ScsiDiskAsyncRead10 (
4867 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4868 OldDataLength
- Request
->DataLength
,
4869 (UINT32
)Request
->StartLba
+ Request
->SectorCount
,
4870 OldSectorCount
- Request
->SectorCount
,
4875 Status
= ScsiDiskAsyncRead16 (
4879 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4880 OldDataLength
- Request
->DataLength
,
4881 Request
->StartLba
+ Request
->SectorCount
,
4882 OldSectorCount
- Request
->SectorCount
,
4888 if (EFI_ERROR (Status
)) {
4889 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4895 // SCSI write command
4897 if (!ScsiDiskDevice
->Cdb16Byte
) {
4898 Status
= ScsiDiskAsyncWrite10 (
4901 Request
->TimesRetry
,
4903 Request
->DataLength
,
4904 (UINT32
)Request
->StartLba
,
4905 Request
->SectorCount
,
4910 Status
= ScsiDiskAsyncWrite16 (
4913 Request
->TimesRetry
,
4915 Request
->DataLength
,
4917 Request
->SectorCount
,
4923 if (EFI_ERROR (Status
)) {
4924 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4926 } else if (OldSectorCount
!= Request
->SectorCount
) {
4928 // Original sub-task will be split into two new sub-tasks with smaller
4931 if (!ScsiDiskDevice
->Cdb16Byte
) {
4932 Status
= ScsiDiskAsyncWrite10 (
4936 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4937 OldDataLength
- Request
->DataLength
,
4938 (UINT32
)Request
->StartLba
+ Request
->SectorCount
,
4939 OldSectorCount
- Request
->SectorCount
,
4944 Status
= ScsiDiskAsyncWrite16 (
4948 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4949 OldDataLength
- Request
->DataLength
,
4950 Request
->StartLba
+ Request
->SectorCount
,
4951 OldSectorCount
- Request
->SectorCount
,
4957 if (EFI_ERROR (Status
)) {
4958 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4965 RemoveEntryList (&Request
->Link
);
4966 if ((IsListEmpty (&Request
->BlkIo2Req
->ScsiRWQueue
)) &&
4967 (Request
->BlkIo2Req
->LastScsiRW
))
4970 // The last SCSI R/W command of a BlockIo2 request completes
4972 RemoveEntryList (&Request
->BlkIo2Req
->Link
);
4973 FreePool (Request
->BlkIo2Req
); // Should be freed only once
4974 gBS
->SignalEvent (Token
->Event
);
4977 FreePool (Request
->SenseData
);
4982 Submit Async Read(10) command.
4984 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4985 @param Timeout The time to complete the command.
4986 @param TimesRetry The number of times the command has been retried.
4987 @param DataBuffer The buffer to fill with the read out data.
4988 @param DataLength The length of buffer.
4989 @param StartLba The start logic block address.
4990 @param SectorCount The number of blocks to read.
4991 @param BlkIo2Req The upstream BlockIo2 request.
4992 @param Token The pointer to the token associated with the
4993 non-blocking read request.
4995 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4997 @return others Status returned by calling
4998 ScsiRead10CommandEx().
5002 ScsiDiskAsyncRead10 (
5003 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5005 IN UINT8 TimesRetry
,
5006 OUT UINT8
*DataBuffer
,
5007 IN UINT32 DataLength
,
5009 IN UINT32 SectorCount
,
5010 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
5011 IN EFI_BLOCK_IO2_TOKEN
*Token
5015 SCSI_ASYNC_RW_REQUEST
*Request
;
5016 EFI_EVENT AsyncIoEvent
;
5019 AsyncIoEvent
= NULL
;
5021 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
5022 if (Request
== NULL
) {
5023 return EFI_OUT_OF_RESOURCES
;
5026 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5027 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
5028 gBS
->RestoreTPL (OldTpl
);
5030 Request
->SenseDataLength
= (UINT8
)(6 * sizeof (EFI_SCSI_SENSE_DATA
));
5031 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
5032 if (Request
->SenseData
== NULL
) {
5033 Status
= EFI_OUT_OF_RESOURCES
;
5037 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
5038 Request
->Timeout
= Timeout
;
5039 Request
->TimesRetry
= TimesRetry
;
5040 Request
->InBuffer
= DataBuffer
;
5041 Request
->DataLength
= DataLength
;
5042 Request
->StartLba
= StartLba
;
5043 Request
->SectorCount
= SectorCount
;
5044 Request
->BlkIo2Req
= BlkIo2Req
;
5049 Status
= gBS
->CreateEvent (
5056 if (EFI_ERROR (Status
)) {
5060 Status
= ScsiRead10CommandEx (
5061 ScsiDiskDevice
->ScsiIo
,
5064 &Request
->SenseDataLength
,
5065 &Request
->HostAdapterStatus
,
5066 &Request
->TargetStatus
,
5068 &Request
->DataLength
,
5069 (UINT32
)Request
->StartLba
,
5070 Request
->SectorCount
,
5073 if (EFI_ERROR (Status
)) {
5080 if (AsyncIoEvent
!= NULL
) {
5081 gBS
->CloseEvent (AsyncIoEvent
);
5084 if (Request
!= NULL
) {
5085 if (Request
->SenseData
!= NULL
) {
5086 FreePool (Request
->SenseData
);
5089 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5090 RemoveEntryList (&Request
->Link
);
5091 gBS
->RestoreTPL (OldTpl
);
5100 Submit Async Write(10) command.
5102 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
5103 @param Timeout The time to complete the command.
5104 @param TimesRetry The number of times the command has been retried.
5105 @param DataBuffer The buffer contains the data to write.
5106 @param DataLength The length of buffer.
5107 @param StartLba The start logic block address.
5108 @param SectorCount The number of blocks to write.
5109 @param BlkIo2Req The upstream BlockIo2 request.
5110 @param Token The pointer to the token associated with the
5111 non-blocking read request.
5113 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
5115 @return others Status returned by calling
5116 ScsiWrite10CommandEx().
5120 ScsiDiskAsyncWrite10 (
5121 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5123 IN UINT8 TimesRetry
,
5124 IN UINT8
*DataBuffer
,
5125 IN UINT32 DataLength
,
5127 IN UINT32 SectorCount
,
5128 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
5129 IN EFI_BLOCK_IO2_TOKEN
*Token
5133 SCSI_ASYNC_RW_REQUEST
*Request
;
5134 EFI_EVENT AsyncIoEvent
;
5137 AsyncIoEvent
= NULL
;
5139 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
5140 if (Request
== NULL
) {
5141 return EFI_OUT_OF_RESOURCES
;
5144 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5145 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
5146 gBS
->RestoreTPL (OldTpl
);
5148 Request
->SenseDataLength
= (UINT8
)(6 * sizeof (EFI_SCSI_SENSE_DATA
));
5149 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
5150 if (Request
->SenseData
== NULL
) {
5151 Status
= EFI_OUT_OF_RESOURCES
;
5155 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
5156 Request
->Timeout
= Timeout
;
5157 Request
->TimesRetry
= TimesRetry
;
5158 Request
->OutBuffer
= DataBuffer
;
5159 Request
->DataLength
= DataLength
;
5160 Request
->StartLba
= StartLba
;
5161 Request
->SectorCount
= SectorCount
;
5162 Request
->BlkIo2Req
= BlkIo2Req
;
5167 Status
= gBS
->CreateEvent (
5174 if (EFI_ERROR (Status
)) {
5178 Status
= ScsiWrite10CommandEx (
5179 ScsiDiskDevice
->ScsiIo
,
5182 &Request
->SenseDataLength
,
5183 &Request
->HostAdapterStatus
,
5184 &Request
->TargetStatus
,
5186 &Request
->DataLength
,
5187 (UINT32
)Request
->StartLba
,
5188 Request
->SectorCount
,
5191 if (EFI_ERROR (Status
)) {
5198 if (AsyncIoEvent
!= NULL
) {
5199 gBS
->CloseEvent (AsyncIoEvent
);
5202 if (Request
!= NULL
) {
5203 if (Request
->SenseData
!= NULL
) {
5204 FreePool (Request
->SenseData
);
5207 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5208 RemoveEntryList (&Request
->Link
);
5209 gBS
->RestoreTPL (OldTpl
);
5218 Submit Async Read(16) command.
5220 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
5221 @param Timeout The time to complete the command.
5222 @param TimesRetry The number of times the command has been retried.
5223 @param DataBuffer The buffer to fill with the read out data.
5224 @param DataLength The length of buffer.
5225 @param StartLba The start logic block address.
5226 @param SectorCount The number of blocks to read.
5227 @param BlkIo2Req The upstream BlockIo2 request.
5228 @param Token The pointer to the token associated with the
5229 non-blocking read request.
5231 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
5233 @return others Status returned by calling
5234 ScsiRead16CommandEx().
5238 ScsiDiskAsyncRead16 (
5239 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5241 IN UINT8 TimesRetry
,
5242 OUT UINT8
*DataBuffer
,
5243 IN UINT32 DataLength
,
5245 IN UINT32 SectorCount
,
5246 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
5247 IN EFI_BLOCK_IO2_TOKEN
*Token
5251 SCSI_ASYNC_RW_REQUEST
*Request
;
5252 EFI_EVENT AsyncIoEvent
;
5255 AsyncIoEvent
= NULL
;
5257 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
5258 if (Request
== NULL
) {
5259 return EFI_OUT_OF_RESOURCES
;
5262 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5263 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
5264 gBS
->RestoreTPL (OldTpl
);
5266 Request
->SenseDataLength
= (UINT8
)(6 * sizeof (EFI_SCSI_SENSE_DATA
));
5267 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
5268 if (Request
->SenseData
== NULL
) {
5269 Status
= EFI_OUT_OF_RESOURCES
;
5273 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
5274 Request
->Timeout
= Timeout
;
5275 Request
->TimesRetry
= TimesRetry
;
5276 Request
->InBuffer
= DataBuffer
;
5277 Request
->DataLength
= DataLength
;
5278 Request
->StartLba
= StartLba
;
5279 Request
->SectorCount
= SectorCount
;
5280 Request
->BlkIo2Req
= BlkIo2Req
;
5285 Status
= gBS
->CreateEvent (
5292 if (EFI_ERROR (Status
)) {
5296 Status
= ScsiRead16CommandEx (
5297 ScsiDiskDevice
->ScsiIo
,
5300 &Request
->SenseDataLength
,
5301 &Request
->HostAdapterStatus
,
5302 &Request
->TargetStatus
,
5304 &Request
->DataLength
,
5306 Request
->SectorCount
,
5309 if (EFI_ERROR (Status
)) {
5316 if (AsyncIoEvent
!= NULL
) {
5317 gBS
->CloseEvent (AsyncIoEvent
);
5320 if (Request
!= NULL
) {
5321 if (Request
->SenseData
!= NULL
) {
5322 FreePool (Request
->SenseData
);
5325 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5326 RemoveEntryList (&Request
->Link
);
5327 gBS
->RestoreTPL (OldTpl
);
5336 Submit Async Write(16) command.
5338 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
5339 @param Timeout The time to complete the command.
5340 @param TimesRetry The number of times the command has been retried.
5341 @param DataBuffer The buffer contains the data to write.
5342 @param DataLength The length of buffer.
5343 @param StartLba The start logic block address.
5344 @param SectorCount The number of blocks to write.
5345 @param BlkIo2Req The upstream BlockIo2 request.
5346 @param Token The pointer to the token associated with the
5347 non-blocking read request.
5349 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
5351 @return others Status returned by calling
5352 ScsiWrite16CommandEx().
5356 ScsiDiskAsyncWrite16 (
5357 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5359 IN UINT8 TimesRetry
,
5360 IN UINT8
*DataBuffer
,
5361 IN UINT32 DataLength
,
5363 IN UINT32 SectorCount
,
5364 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
5365 IN EFI_BLOCK_IO2_TOKEN
*Token
5369 SCSI_ASYNC_RW_REQUEST
*Request
;
5370 EFI_EVENT AsyncIoEvent
;
5373 AsyncIoEvent
= NULL
;
5375 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
5376 if (Request
== NULL
) {
5377 return EFI_OUT_OF_RESOURCES
;
5380 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5381 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
5382 gBS
->RestoreTPL (OldTpl
);
5384 Request
->SenseDataLength
= (UINT8
)(6 * sizeof (EFI_SCSI_SENSE_DATA
));
5385 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
5386 if (Request
->SenseData
== NULL
) {
5387 Status
= EFI_OUT_OF_RESOURCES
;
5391 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
5392 Request
->Timeout
= Timeout
;
5393 Request
->TimesRetry
= TimesRetry
;
5394 Request
->OutBuffer
= DataBuffer
;
5395 Request
->DataLength
= DataLength
;
5396 Request
->StartLba
= StartLba
;
5397 Request
->SectorCount
= SectorCount
;
5398 Request
->BlkIo2Req
= BlkIo2Req
;
5403 Status
= gBS
->CreateEvent (
5410 if (EFI_ERROR (Status
)) {
5414 Status
= ScsiWrite16CommandEx (
5415 ScsiDiskDevice
->ScsiIo
,
5418 &Request
->SenseDataLength
,
5419 &Request
->HostAdapterStatus
,
5420 &Request
->TargetStatus
,
5422 &Request
->DataLength
,
5424 Request
->SectorCount
,
5427 if (EFI_ERROR (Status
)) {
5434 if (AsyncIoEvent
!= NULL
) {
5435 gBS
->CloseEvent (AsyncIoEvent
);
5438 if (Request
!= NULL
) {
5439 if (Request
->SenseData
!= NULL
) {
5440 FreePool (Request
->SenseData
);
5443 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5444 RemoveEntryList (&Request
->Link
);
5445 gBS
->RestoreTPL (OldTpl
);
5454 Check sense key to find if media presents.
5456 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5457 @param SenseCounts The number of sense key
5459 @retval TRUE NOT any media
5460 @retval FALSE Media presents
5464 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5465 IN UINTN SenseCounts
5468 EFI_SCSI_SENSE_DATA
*SensePtr
;
5473 SensePtr
= SenseData
;
5475 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5477 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
5478 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
5480 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
5481 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
))
5495 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5496 @param SenseCounts The number of sense key
5499 @retval FALSE NOT error
5503 ScsiDiskIsMediaError (
5504 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5505 IN UINTN SenseCounts
5508 EFI_SCSI_SENSE_DATA
*SensePtr
;
5513 SensePtr
= SenseData
;
5515 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5516 switch (SensePtr
->Sense_Key
) {
5517 case EFI_SCSI_SK_MEDIUM_ERROR
:
5519 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
5521 switch (SensePtr
->Addnl_Sense_Code
) {
5525 case EFI_SCSI_ASC_MEDIA_ERR1
:
5530 case EFI_SCSI_ASC_MEDIA_ERR2
:
5535 case EFI_SCSI_ASC_MEDIA_ERR3
:
5536 case EFI_SCSI_ASC_MEDIA_ERR4
:
5546 case EFI_SCSI_SK_NOT_READY
:
5548 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5550 switch (SensePtr
->Addnl_Sense_Code
) {
5552 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
5554 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
5575 Check sense key to find if hardware error happens.
5577 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5578 @param SenseCounts The number of sense key
5580 @retval TRUE Hardware error exits.
5581 @retval FALSE NO error.
5585 ScsiDiskIsHardwareError (
5586 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5587 IN UINTN SenseCounts
5590 EFI_SCSI_SENSE_DATA
*SensePtr
;
5595 SensePtr
= SenseData
;
5597 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5599 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
5601 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
5612 Check sense key to find if media has changed.
5614 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5615 @param SenseCounts The number of sense key
5617 @retval TRUE Media is changed.
5618 @retval FALSE Media is NOT changed.
5621 ScsiDiskIsMediaChange (
5622 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5623 IN UINTN SenseCounts
5626 EFI_SCSI_SENSE_DATA
*SensePtr
;
5628 BOOLEAN IsMediaChanged
;
5630 IsMediaChanged
= FALSE
;
5631 SensePtr
= SenseData
;
5633 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5635 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
5636 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
5638 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
5639 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
))
5641 IsMediaChanged
= TRUE
;
5647 return IsMediaChanged
;
5651 Check sense key to find if reset happens.
5653 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5654 @param SenseCounts The number of sense key
5656 @retval TRUE It is reset before.
5657 @retval FALSE It is NOT reset before.
5661 ScsiDiskIsResetBefore (
5662 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5663 IN UINTN SenseCounts
5666 EFI_SCSI_SENSE_DATA
*SensePtr
;
5668 BOOLEAN IsResetBefore
;
5670 IsResetBefore
= FALSE
;
5671 SensePtr
= SenseData
;
5673 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5675 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
5676 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
5678 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
5679 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
))
5681 IsResetBefore
= TRUE
;
5687 return IsResetBefore
;
5691 Check sense key to find if the drive is ready.
5693 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5694 @param SenseCounts The number of sense key
5695 @param RetryLater The flag means if need a retry
5697 @retval TRUE Drive is ready.
5698 @retval FALSE Drive is NOT ready.
5702 ScsiDiskIsDriveReady (
5703 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5704 IN UINTN SenseCounts
,
5705 OUT BOOLEAN
*RetryLater
5708 EFI_SCSI_SENSE_DATA
*SensePtr
;
5713 *RetryLater
= FALSE
;
5714 SensePtr
= SenseData
;
5716 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5717 switch (SensePtr
->Sense_Key
) {
5718 case EFI_SCSI_SK_NOT_READY
:
5720 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5722 switch (SensePtr
->Addnl_Sense_Code
) {
5723 case EFI_SCSI_ASC_NOT_READY
:
5725 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
5727 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
5728 case EFI_SCSI_ASCQ_IN_PROGRESS
:
5730 // Additional Sense Code Qualifier is
5731 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
5739 *RetryLater
= FALSE
;
5762 Check sense key to find if it has sense key.
5764 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
5765 @param SenseCounts - The number of sense key
5767 @retval TRUE It has sense key.
5768 @retval FALSE It has NOT any sense key.
5772 ScsiDiskHaveSenseKey (
5773 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5774 IN UINTN SenseCounts
5777 EFI_SCSI_SENSE_DATA
*SensePtr
;
5779 BOOLEAN HaveSenseKey
;
5781 if (SenseCounts
== 0) {
5782 HaveSenseKey
= FALSE
;
5784 HaveSenseKey
= TRUE
;
5787 SensePtr
= SenseData
;
5789 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5791 // Sense Key is SK_NO_SENSE (0x0)
5793 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
5796 HaveSenseKey
= FALSE
;
5802 return HaveSenseKey
;
5806 Release resource about disk device.
5808 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
5812 ReleaseScsiDiskDeviceResources (
5813 IN SCSI_DISK_DEV
*ScsiDiskDevice
5816 if (ScsiDiskDevice
== NULL
) {
5820 if (ScsiDiskDevice
->SenseData
!= NULL
) {
5821 FreePool (ScsiDiskDevice
->SenseData
);
5822 ScsiDiskDevice
->SenseData
= NULL
;
5825 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
5826 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
5827 ScsiDiskDevice
->ControllerNameTable
= NULL
;
5830 FreePool (ScsiDiskDevice
);
5832 ScsiDiskDevice
= NULL
;
5836 Determine if Block Io & Block Io2 should be produced.
5839 @param ChildHandle Child Handle to retrieve Parent information.
5841 @retval TRUE Should produce Block Io & Block Io2.
5842 @retval FALSE Should not produce Block Io & Block Io2.
5846 DetermineInstallBlockIo (
5847 IN EFI_HANDLE ChildHandle
5850 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
5851 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
5854 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
5855 // check its attribute, logic or physical.
5857 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
5858 if (ExtScsiPassThru
!= NULL
) {
5859 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
5865 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
5866 // check its attribute, logic or physical.
5868 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
5869 if (ScsiPassThru
!= NULL
) {
5870 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
5879 Search protocol database and check to see if the protocol
5880 specified by ProtocolGuid is present on a ControllerHandle and opened by
5881 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
5882 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
5883 will be opened on it.
5886 @param ProtocolGuid ProtocolGuid pointer.
5887 @param ChildHandle Child Handle to retrieve Parent information.
5893 IN EFI_GUID
*ProtocolGuid
,
5894 IN EFI_HANDLE ChildHandle
5901 EFI_HANDLE
*HandleBuffer
;
5904 // Retrieve the list of all handles from the handle database
5906 Status
= gBS
->LocateHandleBuffer (
5914 if (EFI_ERROR (Status
)) {
5919 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
5921 for (Index
= 0; Index
< HandleCount
; Index
++) {
5922 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
5923 if (!EFI_ERROR (Status
)) {
5924 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
5925 if (!EFI_ERROR (Status
)) {
5926 gBS
->FreePool (HandleBuffer
);
5932 gBS
->FreePool (HandleBuffer
);
5937 Determine if EFI Erase Block Protocol should be produced.
5939 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
5940 @param ChildHandle Handle of device.
5942 @retval TRUE Should produce EFI Erase Block Protocol.
5943 @retval FALSE Should not produce EFI Erase Block Protocol.
5947 DetermineInstallEraseBlock (
5948 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5949 IN EFI_HANDLE ChildHandle
5952 UINT8 HostAdapterStatus
;
5954 EFI_STATUS CommandStatus
;
5958 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
5959 UINT8 SenseDataLength
;
5960 UINT32 DataLength16
;
5961 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
5965 CapacityData16
= NULL
;
5968 // UNMAP command is not supported by any of the UFS WLUNs.
5970 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_WLUN
) {
5975 Status
= gBS
->HandleProtocol (
5977 &gEfiDevicePathProtocolGuid
,
5978 (VOID
**)&DevicePathNode
5981 // Device Path protocol must be installed on the device handle.
5983 ASSERT_EFI_ERROR (Status
);
5985 while (!IsDevicePathEndType (DevicePathNode
)) {
5987 // For now, only support Erase Block Protocol on UFS devices.
5989 if ((DevicePathNode
->Type
== MESSAGING_DEVICE_PATH
) &&
5990 (DevicePathNode
->SubType
== MSG_UFS_DP
))
5996 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
6005 // Check whether the erase functionality is enabled on the UFS device.
6007 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
6008 if (CapacityData16
== NULL
) {
6013 SenseDataLength
= 0;
6014 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
6015 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
6017 CommandStatus
= ScsiReadCapacity16Command (
6018 ScsiDiskDevice
->ScsiIo
,
6024 (VOID
*)CapacityData16
,
6029 if (CommandStatus
== EFI_SUCCESS
) {
6031 // Universal Flash Storage (UFS) Version 2.0
6033 // Bits TPE and TPRZ should both be set to enable the erase feature on UFS.
6035 if (((CapacityData16
->LowestAlignLogic2
& BIT7
) == 0) ||
6036 ((CapacityData16
->LowestAlignLogic2
& BIT6
) == 0))
6040 "ScsiDisk EraseBlock: Either TPE or TPRZ is not set: 0x%x.\n",
6041 CapacityData16
->LowestAlignLogic2
6050 "ScsiDisk EraseBlock: ReadCapacity16 failed with status %r.\n",
6059 // Check whether the UFS device server implements the UNMAP command.
6061 if ((ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
== 0) ||
6062 (ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
== 0))
6066 "ScsiDisk EraseBlock: The device server does not implement the UNMAP command.\n"
6074 if (CapacityData16
!= NULL
) {
6075 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
6082 Determine if EFI Storage Security Command Protocol should be produced.
6084 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
6085 @param ChildHandle Handle of device.
6087 @retval TRUE Should produce EFI Storage Security Command Protocol.
6088 @retval FALSE Should not produce EFI Storage Security Command Protocol.
6092 DetermineInstallStorageSecurity (
6093 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
6094 IN EFI_HANDLE ChildHandle
6098 UFS_DEVICE_PATH
*UfsDevice
;
6100 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
6105 Status
= gBS
->HandleProtocol (
6107 &gEfiDevicePathProtocolGuid
,
6108 (VOID
**)&DevicePathNode
6111 // Device Path protocol must be installed on the device handle.
6113 ASSERT_EFI_ERROR (Status
);
6115 while (!IsDevicePathEndType (DevicePathNode
)) {
6117 // For now, only support Storage Security Command Protocol on UFS devices.
6119 if ((DevicePathNode
->Type
== MESSAGING_DEVICE_PATH
) &&
6120 (DevicePathNode
->SubType
== MSG_UFS_DP
))
6122 UfsDevice
= (UFS_DEVICE_PATH
*)DevicePathNode
;
6126 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
6129 if (UfsDevice
== NULL
) {
6134 if (UfsDevice
->Lun
!= UFS_WLUN_RPMB
) {
6143 Provides inquiry information for the controller type.
6145 This function is used by the IDE bus driver to get inquiry data. Data format
6146 of Identify data is defined by the Interface GUID.
6148 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
6149 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
6150 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
6152 @retval EFI_SUCCESS The command was accepted without any errors.
6153 @retval EFI_NOT_FOUND Device does not support this data class
6154 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
6155 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
6160 ScsiDiskInfoInquiry (
6161 IN EFI_DISK_INFO_PROTOCOL
*This
,
6162 IN OUT VOID
*InquiryData
,
6163 IN OUT UINT32
*InquiryDataSize
6167 SCSI_DISK_DEV
*ScsiDiskDevice
;
6169 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
6171 Status
= EFI_BUFFER_TOO_SMALL
;
6172 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
6173 Status
= EFI_SUCCESS
;
6174 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
6177 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
6182 Provides identify information for the controller type.
6184 This function is used by the IDE bus driver to get identify data. Data format
6185 of Identify data is defined by the Interface GUID.
6187 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
6189 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
6190 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
6193 @retval EFI_SUCCESS The command was accepted without any errors.
6194 @retval EFI_NOT_FOUND Device does not support this data class
6195 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
6196 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
6201 ScsiDiskInfoIdentify (
6202 IN EFI_DISK_INFO_PROTOCOL
*This
,
6203 IN OUT VOID
*IdentifyData
,
6204 IN OUT UINT32
*IdentifyDataSize
6208 SCSI_DISK_DEV
*ScsiDiskDevice
;
6210 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
6212 // Physical SCSI bus does not support this data class.
6214 return EFI_NOT_FOUND
;
6217 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
6219 Status
= EFI_BUFFER_TOO_SMALL
;
6220 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
6221 Status
= EFI_SUCCESS
;
6222 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
6225 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
6230 Provides sense data information for the controller type.
6232 This function is used by the IDE bus driver to get sense data.
6233 Data format of Sense data is defined by the Interface GUID.
6235 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
6236 @param[in, out] SenseData Pointer to the SenseData.
6237 @param[in, out] SenseDataSize Size of SenseData in bytes.
6238 @param[out] SenseDataNumber Pointer to the value for the sense data size.
6240 @retval EFI_SUCCESS The command was accepted without any errors.
6241 @retval EFI_NOT_FOUND Device does not support this data class.
6242 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
6243 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
6248 ScsiDiskInfoSenseData (
6249 IN EFI_DISK_INFO_PROTOCOL
*This
,
6250 IN OUT VOID
*SenseData
,
6251 IN OUT UINT32
*SenseDataSize
,
6252 OUT UINT8
*SenseDataNumber
6255 return EFI_NOT_FOUND
;
6259 This function is used by the IDE bus driver to get controller information.
6261 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
6262 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
6263 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
6265 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
6266 @retval EFI_UNSUPPORTED This is not an IDE device.
6271 ScsiDiskInfoWhichIde (
6272 IN EFI_DISK_INFO_PROTOCOL
*This
,
6273 OUT UINT32
*IdeChannel
,
6274 OUT UINT32
*IdeDevice
6277 SCSI_DISK_DEV
*ScsiDiskDevice
;
6279 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
6281 // This is not an IDE physical device.
6283 return EFI_UNSUPPORTED
;
6286 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
6287 *IdeChannel
= ScsiDiskDevice
->Channel
;
6288 *IdeDevice
= ScsiDiskDevice
->Device
;
6294 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
6296 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
6297 implement Identify() interface for DiskInfo protocol. The ATA command is sent
6298 via SCSI Request Packet.
6300 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
6302 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
6303 @retval others Some error occurred during the identification that ATAPI device.
6307 AtapiIdentifyDevice (
6308 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
6311 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
6315 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
6317 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
6318 ZeroMem (Cdb
, sizeof (Cdb
));
6320 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
6321 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
6322 CommandPacket
.Cdb
= Cdb
;
6323 CommandPacket
.CdbLength
= (UINT8
)sizeof (Cdb
);
6324 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
6325 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
6327 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
6331 Initialize the installation of DiskInfo protocol.
6333 This function prepares for the installation of DiskInfo protocol on the child handle.
6334 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
6335 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
6336 to be IDE/AHCI interface GUID.
6338 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
6339 @param ChildHandle Child handle to install DiskInfo protocol.
6343 InitializeInstallDiskInfo (
6344 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
6345 IN EFI_HANDLE ChildHandle
6349 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
6350 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
6351 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
6352 SATA_DEVICE_PATH
*SataDevicePath
;
6353 UINTN IdentifyRetry
;
6355 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathNode
);
6357 // Device Path protocol must be installed on the device handle.
6359 ASSERT_EFI_ERROR (Status
);
6361 // Copy the DiskInfo protocol template.
6363 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
6365 while (!IsDevicePathEnd (DevicePathNode
)) {
6366 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
6367 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
6368 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
6369 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
6370 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
6371 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
)))
6376 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
6377 // with IDE/AHCI interface GUID.
6379 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
6380 if (!EFI_ERROR (Status
)) {
6381 if (DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) {
6383 // We find the valid ATAPI device path
6385 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*)ChildDevicePathNode
;
6386 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
6387 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
6389 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
6391 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
6394 // We find the valid SATA device path
6396 SataDevicePath
= (SATA_DEVICE_PATH
*)ChildDevicePathNode
;
6397 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
6398 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
6400 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
6402 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
6407 } while (--IdentifyRetry
> 0);
6408 } else if ((DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
6409 (DevicePathSubType (ChildDevicePathNode
) == MSG_UFS_DP
))
6411 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoUfsInterfaceGuid
);
6415 DevicePathNode
= ChildDevicePathNode
;