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 SPDX-License-Identifier: BSD-2-Clause-Patent
11 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding
= {
12 ScsiDiskDriverBindingSupported
,
13 ScsiDiskDriverBindingStart
,
14 ScsiDiskDriverBindingStop
,
20 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate
= {
21 EFI_DISK_INFO_SCSI_INTERFACE_GUID
,
24 ScsiDiskInfoSenseData
,
29 Allocates an aligned buffer for SCSI disk.
31 This function allocates an aligned buffer for the SCSI disk to perform
32 SCSI IO operations. The alignment requirement is from SCSI IO interface.
34 @param ScsiDiskDevice The SCSI disk involved for the operation.
35 @param BufferSize The request buffer size.
37 @return A pointer to the aligned buffer or NULL if the allocation fails.
41 AllocateAlignedBuffer (
42 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
46 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), ScsiDiskDevice
->ScsiIo
->IoAlign
);
50 Frees an aligned buffer for SCSI disk.
52 This function frees an aligned buffer for the SCSI disk to perform
55 @param Buffer The aligned buffer to be freed.
56 @param BufferSize The request buffer size.
66 FreeAlignedPages (Buffer
, EFI_SIZE_TO_PAGES (BufferSize
));
71 The user Entry Point for module ScsiDisk.
73 The user code starts with this function.
75 @param ImageHandle The firmware allocated handle for the EFI image.
76 @param SystemTable A pointer to the EFI System Table.
78 @retval EFI_SUCCESS The entry point is executed successfully.
79 @retval other Some error occurs when executing this entry point.
85 IN EFI_HANDLE ImageHandle
,
86 IN EFI_SYSTEM_TABLE
*SystemTable
92 // Install driver model protocol(s).
94 Status
= EfiLibInstallDriverBindingComponentName2 (
97 &gScsiDiskDriverBinding
,
99 &gScsiDiskComponentName
,
100 &gScsiDiskComponentName2
102 ASSERT_EFI_ERROR (Status
);
108 Test to see if this driver supports ControllerHandle.
110 This service is called by the EFI boot service ConnectController(). In order
111 to make drivers as small as possible, there are a few calling restrictions for
112 this service. ConnectController() must follow these calling restrictions.
113 If any other agent wishes to call Supported() it must also follow these
114 calling restrictions.
116 @param This Protocol instance pointer.
117 @param ControllerHandle Handle of device to test
118 @param RemainingDevicePath Optional parameter use to pick a specific child
121 @retval EFI_SUCCESS This driver supports this device
122 @retval EFI_ALREADY_STARTED This driver is already running on this device
123 @retval other This driver does not support this device
128 ScsiDiskDriverBindingSupported (
129 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
130 IN EFI_HANDLE Controller
,
131 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
135 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
138 Status
= gBS
->OpenProtocol (
140 &gEfiScsiIoProtocolGuid
,
142 This
->DriverBindingHandle
,
144 EFI_OPEN_PROTOCOL_BY_DRIVER
146 if (EFI_ERROR (Status
)) {
150 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
151 if (!EFI_ERROR (Status
)) {
152 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) ||
153 (DeviceType
== EFI_SCSI_TYPE_CDROM
) ||
154 (DeviceType
== EFI_SCSI_TYPE_WLUN
))
156 Status
= EFI_SUCCESS
;
158 Status
= EFI_UNSUPPORTED
;
164 &gEfiScsiIoProtocolGuid
,
165 This
->DriverBindingHandle
,
172 Start this driver on ControllerHandle.
174 This service is called by the EFI boot service ConnectController(). In order
175 to make drivers as small as possible, there are a few calling restrictions for
176 this service. ConnectController() must follow these calling restrictions. If
177 any other agent wishes to call Start() it must also follow these calling
180 @param This Protocol instance pointer.
181 @param ControllerHandle Handle of device to bind driver to
182 @param RemainingDevicePath Optional parameter use to pick a specific child
185 @retval EFI_SUCCESS This driver is added to ControllerHandle
186 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
187 @retval other This driver does not support this device
192 ScsiDiskDriverBindingStart (
193 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
194 IN EFI_HANDLE Controller
,
195 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
199 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
200 SCSI_DISK_DEV
*ScsiDiskDevice
;
205 BOOLEAN MustReadCapacity
;
207 MustReadCapacity
= TRUE
;
209 ScsiDiskDevice
= (SCSI_DISK_DEV
*)AllocateZeroPool (sizeof (SCSI_DISK_DEV
));
210 if (ScsiDiskDevice
== NULL
) {
211 return EFI_OUT_OF_RESOURCES
;
214 Status
= gBS
->OpenProtocol (
216 &gEfiScsiIoProtocolGuid
,
218 This
->DriverBindingHandle
,
220 EFI_OPEN_PROTOCOL_BY_DRIVER
222 if (EFI_ERROR (Status
)) {
223 FreePool (ScsiDiskDevice
);
227 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
228 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
229 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION3
;
230 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
231 ScsiDiskDevice
->BlkIo
.Media
->IoAlign
= ScsiIo
->IoAlign
;
232 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
233 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
234 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
235 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
236 ScsiDiskDevice
->BlkIo2
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
237 ScsiDiskDevice
->BlkIo2
.Reset
= ScsiDiskResetEx
;
238 ScsiDiskDevice
->BlkIo2
.ReadBlocksEx
= ScsiDiskReadBlocksEx
;
239 ScsiDiskDevice
->BlkIo2
.WriteBlocksEx
= ScsiDiskWriteBlocksEx
;
240 ScsiDiskDevice
->BlkIo2
.FlushBlocksEx
= ScsiDiskFlushBlocksEx
;
241 ScsiDiskDevice
->StorageSecurity
.ReceiveData
= ScsiDiskReceiveData
;
242 ScsiDiskDevice
->StorageSecurity
.SendData
= ScsiDiskSendData
;
243 ScsiDiskDevice
->EraseBlock
.Revision
= EFI_ERASE_BLOCK_PROTOCOL_REVISION
;
244 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
= 1;
245 ScsiDiskDevice
->EraseBlock
.EraseBlocks
= ScsiDiskEraseBlocks
;
246 ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
= 1;
247 ScsiDiskDevice
->BlockLimitsVpdSupported
= FALSE
;
248 ScsiDiskDevice
->Handle
= Controller
;
249 InitializeListHead (&ScsiDiskDevice
->AsyncTaskQueue
);
251 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
252 switch (ScsiDiskDevice
->DeviceType
) {
253 case EFI_SCSI_TYPE_DISK
:
254 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
255 MustReadCapacity
= TRUE
;
258 case EFI_SCSI_TYPE_CDROM
:
259 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
260 ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
= TRUE
;
261 MustReadCapacity
= FALSE
;
264 case EFI_SCSI_TYPE_WLUN
:
265 MustReadCapacity
= FALSE
;
270 // The Sense Data Array's initial size is 6
272 ScsiDiskDevice
->SenseDataNumber
= 6;
273 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*)AllocateZeroPool (
274 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
276 if (ScsiDiskDevice
->SenseData
== NULL
) {
279 &gEfiScsiIoProtocolGuid
,
280 This
->DriverBindingHandle
,
283 FreePool (ScsiDiskDevice
);
284 return EFI_OUT_OF_RESOURCES
;
288 // Retrieve device information
291 for (Index
= 0; Index
< MaxRetry
; Index
++) {
292 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
293 if (!EFI_ERROR (Status
)) {
298 FreePool (ScsiDiskDevice
->SenseData
);
301 &gEfiScsiIoProtocolGuid
,
302 This
->DriverBindingHandle
,
305 FreePool (ScsiDiskDevice
);
306 return EFI_DEVICE_ERROR
;
311 // The second parameter "TRUE" means must
312 // retrieve media capacity
314 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, MustReadCapacity
, &Temp
);
315 if (!EFI_ERROR (Status
)) {
317 // Determine if Block IO & Block IO2 should be produced on this controller
320 if (DetermineInstallBlockIo (Controller
)) {
321 InitializeInstallDiskInfo (ScsiDiskDevice
, Controller
);
322 Status
= gBS
->InstallMultipleProtocolInterfaces (
324 &gEfiBlockIoProtocolGuid
,
325 &ScsiDiskDevice
->BlkIo
,
326 &gEfiBlockIo2ProtocolGuid
,
327 &ScsiDiskDevice
->BlkIo2
,
328 &gEfiDiskInfoProtocolGuid
,
329 &ScsiDiskDevice
->DiskInfo
,
332 if (!EFI_ERROR (Status
)) {
333 if (DetermineInstallEraseBlock (ScsiDiskDevice
, Controller
)) {
334 Status
= gBS
->InstallProtocolInterface (
336 &gEfiEraseBlockProtocolGuid
,
337 EFI_NATIVE_INTERFACE
,
338 &ScsiDiskDevice
->EraseBlock
340 if (EFI_ERROR (Status
)) {
341 DEBUG ((DEBUG_ERROR
, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", Status
));
345 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, Controller
)) {
346 Status
= gBS
->InstallProtocolInterface (
348 &gEfiStorageSecurityCommandProtocolGuid
,
349 EFI_NATIVE_INTERFACE
,
350 &ScsiDiskDevice
->StorageSecurity
352 if (EFI_ERROR (Status
)) {
353 DEBUG ((DEBUG_ERROR
, "ScsiDisk: Failed to install the Storage Security Command Protocol! Status = %r\n", Status
));
357 ScsiDiskDevice
->ControllerNameTable
= NULL
;
360 gScsiDiskComponentName
.SupportedLanguages
,
361 &ScsiDiskDevice
->ControllerNameTable
,
367 gScsiDiskComponentName2
.SupportedLanguages
,
368 &ScsiDiskDevice
->ControllerNameTable
,
377 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
378 gBS
->FreePool (ScsiDiskDevice
);
381 &gEfiScsiIoProtocolGuid
,
382 This
->DriverBindingHandle
,
389 Stop this driver on ControllerHandle.
391 This service is called by the EFI boot service DisconnectController().
392 In order to make drivers as small as possible, there are a few calling
393 restrictions for this service. DisconnectController() must follow these
394 calling restrictions. If any other agent wishes to call Stop() it must
395 also follow these calling restrictions.
397 @param This Protocol instance pointer.
398 @param ControllerHandle Handle of device to stop driver on
399 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
400 children is zero stop the entire bus driver.
401 @param ChildHandleBuffer List of Child Handles to Stop.
403 @retval EFI_SUCCESS This driver is removed ControllerHandle
404 @retval other This driver was not removed from this device
409 ScsiDiskDriverBindingStop (
410 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
411 IN EFI_HANDLE Controller
,
412 IN UINTN NumberOfChildren
,
413 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
416 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
417 EFI_ERASE_BLOCK_PROTOCOL
*EraseBlock
;
418 SCSI_DISK_DEV
*ScsiDiskDevice
;
421 Status
= gBS
->OpenProtocol (
423 &gEfiBlockIoProtocolGuid
,
425 This
->DriverBindingHandle
,
427 EFI_OPEN_PROTOCOL_GET_PROTOCOL
429 if (EFI_ERROR (Status
)) {
433 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (BlkIo
);
436 // Wait for the BlockIo2 requests queue to become empty
438 while (!IsListEmpty (&ScsiDiskDevice
->AsyncTaskQueue
)) {
442 // If Erase Block Protocol is installed, then uninstall this protocol.
444 Status
= gBS
->OpenProtocol (
446 &gEfiEraseBlockProtocolGuid
,
447 (VOID
**)&EraseBlock
,
448 This
->DriverBindingHandle
,
450 EFI_OPEN_PROTOCOL_GET_PROTOCOL
453 if (!EFI_ERROR (Status
)) {
454 Status
= gBS
->UninstallProtocolInterface (
456 &gEfiEraseBlockProtocolGuid
,
457 &ScsiDiskDevice
->EraseBlock
459 if (EFI_ERROR (Status
)) {
464 Status
= gBS
->UninstallMultipleProtocolInterfaces (
466 &gEfiBlockIoProtocolGuid
,
467 &ScsiDiskDevice
->BlkIo
,
468 &gEfiBlockIo2ProtocolGuid
,
469 &ScsiDiskDevice
->BlkIo2
,
470 &gEfiDiskInfoProtocolGuid
,
471 &ScsiDiskDevice
->DiskInfo
,
474 if (!EFI_ERROR (Status
)) {
477 &gEfiScsiIoProtocolGuid
,
478 This
->DriverBindingHandle
,
482 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
497 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
498 @param ExtendedVerification The flag about if extend verificate
500 @retval EFI_SUCCESS The device was reset.
501 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
503 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
509 IN EFI_BLOCK_IO_PROTOCOL
*This
,
510 IN BOOLEAN ExtendedVerification
514 SCSI_DISK_DEV
*ScsiDiskDevice
;
517 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
519 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
521 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
523 if (EFI_ERROR (Status
)) {
524 if (Status
== EFI_UNSUPPORTED
) {
525 Status
= EFI_SUCCESS
;
527 Status
= EFI_DEVICE_ERROR
;
532 if (!ExtendedVerification
) {
536 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
538 if (EFI_ERROR (Status
)) {
539 Status
= EFI_DEVICE_ERROR
;
544 gBS
->RestoreTPL (OldTpl
);
549 The function is to Read Block from SCSI Disk.
551 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
552 @param MediaId The Id of Media detected
553 @param Lba The logic block address
554 @param BufferSize The size of Buffer
555 @param Buffer The buffer to fill the read out data
557 @retval EFI_SUCCESS Successfully to read out block.
558 @retval EFI_DEVICE_ERROR Fail to detect media.
559 @retval EFI_NO_MEDIA Media is not present.
560 @retval EFI_MEDIA_CHANGED Media has changed.
561 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
562 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
568 IN EFI_BLOCK_IO_PROTOCOL
*This
,
575 SCSI_DISK_DEV
*ScsiDiskDevice
;
576 EFI_BLOCK_IO_MEDIA
*Media
;
579 UINTN NumberOfBlocks
;
584 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
585 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
586 Media
= ScsiDiskDevice
->BlkIo
.Media
;
588 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
589 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
590 if (EFI_ERROR (Status
)) {
591 Status
= EFI_DEVICE_ERROR
;
596 gBS
->ReinstallProtocolInterface (
597 ScsiDiskDevice
->Handle
,
598 &gEfiBlockIoProtocolGuid
,
599 &ScsiDiskDevice
->BlkIo
,
600 &ScsiDiskDevice
->BlkIo
602 gBS
->ReinstallProtocolInterface (
603 ScsiDiskDevice
->Handle
,
604 &gEfiBlockIo2ProtocolGuid
,
605 &ScsiDiskDevice
->BlkIo2
,
606 &ScsiDiskDevice
->BlkIo2
608 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
609 gBS
->ReinstallProtocolInterface (
610 ScsiDiskDevice
->Handle
,
611 &gEfiEraseBlockProtocolGuid
,
612 &ScsiDiskDevice
->EraseBlock
,
613 &ScsiDiskDevice
->EraseBlock
617 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
618 gBS
->ReinstallProtocolInterface (
619 ScsiDiskDevice
->Handle
,
620 &gEfiStorageSecurityCommandProtocolGuid
,
621 &ScsiDiskDevice
->StorageSecurity
,
622 &ScsiDiskDevice
->StorageSecurity
626 if (Media
->MediaPresent
) {
627 Status
= EFI_MEDIA_CHANGED
;
629 Status
= EFI_NO_MEDIA
;
637 // Get the intrinsic block size
639 BlockSize
= Media
->BlockSize
;
641 if (BlockSize
== 0) {
642 Status
= EFI_DEVICE_ERROR
;
646 NumberOfBlocks
= BufferSize
/ BlockSize
;
648 if (!(Media
->MediaPresent
)) {
649 Status
= EFI_NO_MEDIA
;
653 if (MediaId
!= Media
->MediaId
) {
654 Status
= EFI_MEDIA_CHANGED
;
658 if (Buffer
== NULL
) {
659 Status
= EFI_INVALID_PARAMETER
;
663 if (BufferSize
== 0) {
664 Status
= EFI_SUCCESS
;
668 if (BufferSize
% BlockSize
!= 0) {
669 Status
= EFI_BAD_BUFFER_SIZE
;
673 if (Lba
> Media
->LastBlock
) {
674 Status
= EFI_INVALID_PARAMETER
;
678 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
679 Status
= EFI_INVALID_PARAMETER
;
683 if ((Media
->IoAlign
> 1) && (((UINTN
)Buffer
& (Media
->IoAlign
- 1)) != 0)) {
684 Status
= EFI_INVALID_PARAMETER
;
689 // If all the parameters are valid, then perform read sectors command
690 // to transfer data from device to host.
692 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
695 gBS
->RestoreTPL (OldTpl
);
700 The function is to Write Block to SCSI Disk.
702 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
703 @param MediaId The Id of Media detected
704 @param Lba The logic block address
705 @param BufferSize The size of Buffer
706 @param Buffer The buffer to fill the read out data
708 @retval EFI_SUCCESS Successfully to read out block.
709 @retval EFI_WRITE_PROTECTED The device can not be written to.
710 @retval EFI_DEVICE_ERROR Fail to detect media.
711 @retval EFI_NO_MEDIA Media is not present.
712 @retval EFI_MEDIA_CHANGED Media has changed.
713 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
714 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
719 ScsiDiskWriteBlocks (
720 IN EFI_BLOCK_IO_PROTOCOL
*This
,
727 SCSI_DISK_DEV
*ScsiDiskDevice
;
728 EFI_BLOCK_IO_MEDIA
*Media
;
731 UINTN NumberOfBlocks
;
736 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
737 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
738 Media
= ScsiDiskDevice
->BlkIo
.Media
;
740 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
741 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
742 if (EFI_ERROR (Status
)) {
743 Status
= EFI_DEVICE_ERROR
;
748 gBS
->ReinstallProtocolInterface (
749 ScsiDiskDevice
->Handle
,
750 &gEfiBlockIoProtocolGuid
,
751 &ScsiDiskDevice
->BlkIo
,
752 &ScsiDiskDevice
->BlkIo
754 gBS
->ReinstallProtocolInterface (
755 ScsiDiskDevice
->Handle
,
756 &gEfiBlockIo2ProtocolGuid
,
757 &ScsiDiskDevice
->BlkIo2
,
758 &ScsiDiskDevice
->BlkIo2
760 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
761 gBS
->ReinstallProtocolInterface (
762 ScsiDiskDevice
->Handle
,
763 &gEfiEraseBlockProtocolGuid
,
764 &ScsiDiskDevice
->EraseBlock
,
765 &ScsiDiskDevice
->EraseBlock
769 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
770 gBS
->ReinstallProtocolInterface (
771 ScsiDiskDevice
->Handle
,
772 &gEfiStorageSecurityCommandProtocolGuid
,
773 &ScsiDiskDevice
->StorageSecurity
,
774 &ScsiDiskDevice
->StorageSecurity
778 if (Media
->MediaPresent
) {
779 Status
= EFI_MEDIA_CHANGED
;
781 Status
= EFI_NO_MEDIA
;
789 // Get the intrinsic block size
791 BlockSize
= Media
->BlockSize
;
793 if (BlockSize
== 0) {
794 Status
= EFI_DEVICE_ERROR
;
798 NumberOfBlocks
= BufferSize
/ BlockSize
;
800 if (!(Media
->MediaPresent
)) {
801 Status
= EFI_NO_MEDIA
;
805 if (MediaId
!= Media
->MediaId
) {
806 Status
= EFI_MEDIA_CHANGED
;
810 if (Media
->ReadOnly
) {
811 Status
= EFI_WRITE_PROTECTED
;
815 if (BufferSize
== 0) {
816 Status
= EFI_SUCCESS
;
820 if (Buffer
== NULL
) {
821 Status
= EFI_INVALID_PARAMETER
;
825 if (BufferSize
% BlockSize
!= 0) {
826 Status
= EFI_BAD_BUFFER_SIZE
;
830 if (Lba
> Media
->LastBlock
) {
831 Status
= EFI_INVALID_PARAMETER
;
835 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
836 Status
= EFI_INVALID_PARAMETER
;
840 if ((Media
->IoAlign
> 1) && (((UINTN
)Buffer
& (Media
->IoAlign
- 1)) != 0)) {
841 Status
= EFI_INVALID_PARAMETER
;
846 // if all the parameters are valid, then perform read sectors command
847 // to transfer data from device to host.
849 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
852 gBS
->RestoreTPL (OldTpl
);
859 EFI_SUCCESS is returned directly.
861 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
863 @retval EFI_SUCCESS All outstanding data was written to the device
868 ScsiDiskFlushBlocks (
869 IN EFI_BLOCK_IO_PROTOCOL
*This
881 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
882 @param ExtendedVerification The flag about if extend verificate.
884 @retval EFI_SUCCESS The device was reset.
885 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
887 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
893 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
894 IN BOOLEAN ExtendedVerification
898 SCSI_DISK_DEV
*ScsiDiskDevice
;
901 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
903 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
905 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
907 if (EFI_ERROR (Status
)) {
908 if (Status
== EFI_UNSUPPORTED
) {
909 Status
= EFI_SUCCESS
;
911 Status
= EFI_DEVICE_ERROR
;
916 if (!ExtendedVerification
) {
920 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
922 if (EFI_ERROR (Status
)) {
923 Status
= EFI_DEVICE_ERROR
;
928 gBS
->RestoreTPL (OldTpl
);
933 The function is to Read Block from SCSI Disk.
935 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
936 @param MediaId The Id of Media detected.
937 @param Lba The logic block address.
938 @param Token A pointer to the token associated with the transaction.
939 @param BufferSize The size of Buffer.
940 @param Buffer The buffer to fill the read out data.
942 @retval EFI_SUCCESS The read request was queued if Token-> Event is
943 not NULL. The data was read correctly from the
944 device if theToken-> Event is NULL.
945 @retval EFI_DEVICE_ERROR The device reported an error while attempting
946 to perform the read operation.
947 @retval EFI_NO_MEDIA There is no media in the device.
948 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
949 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
950 the intrinsic block size of the device.
951 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
952 valid, or the buffer is not on proper
954 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
960 ScsiDiskReadBlocksEx (
961 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
964 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
969 SCSI_DISK_DEV
*ScsiDiskDevice
;
970 EFI_BLOCK_IO_MEDIA
*Media
;
973 UINTN NumberOfBlocks
;
978 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
979 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
980 Media
= ScsiDiskDevice
->BlkIo
.Media
;
982 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
983 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
984 if (EFI_ERROR (Status
)) {
985 Status
= EFI_DEVICE_ERROR
;
990 gBS
->ReinstallProtocolInterface (
991 ScsiDiskDevice
->Handle
,
992 &gEfiBlockIoProtocolGuid
,
993 &ScsiDiskDevice
->BlkIo
,
994 &ScsiDiskDevice
->BlkIo
996 gBS
->ReinstallProtocolInterface (
997 ScsiDiskDevice
->Handle
,
998 &gEfiBlockIo2ProtocolGuid
,
999 &ScsiDiskDevice
->BlkIo2
,
1000 &ScsiDiskDevice
->BlkIo2
1002 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1003 gBS
->ReinstallProtocolInterface (
1004 ScsiDiskDevice
->Handle
,
1005 &gEfiEraseBlockProtocolGuid
,
1006 &ScsiDiskDevice
->EraseBlock
,
1007 &ScsiDiskDevice
->EraseBlock
1011 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1012 gBS
->ReinstallProtocolInterface (
1013 ScsiDiskDevice
->Handle
,
1014 &gEfiStorageSecurityCommandProtocolGuid
,
1015 &ScsiDiskDevice
->StorageSecurity
,
1016 &ScsiDiskDevice
->StorageSecurity
1020 if (Media
->MediaPresent
) {
1021 Status
= EFI_MEDIA_CHANGED
;
1023 Status
= EFI_NO_MEDIA
;
1031 // Get the intrinsic block size
1033 BlockSize
= Media
->BlockSize
;
1035 if (BlockSize
== 0) {
1036 Status
= EFI_DEVICE_ERROR
;
1040 NumberOfBlocks
= BufferSize
/ BlockSize
;
1042 if (!(Media
->MediaPresent
)) {
1043 Status
= EFI_NO_MEDIA
;
1047 if (MediaId
!= Media
->MediaId
) {
1048 Status
= EFI_MEDIA_CHANGED
;
1052 if (Buffer
== NULL
) {
1053 Status
= EFI_INVALID_PARAMETER
;
1057 if (BufferSize
== 0) {
1058 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1059 Token
->TransactionStatus
= EFI_SUCCESS
;
1060 gBS
->SignalEvent (Token
->Event
);
1063 Status
= EFI_SUCCESS
;
1067 if (BufferSize
% BlockSize
!= 0) {
1068 Status
= EFI_BAD_BUFFER_SIZE
;
1072 if (Lba
> Media
->LastBlock
) {
1073 Status
= EFI_INVALID_PARAMETER
;
1077 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1078 Status
= EFI_INVALID_PARAMETER
;
1082 if ((Media
->IoAlign
> 1) && (((UINTN
)Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1083 Status
= EFI_INVALID_PARAMETER
;
1088 // If all the parameters are valid, then perform read sectors command
1089 // to transfer data from device to host.
1091 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1092 Token
->TransactionStatus
= EFI_SUCCESS
;
1093 Status
= ScsiDiskAsyncReadSectors (
1101 Status
= ScsiDiskReadSectors (
1110 gBS
->RestoreTPL (OldTpl
);
1115 The function is to Write Block to SCSI Disk.
1117 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
1118 @param MediaId The Id of Media detected.
1119 @param Lba The logic block address.
1120 @param Token A pointer to the token associated with the transaction.
1121 @param BufferSize The size of Buffer.
1122 @param Buffer The buffer to fill the read out data.
1124 @retval EFI_SUCCESS The data were written correctly to the device.
1125 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1126 @retval EFI_NO_MEDIA There is no media in the device.
1127 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1128 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1129 to perform the write operation.
1130 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
1131 the intrinsic block size of the device.
1132 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
1133 valid, or the buffer is not on proper
1139 ScsiDiskWriteBlocksEx (
1140 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1143 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1144 IN UINTN BufferSize
,
1148 SCSI_DISK_DEV
*ScsiDiskDevice
;
1149 EFI_BLOCK_IO_MEDIA
*Media
;
1152 UINTN NumberOfBlocks
;
1153 BOOLEAN MediaChange
;
1156 MediaChange
= FALSE
;
1157 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1158 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1159 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1161 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
1162 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1163 if (EFI_ERROR (Status
)) {
1164 Status
= EFI_DEVICE_ERROR
;
1169 gBS
->ReinstallProtocolInterface (
1170 ScsiDiskDevice
->Handle
,
1171 &gEfiBlockIoProtocolGuid
,
1172 &ScsiDiskDevice
->BlkIo
,
1173 &ScsiDiskDevice
->BlkIo
1175 gBS
->ReinstallProtocolInterface (
1176 ScsiDiskDevice
->Handle
,
1177 &gEfiBlockIo2ProtocolGuid
,
1178 &ScsiDiskDevice
->BlkIo2
,
1179 &ScsiDiskDevice
->BlkIo2
1181 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1182 gBS
->ReinstallProtocolInterface (
1183 ScsiDiskDevice
->Handle
,
1184 &gEfiEraseBlockProtocolGuid
,
1185 &ScsiDiskDevice
->EraseBlock
,
1186 &ScsiDiskDevice
->EraseBlock
1190 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1191 gBS
->ReinstallProtocolInterface (
1192 ScsiDiskDevice
->Handle
,
1193 &gEfiStorageSecurityCommandProtocolGuid
,
1194 &ScsiDiskDevice
->StorageSecurity
,
1195 &ScsiDiskDevice
->StorageSecurity
1199 if (Media
->MediaPresent
) {
1200 Status
= EFI_MEDIA_CHANGED
;
1202 Status
= EFI_NO_MEDIA
;
1210 // Get the intrinsic block size
1212 BlockSize
= Media
->BlockSize
;
1214 if (BlockSize
== 0) {
1215 Status
= EFI_DEVICE_ERROR
;
1219 NumberOfBlocks
= BufferSize
/ BlockSize
;
1221 if (!(Media
->MediaPresent
)) {
1222 Status
= EFI_NO_MEDIA
;
1226 if (MediaId
!= Media
->MediaId
) {
1227 Status
= EFI_MEDIA_CHANGED
;
1231 if (Media
->ReadOnly
) {
1232 Status
= EFI_WRITE_PROTECTED
;
1236 if (BufferSize
== 0) {
1237 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1238 Token
->TransactionStatus
= EFI_SUCCESS
;
1239 gBS
->SignalEvent (Token
->Event
);
1242 Status
= EFI_SUCCESS
;
1246 if (Buffer
== NULL
) {
1247 Status
= EFI_INVALID_PARAMETER
;
1251 if (BufferSize
% BlockSize
!= 0) {
1252 Status
= EFI_BAD_BUFFER_SIZE
;
1256 if (Lba
> Media
->LastBlock
) {
1257 Status
= EFI_INVALID_PARAMETER
;
1261 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1262 Status
= EFI_INVALID_PARAMETER
;
1266 if ((Media
->IoAlign
> 1) && (((UINTN
)Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1267 Status
= EFI_INVALID_PARAMETER
;
1272 // if all the parameters are valid, then perform write sectors command
1273 // to transfer data from device to host.
1275 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1276 Token
->TransactionStatus
= EFI_SUCCESS
;
1277 Status
= ScsiDiskAsyncWriteSectors (
1285 Status
= ScsiDiskWriteSectors (
1294 gBS
->RestoreTPL (OldTpl
);
1299 Flush the Block Device.
1301 @param This Indicates a pointer to the calling context.
1302 @param Token A pointer to the token associated with the transaction.
1304 @retval EFI_SUCCESS All outstanding data was written to the device.
1305 @retval EFI_DEVICE_ERROR The device reported an error while attempting to
1307 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1308 @retval EFI_NO_MEDIA There is no media in the device.
1309 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1314 ScsiDiskFlushBlocksEx (
1315 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1316 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1319 SCSI_DISK_DEV
*ScsiDiskDevice
;
1320 EFI_BLOCK_IO_MEDIA
*Media
;
1322 BOOLEAN MediaChange
;
1325 MediaChange
= FALSE
;
1326 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1327 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1328 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1330 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
1331 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1332 if (EFI_ERROR (Status
)) {
1333 Status
= EFI_DEVICE_ERROR
;
1338 gBS
->ReinstallProtocolInterface (
1339 ScsiDiskDevice
->Handle
,
1340 &gEfiBlockIoProtocolGuid
,
1341 &ScsiDiskDevice
->BlkIo
,
1342 &ScsiDiskDevice
->BlkIo
1344 gBS
->ReinstallProtocolInterface (
1345 ScsiDiskDevice
->Handle
,
1346 &gEfiBlockIo2ProtocolGuid
,
1347 &ScsiDiskDevice
->BlkIo2
,
1348 &ScsiDiskDevice
->BlkIo2
1350 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1351 gBS
->ReinstallProtocolInterface (
1352 ScsiDiskDevice
->Handle
,
1353 &gEfiEraseBlockProtocolGuid
,
1354 &ScsiDiskDevice
->EraseBlock
,
1355 &ScsiDiskDevice
->EraseBlock
1359 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1360 gBS
->ReinstallProtocolInterface (
1361 ScsiDiskDevice
->Handle
,
1362 &gEfiStorageSecurityCommandProtocolGuid
,
1363 &ScsiDiskDevice
->StorageSecurity
,
1364 &ScsiDiskDevice
->StorageSecurity
1368 if (Media
->MediaPresent
) {
1369 Status
= EFI_MEDIA_CHANGED
;
1371 Status
= EFI_NO_MEDIA
;
1378 if (!(Media
->MediaPresent
)) {
1379 Status
= EFI_NO_MEDIA
;
1383 if (Media
->ReadOnly
) {
1384 Status
= EFI_WRITE_PROTECTED
;
1389 // Wait for the BlockIo2 requests queue to become empty
1391 while (!IsListEmpty (&ScsiDiskDevice
->AsyncTaskQueue
)) {
1394 Status
= EFI_SUCCESS
;
1397 // Signal caller event
1399 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1400 Token
->TransactionStatus
= EFI_SUCCESS
;
1401 gBS
->SignalEvent (Token
->Event
);
1405 gBS
->RestoreTPL (OldTpl
);
1410 Internal helper notify function which process the result of an asynchronous
1411 SCSI UNMAP Command and signal the event passed from EraseBlocks.
1413 @param Event The instance of EFI_EVENT.
1414 @param Context The parameter passed in.
1419 ScsiDiskAsyncUnmapNotify (
1424 SCSI_ERASEBLK_REQUEST
*EraseBlkReq
;
1425 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*CommandPacket
;
1426 EFI_ERASE_BLOCK_TOKEN
*Token
;
1429 gBS
->CloseEvent (Event
);
1431 EraseBlkReq
= (SCSI_ERASEBLK_REQUEST
*)Context
;
1432 CommandPacket
= &EraseBlkReq
->CommandPacket
;
1433 Token
= EraseBlkReq
->Token
;
1434 Token
->TransactionStatus
= EFI_SUCCESS
;
1436 Status
= CheckHostAdapterStatus (CommandPacket
->HostAdapterStatus
);
1437 if (EFI_ERROR (Status
)) {
1440 "ScsiDiskAsyncUnmapNotify: Host adapter indicating error status 0x%x.\n",
1441 CommandPacket
->HostAdapterStatus
1444 Token
->TransactionStatus
= Status
;
1448 Status
= CheckTargetStatus (CommandPacket
->TargetStatus
);
1449 if (EFI_ERROR (Status
)) {
1452 "ScsiDiskAsyncUnmapNotify: Target indicating error status 0x%x.\n",
1453 CommandPacket
->HostAdapterStatus
1456 Token
->TransactionStatus
= Status
;
1461 RemoveEntryList (&EraseBlkReq
->Link
);
1462 FreePool (CommandPacket
->OutDataBuffer
);
1463 FreePool (EraseBlkReq
->CommandPacket
.Cdb
);
1464 FreePool (EraseBlkReq
);
1466 gBS
->SignalEvent (Token
->Event
);
1470 Require the device server to cause one or more LBAs to be unmapped.
1472 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
1473 @param Lba The start block number.
1474 @param Blocks Total block number to be unmapped.
1475 @param Token The pointer to the token associated with the
1476 non-blocking erase block request.
1478 @retval EFI_SUCCESS Target blocks have been successfully unmapped.
1479 @retval EFI_DEVICE_ERROR Fail to unmap the target blocks.
1484 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1487 IN EFI_ERASE_BLOCK_TOKEN
*Token OPTIONAL
1490 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
1491 SCSI_ERASEBLK_REQUEST
*EraseBlkReq
;
1492 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*CommandPacket
;
1493 EFI_SCSI_DISK_UNMAP_BLOCK_DESP
*BlkDespPtr
;
1495 EFI_STATUS ReturnStatus
;
1498 UINT32 MaxBlkDespCnt
;
1500 UINT16 UnmapParamListLen
;
1501 VOID
*UnmapParamList
;
1502 EFI_EVENT AsyncUnmapEvent
;
1505 ScsiIo
= ScsiDiskDevice
->ScsiIo
;
1506 MaxLbaCnt
= ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
;
1507 MaxBlkDespCnt
= ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
;
1509 UnmapParamList
= NULL
;
1510 AsyncUnmapEvent
= NULL
;
1511 ReturnStatus
= EFI_SUCCESS
;
1513 if (Blocks
/ (UINTN
)MaxLbaCnt
> MaxBlkDespCnt
) {
1514 ReturnStatus
= EFI_DEVICE_ERROR
;
1518 EraseBlkReq
= AllocateZeroPool (sizeof (SCSI_ERASEBLK_REQUEST
));
1519 if (EraseBlkReq
== NULL
) {
1520 ReturnStatus
= EFI_DEVICE_ERROR
;
1524 EraseBlkReq
->CommandPacket
.Cdb
= AllocateZeroPool (0xA);
1525 if (EraseBlkReq
->CommandPacket
.Cdb
== NULL
) {
1526 ReturnStatus
= EFI_DEVICE_ERROR
;
1530 BlkDespCnt
= (UINT32
)((Blocks
- 1) / MaxLbaCnt
+ 1);
1531 UnmapParamListLen
= (UINT16
)(sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
)
1532 + BlkDespCnt
* sizeof (EFI_SCSI_DISK_UNMAP_BLOCK_DESP
));
1533 UnmapParamList
= AllocateZeroPool (UnmapParamListLen
);
1534 if (UnmapParamList
== NULL
) {
1535 ReturnStatus
= EFI_DEVICE_ERROR
;
1539 *((UINT16
*)UnmapParamList
) = SwapBytes16 (UnmapParamListLen
- 2);
1540 *((UINT16
*)UnmapParamList
+ 1) = SwapBytes16 (UnmapParamListLen
- sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
));
1542 BlkDespPtr
= (EFI_SCSI_DISK_UNMAP_BLOCK_DESP
*)((UINT8
*)UnmapParamList
+ sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
));
1543 while (Blocks
> 0) {
1544 if (Blocks
> MaxLbaCnt
) {
1545 *(UINT64
*)(&BlkDespPtr
->Lba
) = SwapBytes64 (Lba
);
1546 *(UINT32
*)(&BlkDespPtr
->BlockNum
) = SwapBytes32 (MaxLbaCnt
);
1547 Blocks
-= MaxLbaCnt
;
1550 *(UINT64
*)(&BlkDespPtr
->Lba
) = SwapBytes64 (Lba
);
1551 *(UINT32
*)(&BlkDespPtr
->BlockNum
) = SwapBytes32 ((UINT32
)Blocks
);
1558 CommandPacket
= &EraseBlkReq
->CommandPacket
;
1559 CommandPacket
->Timeout
= SCSI_DISK_TIMEOUT
;
1560 CommandPacket
->OutDataBuffer
= UnmapParamList
;
1561 CommandPacket
->OutTransferLength
= UnmapParamListLen
;
1562 CommandPacket
->CdbLength
= 0xA;
1563 CommandPacket
->DataDirection
= EFI_SCSI_DATA_OUT
;
1565 // Fill Cdb for UNMAP Command
1567 Cdb
= CommandPacket
->Cdb
;
1568 Cdb
[0] = EFI_SCSI_OP_UNMAP
;
1569 WriteUnaligned16 ((UINT16
*)&Cdb
[7], SwapBytes16 (UnmapParamListLen
));
1571 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1573 // Non-blocking UNMAP request
1575 Status
= gBS
->CreateEvent (
1578 ScsiDiskAsyncUnmapNotify
,
1582 if (EFI_ERROR (Status
)) {
1583 ReturnStatus
= EFI_DEVICE_ERROR
;
1587 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1588 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &EraseBlkReq
->Link
);
1589 gBS
->RestoreTPL (OldTpl
);
1591 EraseBlkReq
->Token
= Token
;
1593 Status
= ScsiIo
->ExecuteScsiCommand (
1598 if (EFI_ERROR (Status
)) {
1599 ReturnStatus
= EFI_DEVICE_ERROR
;
1601 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1602 RemoveEntryList (&EraseBlkReq
->Link
);
1603 gBS
->RestoreTPL (OldTpl
);
1608 // Directly return if the non-blocking UNMAP request is queued.
1614 // Blocking UNMAP request
1616 Status
= ScsiIo
->ExecuteScsiCommand (
1621 if (EFI_ERROR (Status
)) {
1622 ReturnStatus
= EFI_DEVICE_ERROR
;
1628 // Only blocking UNMAP request will reach here.
1630 Status
= CheckHostAdapterStatus (CommandPacket
->HostAdapterStatus
);
1631 if (EFI_ERROR (Status
)) {
1634 "ScsiDiskUnmap: Host adapter indicating error status 0x%x.\n",
1635 CommandPacket
->HostAdapterStatus
1638 ReturnStatus
= EFI_DEVICE_ERROR
;
1642 Status
= CheckTargetStatus (CommandPacket
->TargetStatus
);
1643 if (EFI_ERROR (Status
)) {
1646 "ScsiDiskUnmap: Target indicating error status 0x%x.\n",
1647 CommandPacket
->HostAdapterStatus
1650 ReturnStatus
= EFI_DEVICE_ERROR
;
1655 if (EraseBlkReq
!= NULL
) {
1656 if (EraseBlkReq
->CommandPacket
.Cdb
!= NULL
) {
1657 FreePool (EraseBlkReq
->CommandPacket
.Cdb
);
1660 FreePool (EraseBlkReq
);
1663 if (UnmapParamList
!= NULL
) {
1664 FreePool (UnmapParamList
);
1667 if (AsyncUnmapEvent
!= NULL
) {
1668 gBS
->CloseEvent (AsyncUnmapEvent
);
1671 return ReturnStatus
;
1675 Erase a specified number of device blocks.
1677 @param[in] This Indicates a pointer to the calling context.
1678 @param[in] MediaId The media ID that the erase request is for.
1679 @param[in] Lba The starting logical block address to be
1680 erased. The caller is responsible for erasing
1681 only legitimate locations.
1682 @param[in, out] Token A pointer to the token associated with the
1684 @param[in] Size The size in bytes to be erased. This must be
1685 a multiple of the physical block size of the
1688 @retval EFI_SUCCESS The erase request was queued if Event is not
1689 NULL. The data was erased correctly to the
1690 device if the Event is NULL.to the device.
1691 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
1693 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1694 to perform the erase operation.
1695 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
1697 @retval EFI_NO_MEDIA There is no media in the device.
1698 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1703 ScsiDiskEraseBlocks (
1704 IN EFI_ERASE_BLOCK_PROTOCOL
*This
,
1707 IN OUT EFI_ERASE_BLOCK_TOKEN
*Token
,
1711 SCSI_DISK_DEV
*ScsiDiskDevice
;
1712 EFI_BLOCK_IO_MEDIA
*Media
;
1715 UINTN NumberOfBlocks
;
1716 BOOLEAN MediaChange
;
1719 MediaChange
= FALSE
;
1720 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1721 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_ERASEBLK (This
);
1723 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
1724 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1725 if (EFI_ERROR (Status
)) {
1726 Status
= EFI_DEVICE_ERROR
;
1731 gBS
->ReinstallProtocolInterface (
1732 ScsiDiskDevice
->Handle
,
1733 &gEfiBlockIoProtocolGuid
,
1734 &ScsiDiskDevice
->BlkIo
,
1735 &ScsiDiskDevice
->BlkIo
1737 gBS
->ReinstallProtocolInterface (
1738 ScsiDiskDevice
->Handle
,
1739 &gEfiBlockIo2ProtocolGuid
,
1740 &ScsiDiskDevice
->BlkIo2
,
1741 &ScsiDiskDevice
->BlkIo2
1743 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1744 gBS
->ReinstallProtocolInterface (
1745 ScsiDiskDevice
->Handle
,
1746 &gEfiEraseBlockProtocolGuid
,
1747 &ScsiDiskDevice
->EraseBlock
,
1748 &ScsiDiskDevice
->EraseBlock
1752 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1753 gBS
->ReinstallProtocolInterface (
1754 ScsiDiskDevice
->Handle
,
1755 &gEfiStorageSecurityCommandProtocolGuid
,
1756 &ScsiDiskDevice
->StorageSecurity
,
1757 &ScsiDiskDevice
->StorageSecurity
1761 Status
= EFI_MEDIA_CHANGED
;
1767 // Get the intrinsic block size
1769 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1771 if (!(Media
->MediaPresent
)) {
1772 Status
= EFI_NO_MEDIA
;
1776 if (MediaId
!= Media
->MediaId
) {
1777 Status
= EFI_MEDIA_CHANGED
;
1781 if (Media
->ReadOnly
) {
1782 Status
= EFI_WRITE_PROTECTED
;
1787 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1788 Token
->TransactionStatus
= EFI_SUCCESS
;
1789 gBS
->SignalEvent (Token
->Event
);
1792 Status
= EFI_SUCCESS
;
1796 BlockSize
= Media
->BlockSize
;
1797 if ((Size
% BlockSize
) != 0) {
1798 Status
= EFI_INVALID_PARAMETER
;
1802 NumberOfBlocks
= Size
/ BlockSize
;
1803 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1804 Status
= EFI_INVALID_PARAMETER
;
1808 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1809 Status
= ScsiDiskUnmap (ScsiDiskDevice
, Lba
, NumberOfBlocks
, Token
);
1811 Status
= ScsiDiskUnmap (ScsiDiskDevice
, Lba
, NumberOfBlocks
, NULL
);
1815 gBS
->RestoreTPL (OldTpl
);
1820 Send a security protocol command to a device that receives data and/or the result
1821 of one or more commands sent by SendData.
1823 The ReceiveData function sends a security protocol command to the given MediaId.
1824 The security protocol command sent is defined by SecurityProtocolId and contains
1825 the security protocol specific data SecurityProtocolSpecificData. The function
1826 returns the data from the security protocol command in PayloadBuffer.
1828 For devices supporting the SCSI command set, the security protocol command is sent
1829 using the SECURITY PROTOCOL IN command defined in SPC-4.
1831 If PayloadBufferSize is too small to store the available data from the security
1832 protocol command, the function shall copy PayloadBufferSize bytes into the
1833 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
1835 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
1836 the function shall return EFI_INVALID_PARAMETER.
1838 If the given MediaId does not support security protocol commands, the function shall
1839 return EFI_UNSUPPORTED. If there is no media in the device, the function returns
1840 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
1841 the function returns EFI_MEDIA_CHANGED.
1843 If the security protocol fails to complete within the Timeout period, the function
1844 shall return EFI_TIMEOUT.
1846 If the security protocol command completes without an error, the function shall
1847 return EFI_SUCCESS. If the security protocol command completes with an error, the
1848 function shall return EFI_DEVICE_ERROR.
1850 @param This Indicates a pointer to the calling context.
1851 @param MediaId ID of the medium to receive data from.
1852 @param Timeout The timeout, in 100ns units, to use for the execution
1853 of the security protocol command. A Timeout value of 0
1854 means that this function will wait indefinitely for the
1855 security protocol command to execute. If Timeout is greater
1856 than zero, then this function will return EFI_TIMEOUT if the
1857 time required to execute the receive data command is greater than Timeout.
1858 @param SecurityProtocolId The value of the "Security Protocol" parameter of
1859 the security protocol command to be sent.
1860 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1861 of the security protocol command to be sent.
1862 @param PayloadBufferSize Size in bytes of the payload data buffer.
1863 @param PayloadBuffer A pointer to a destination buffer to store the security
1864 protocol command specific payload data for the security
1865 protocol command. The caller is responsible for having
1866 either implicit or explicit ownership of the buffer.
1867 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
1868 data written to the payload data buffer.
1870 @retval EFI_SUCCESS The security protocol command completed successfully.
1871 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
1872 data from the device. The PayloadBuffer contains the truncated data.
1873 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1874 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1875 @retval EFI_NO_MEDIA There is no media in the device.
1876 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1877 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
1878 PayloadBufferSize is non-zero.
1879 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1880 protocol command to execute.
1885 ScsiDiskReceiveData (
1886 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
1887 IN UINT32 MediaId OPTIONAL
,
1889 IN UINT8 SecurityProtocolId
,
1890 IN UINT16 SecurityProtocolSpecificData
,
1891 IN UINTN PayloadBufferSize
,
1892 OUT VOID
*PayloadBuffer
,
1893 OUT UINTN
*PayloadTransferSize
1896 SCSI_DISK_DEV
*ScsiDiskDevice
;
1897 EFI_BLOCK_IO_MEDIA
*Media
;
1899 BOOLEAN MediaChange
;
1901 UINT8 SenseDataLength
;
1902 UINT8 HostAdapterStatus
;
1904 VOID
*AlignedBuffer
;
1905 BOOLEAN AlignedBufferAllocated
;
1907 AlignedBuffer
= NULL
;
1908 MediaChange
= FALSE
;
1909 AlignedBufferAllocated
= FALSE
;
1910 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1911 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_STORSEC (This
);
1912 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1914 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
1916 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
1917 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1918 if (EFI_ERROR (Status
)) {
1919 Status
= EFI_DEVICE_ERROR
;
1924 gBS
->ReinstallProtocolInterface (
1925 ScsiDiskDevice
->Handle
,
1926 &gEfiBlockIoProtocolGuid
,
1927 &ScsiDiskDevice
->BlkIo
,
1928 &ScsiDiskDevice
->BlkIo
1930 gBS
->ReinstallProtocolInterface (
1931 ScsiDiskDevice
->Handle
,
1932 &gEfiBlockIo2ProtocolGuid
,
1933 &ScsiDiskDevice
->BlkIo2
,
1934 &ScsiDiskDevice
->BlkIo2
1936 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1937 gBS
->ReinstallProtocolInterface (
1938 ScsiDiskDevice
->Handle
,
1939 &gEfiEraseBlockProtocolGuid
,
1940 &ScsiDiskDevice
->EraseBlock
,
1941 &ScsiDiskDevice
->EraseBlock
1945 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1946 gBS
->ReinstallProtocolInterface (
1947 ScsiDiskDevice
->Handle
,
1948 &gEfiStorageSecurityCommandProtocolGuid
,
1949 &ScsiDiskDevice
->StorageSecurity
,
1950 &ScsiDiskDevice
->StorageSecurity
1954 if (Media
->MediaPresent
) {
1955 Status
= EFI_MEDIA_CHANGED
;
1957 Status
= EFI_NO_MEDIA
;
1967 if (!(Media
->MediaPresent
)) {
1968 Status
= EFI_NO_MEDIA
;
1972 if ((MediaId
!= 0) && (MediaId
!= Media
->MediaId
)) {
1973 Status
= EFI_MEDIA_CHANGED
;
1977 if (PayloadBufferSize
!= 0) {
1978 if ((PayloadBuffer
== NULL
) || (PayloadTransferSize
== NULL
)) {
1979 Status
= EFI_INVALID_PARAMETER
;
1983 if ((ScsiDiskDevice
->ScsiIo
->IoAlign
> 1) && !IS_ALIGNED (PayloadBuffer
, ScsiDiskDevice
->ScsiIo
->IoAlign
)) {
1984 AlignedBuffer
= AllocateAlignedBuffer (ScsiDiskDevice
, PayloadBufferSize
);
1985 if (AlignedBuffer
== NULL
) {
1986 Status
= EFI_OUT_OF_RESOURCES
;
1990 ZeroMem (AlignedBuffer
, PayloadBufferSize
);
1991 AlignedBufferAllocated
= TRUE
;
1993 AlignedBuffer
= PayloadBuffer
;
1997 Status
= ScsiSecurityProtocolInCommand (
1998 ScsiDiskDevice
->ScsiIo
,
2000 ScsiDiskDevice
->SenseData
,
2005 SecurityProtocolSpecificData
,
2011 if (EFI_ERROR (Status
)) {
2015 if (AlignedBufferAllocated
) {
2016 CopyMem (PayloadBuffer
, AlignedBuffer
, PayloadBufferSize
);
2019 if (PayloadBufferSize
< *PayloadTransferSize
) {
2020 Status
= EFI_WARN_BUFFER_TOO_SMALL
;
2024 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2025 if (EFI_ERROR (Status
)) {
2029 Status
= CheckTargetStatus (TargetStatus
);
2030 if (EFI_ERROR (Status
)) {
2035 if (AlignedBufferAllocated
) {
2036 ZeroMem (AlignedBuffer
, PayloadBufferSize
);
2037 FreeAlignedBuffer (AlignedBuffer
, PayloadBufferSize
);
2040 gBS
->RestoreTPL (OldTpl
);
2045 Send a security protocol command to a device.
2047 The SendData function sends a security protocol command containing the payload
2048 PayloadBuffer to the given MediaId. The security protocol command sent is
2049 defined by SecurityProtocolId and contains the security protocol specific data
2050 SecurityProtocolSpecificData. If the underlying protocol command requires a
2051 specific padding for the command payload, the SendData function shall add padding
2052 bytes to the command payload to satisfy the padding requirements.
2054 For devices supporting the SCSI command set, the security protocol command is sent
2055 using the SECURITY PROTOCOL OUT command defined in SPC-4.
2057 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
2058 return EFI_INVALID_PARAMETER.
2060 If the given MediaId does not support security protocol commands, the function
2061 shall return EFI_UNSUPPORTED. If there is no media in the device, the function
2062 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
2063 device, the function returns EFI_MEDIA_CHANGED.
2065 If the security protocol fails to complete within the Timeout period, the function
2066 shall return EFI_TIMEOUT.
2068 If the security protocol command completes without an error, the function shall return
2069 EFI_SUCCESS. If the security protocol command completes with an error, the function
2070 shall return EFI_DEVICE_ERROR.
2072 @param This Indicates a pointer to the calling context.
2073 @param MediaId ID of the medium to receive data from.
2074 @param Timeout The timeout, in 100ns units, to use for the execution
2075 of the security protocol command. A Timeout value of 0
2076 means that this function will wait indefinitely for the
2077 security protocol command to execute. If Timeout is greater
2078 than zero, then this function will return EFI_TIMEOUT if the
2079 time required to execute the receive data command is greater than Timeout.
2080 @param SecurityProtocolId The value of the "Security Protocol" parameter of
2081 the security protocol command to be sent.
2082 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
2083 of the security protocol command to be sent.
2084 @param PayloadBufferSize Size in bytes of the payload data buffer.
2085 @param PayloadBuffer A pointer to a destination buffer to store the security
2086 protocol command specific payload data for the security
2089 @retval EFI_SUCCESS The security protocol command completed successfully.
2090 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
2091 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
2092 @retval EFI_NO_MEDIA There is no media in the device.
2093 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
2094 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
2095 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
2096 protocol command to execute.
2102 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
2103 IN UINT32 MediaId OPTIONAL
,
2105 IN UINT8 SecurityProtocolId
,
2106 IN UINT16 SecurityProtocolSpecificData
,
2107 IN UINTN PayloadBufferSize
,
2108 OUT VOID
*PayloadBuffer
2111 SCSI_DISK_DEV
*ScsiDiskDevice
;
2112 EFI_BLOCK_IO_MEDIA
*Media
;
2114 BOOLEAN MediaChange
;
2116 UINT8 SenseDataLength
;
2117 UINT8 HostAdapterStatus
;
2119 VOID
*AlignedBuffer
;
2120 BOOLEAN AlignedBufferAllocated
;
2122 AlignedBuffer
= NULL
;
2123 MediaChange
= FALSE
;
2124 AlignedBufferAllocated
= FALSE
;
2125 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
2126 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_STORSEC (This
);
2127 Media
= ScsiDiskDevice
->BlkIo
.Media
;
2129 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2131 if (!IS_DEVICE_FIXED (ScsiDiskDevice
)) {
2132 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
2133 if (EFI_ERROR (Status
)) {
2134 Status
= EFI_DEVICE_ERROR
;
2139 gBS
->ReinstallProtocolInterface (
2140 ScsiDiskDevice
->Handle
,
2141 &gEfiBlockIoProtocolGuid
,
2142 &ScsiDiskDevice
->BlkIo
,
2143 &ScsiDiskDevice
->BlkIo
2145 gBS
->ReinstallProtocolInterface (
2146 ScsiDiskDevice
->Handle
,
2147 &gEfiBlockIo2ProtocolGuid
,
2148 &ScsiDiskDevice
->BlkIo2
,
2149 &ScsiDiskDevice
->BlkIo2
2151 if (DetermineInstallEraseBlock (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
2152 gBS
->ReinstallProtocolInterface (
2153 ScsiDiskDevice
->Handle
,
2154 &gEfiEraseBlockProtocolGuid
,
2155 &ScsiDiskDevice
->EraseBlock
,
2156 &ScsiDiskDevice
->EraseBlock
2160 if (DetermineInstallStorageSecurity (ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
2161 gBS
->ReinstallProtocolInterface (
2162 ScsiDiskDevice
->Handle
,
2163 &gEfiStorageSecurityCommandProtocolGuid
,
2164 &ScsiDiskDevice
->StorageSecurity
,
2165 &ScsiDiskDevice
->StorageSecurity
2169 if (Media
->MediaPresent
) {
2170 Status
= EFI_MEDIA_CHANGED
;
2172 Status
= EFI_NO_MEDIA
;
2182 if (!(Media
->MediaPresent
)) {
2183 Status
= EFI_NO_MEDIA
;
2187 if ((MediaId
!= 0) && (MediaId
!= Media
->MediaId
)) {
2188 Status
= EFI_MEDIA_CHANGED
;
2192 if (Media
->ReadOnly
) {
2193 Status
= EFI_WRITE_PROTECTED
;
2197 if (PayloadBufferSize
!= 0) {
2198 if (PayloadBuffer
== NULL
) {
2199 Status
= EFI_INVALID_PARAMETER
;
2203 if ((ScsiDiskDevice
->ScsiIo
->IoAlign
> 1) && !IS_ALIGNED (PayloadBuffer
, ScsiDiskDevice
->ScsiIo
->IoAlign
)) {
2204 AlignedBuffer
= AllocateAlignedBuffer (ScsiDiskDevice
, PayloadBufferSize
);
2205 if (AlignedBuffer
== NULL
) {
2206 Status
= EFI_OUT_OF_RESOURCES
;
2210 CopyMem (AlignedBuffer
, PayloadBuffer
, PayloadBufferSize
);
2211 AlignedBufferAllocated
= TRUE
;
2213 AlignedBuffer
= PayloadBuffer
;
2217 Status
= ScsiSecurityProtocolOutCommand (
2218 ScsiDiskDevice
->ScsiIo
,
2220 ScsiDiskDevice
->SenseData
,
2225 SecurityProtocolSpecificData
,
2230 if (EFI_ERROR (Status
)) {
2234 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2235 if (EFI_ERROR (Status
)) {
2239 Status
= CheckTargetStatus (TargetStatus
);
2240 if (EFI_ERROR (Status
)) {
2245 if (AlignedBufferAllocated
) {
2246 ZeroMem (AlignedBuffer
, PayloadBufferSize
);
2247 FreeAlignedBuffer (AlignedBuffer
, PayloadBufferSize
);
2250 gBS
->RestoreTPL (OldTpl
);
2255 Detect Device and read out capacity ,if error occurs, parse the sense key.
2257 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2258 @param MustReadCapacity The flag about reading device capacity
2259 @param MediaChange The pointer of flag indicates if media has changed
2261 @retval EFI_DEVICE_ERROR Indicates that error occurs
2262 @retval EFI_SUCCESS Successfully to detect media
2266 ScsiDiskDetectMedia (
2267 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2268 IN BOOLEAN MustReadCapacity
,
2269 OUT BOOLEAN
*MediaChange
2273 EFI_SCSI_SENSE_DATA
*SenseData
;
2274 UINTN NumberOfSenseKeys
;
2276 BOOLEAN NeedReadCapacity
;
2279 EFI_BLOCK_IO_MEDIA OldMedia
;
2281 EFI_EVENT TimeoutEvt
;
2283 Status
= EFI_SUCCESS
;
2285 NumberOfSenseKeys
= 0;
2288 Action
= ACTION_NO_ACTION
;
2289 NeedReadCapacity
= FALSE
;
2290 *MediaChange
= FALSE
;
2293 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
2295 Status
= gBS
->CreateEvent (
2302 if (EFI_ERROR (Status
)) {
2306 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS (120));
2307 if (EFI_ERROR (Status
)) {
2312 // Sending Test_Unit cmd to poll device status.
2313 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
2314 // We limit the upper boundary to 120 seconds.
2316 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
2317 Status
= ScsiDiskTestUnitReady (
2323 if (!EFI_ERROR (Status
)) {
2324 Status
= DetectMediaParsingSenseKeys (
2330 if (EFI_ERROR (Status
)) {
2332 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2339 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
2345 if (EFI_ERROR (Status
)) {
2350 // ACTION_NO_ACTION: need not read capacity
2351 // other action code: need read capacity
2353 if (Action
== ACTION_READ_CAPACITY
) {
2354 NeedReadCapacity
= TRUE
;
2358 // READ_CAPACITY command is not supported by any of the UFS WLUNs.
2360 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_WLUN
) {
2361 NeedReadCapacity
= FALSE
;
2362 MustReadCapacity
= FALSE
;
2363 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
2367 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
2368 // retrieve capacity via Read Capacity command
2370 if (NeedReadCapacity
|| MustReadCapacity
) {
2372 // retrieve media information
2374 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
2375 Status
= ScsiDiskReadCapacity (
2381 if (!EFI_ERROR (Status
)) {
2383 // analyze sense key to action
2385 Status
= DetectMediaParsingSenseKeys (
2391 if (EFI_ERROR (Status
)) {
2393 // if Status is error, it may indicate crisis error,
2394 // so return without retry.
2397 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2405 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
2411 if (EFI_ERROR (Status
)) {
2416 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
2418 // Media change information got from the device
2420 *MediaChange
= TRUE
;
2423 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
2424 *MediaChange
= TRUE
;
2425 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
2428 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
2429 *MediaChange
= TRUE
;
2430 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
2433 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
2434 *MediaChange
= TRUE
;
2435 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
2438 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
2439 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
2441 // when change from no media to media present, reset the MediaId to 1.
2443 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
2446 // when no media, reset the MediaId to zero.
2448 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
2451 *MediaChange
= TRUE
;
2455 if (TimeoutEvt
!= NULL
) {
2456 gBS
->CloseEvent (TimeoutEvt
);
2463 Send out Inquiry command to Device.
2465 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2466 @param NeedRetry Indicates if needs try again when error happens
2468 @retval EFI_DEVICE_ERROR Indicates that error occurs
2469 @retval EFI_SUCCESS Successfully to detect media
2473 ScsiDiskInquiryDevice (
2474 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2475 OUT BOOLEAN
*NeedRetry
2478 UINT32 InquiryDataLength
;
2479 UINT8 SenseDataLength
;
2480 UINT8 HostAdapterStatus
;
2482 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
2483 UINTN NumberOfSenseKeys
;
2487 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
2488 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
2491 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
2492 SenseDataLength
= 0;
2494 Status
= ScsiInquiryCommand (
2495 ScsiDiskDevice
->ScsiIo
,
2501 (VOID
*)&(ScsiDiskDevice
->InquiryData
),
2506 // no need to check HostAdapterStatus and TargetStatus
2508 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
2509 ParseInquiryData (ScsiDiskDevice
);
2511 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
2513 // Check whether the device supports Block Limits VPD page (0xB0)
2515 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2516 if (SupportedVpdPages
== NULL
) {
2518 return EFI_DEVICE_ERROR
;
2521 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2522 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
2523 SenseDataLength
= 0;
2524 Status
= ScsiInquiryCommandEx (
2525 ScsiDiskDevice
->ScsiIo
,
2531 (VOID
*)SupportedVpdPages
,
2534 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
2536 if (!EFI_ERROR (Status
)) {
2537 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
2538 | SupportedVpdPages
->PageLength1
;
2541 // Sanity checks for coping with broken devices
2543 if (PageLength
> sizeof SupportedVpdPages
->SupportedVpdPageList
) {
2546 "%a: invalid PageLength (%u) in Supported VPD Pages page\n",
2553 if ((PageLength
> 0) &&
2554 (SupportedVpdPages
->SupportedVpdPageList
[0] !=
2555 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
))
2559 "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",
2561 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
2567 // Locate the code for the Block Limits VPD page
2569 for (Index
= 0; Index
< PageLength
; Index
++) {
2574 (SupportedVpdPages
->SupportedVpdPageList
[Index
] <=
2575 SupportedVpdPages
->SupportedVpdPageList
[Index
- 1]))
2579 "%a: non-ascending code in Supported VPD Pages page @ %u\n",
2588 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
2594 // Query the Block Limits VPD page
2596 if (Index
< PageLength
) {
2597 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2598 if (BlockLimits
== NULL
) {
2599 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2601 return EFI_DEVICE_ERROR
;
2604 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2605 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
2606 SenseDataLength
= 0;
2607 Status
= ScsiInquiryCommandEx (
2608 ScsiDiskDevice
->ScsiIo
,
2614 (VOID
*)BlockLimits
,
2617 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
2619 if (!EFI_ERROR (Status
)) {
2620 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
2621 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
2622 BlockLimits
->OptimalTransferLengthGranularity1
;
2624 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
=
2625 (BlockLimits
->MaximumUnmapLbaCount4
<< 24) |
2626 (BlockLimits
->MaximumUnmapLbaCount3
<< 16) |
2627 (BlockLimits
->MaximumUnmapLbaCount2
<< 8) |
2628 BlockLimits
->MaximumUnmapLbaCount1
;
2629 ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
=
2630 (BlockLimits
->MaximumUnmapBlockDescriptorCount4
<< 24) |
2631 (BlockLimits
->MaximumUnmapBlockDescriptorCount3
<< 16) |
2632 (BlockLimits
->MaximumUnmapBlockDescriptorCount2
<< 8) |
2633 BlockLimits
->MaximumUnmapBlockDescriptorCount1
;
2634 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
=
2635 (BlockLimits
->OptimalUnmapGranularity4
<< 24) |
2636 (BlockLimits
->OptimalUnmapGranularity3
<< 16) |
2637 (BlockLimits
->OptimalUnmapGranularity2
<< 8) |
2638 BlockLimits
->OptimalUnmapGranularity1
;
2639 if (BlockLimits
->UnmapGranularityAlignmentValid
!= 0) {
2640 ScsiDiskDevice
->UnmapInfo
.GranularityAlignment
=
2641 (BlockLimits
->UnmapGranularityAlignment4
<< 24) |
2642 (BlockLimits
->UnmapGranularityAlignment3
<< 16) |
2643 (BlockLimits
->UnmapGranularityAlignment2
<< 8) |
2644 BlockLimits
->UnmapGranularityAlignment1
;
2647 if (ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
== 0) {
2649 // A value of 0 indicates that the optimal unmap granularity is
2652 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
= 1;
2655 ScsiDiskDevice
->BlockLimitsVpdSupported
= TRUE
;
2658 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2662 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2666 if (!EFI_ERROR (Status
)) {
2668 } else if (Status
== EFI_NOT_READY
) {
2670 return EFI_DEVICE_ERROR
;
2671 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2673 return EFI_DEVICE_ERROR
;
2677 // go ahead to check HostAdapterStatus and TargetStatus
2678 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
2681 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2682 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2684 return EFI_DEVICE_ERROR
;
2685 } else if (Status
== EFI_DEVICE_ERROR
) {
2687 // reset the scsi channel
2689 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2691 return EFI_DEVICE_ERROR
;
2694 Status
= CheckTargetStatus (TargetStatus
);
2695 if (Status
== EFI_NOT_READY
) {
2697 // reset the scsi device
2699 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2701 return EFI_DEVICE_ERROR
;
2702 } else if (Status
== EFI_DEVICE_ERROR
) {
2704 return EFI_DEVICE_ERROR
;
2708 // if goes here, meant ScsiInquiryCommand() failed.
2709 // if ScsiDiskRequestSenseKeys() succeeds at last,
2710 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
2713 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2714 Status
= ScsiDiskRequestSenseKeys (
2721 if (!EFI_ERROR (Status
)) {
2723 return EFI_DEVICE_ERROR
;
2727 return EFI_DEVICE_ERROR
;
2732 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2733 // set *NeedRetry = FALSE to avoid the outside caller try again.
2736 return EFI_DEVICE_ERROR
;
2742 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
2743 When Test Unit Ready command encounters any error caused by host adapter or
2744 target, return error without retrieving Sense Keys.
2746 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2747 @param NeedRetry The pointer of flag indicates try again
2748 @param SenseDataArray The pointer of an array of sense data
2749 @param NumberOfSenseKeys The pointer of the number of sense data array
2751 @retval EFI_DEVICE_ERROR Indicates that error occurs
2752 @retval EFI_SUCCESS Successfully to test unit
2756 ScsiDiskTestUnitReady (
2757 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2758 OUT BOOLEAN
*NeedRetry
,
2759 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2760 OUT UINTN
*NumberOfSenseKeys
2764 UINT8 SenseDataLength
;
2765 UINT8 HostAdapterStatus
;
2770 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2771 *NumberOfSenseKeys
= 0;
2774 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
2776 Status
= ScsiTestUnitReadyCommand (
2777 ScsiDiskDevice
->ScsiIo
,
2779 ScsiDiskDevice
->SenseData
,
2785 // no need to check HostAdapterStatus and TargetStatus
2787 if (Status
== EFI_NOT_READY
) {
2789 return EFI_DEVICE_ERROR
;
2790 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2792 return EFI_DEVICE_ERROR
;
2796 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
2799 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2800 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2802 return EFI_DEVICE_ERROR
;
2803 } else if (Status
== EFI_DEVICE_ERROR
) {
2805 // reset the scsi channel
2807 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2809 return EFI_DEVICE_ERROR
;
2812 Status
= CheckTargetStatus (TargetStatus
);
2813 if (Status
== EFI_NOT_READY
) {
2815 // reset the scsi device
2817 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2819 return EFI_DEVICE_ERROR
;
2820 } else if (Status
== EFI_DEVICE_ERROR
) {
2822 return EFI_DEVICE_ERROR
;
2825 if (SenseDataLength
!= 0) {
2826 *NumberOfSenseKeys
= SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
);
2827 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2832 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2833 Status
= ScsiDiskRequestSenseKeys (
2840 if (!EFI_ERROR (Status
)) {
2845 return EFI_DEVICE_ERROR
;
2850 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2851 // set *NeedRetry = FALSE to avoid the outside caller try again.
2854 return EFI_DEVICE_ERROR
;
2858 Parsing Sense Keys which got from request sense command.
2860 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2861 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2862 @param NumberOfSenseKeys The number of sense key
2863 @param Action The pointer of action which indicates what is need to do next
2865 @retval EFI_DEVICE_ERROR Indicates that error occurs
2866 @retval EFI_SUCCESS Successfully to complete the parsing
2870 DetectMediaParsingSenseKeys (
2871 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2872 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2873 IN UINTN NumberOfSenseKeys
,
2880 // Default is to read capacity, unless..
2882 *Action
= ACTION_READ_CAPACITY
;
2884 if (NumberOfSenseKeys
== 0) {
2885 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
2886 *Action
= ACTION_NO_ACTION
;
2892 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
2894 // No Sense Key returned from last submitted command
2896 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
2897 *Action
= ACTION_NO_ACTION
;
2903 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
2904 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
2905 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
2906 *Action
= ACTION_NO_ACTION
;
2907 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
2911 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
2912 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
2913 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
2917 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
2918 *Action
= ACTION_RETRY_COMMAND_LATER
;
2919 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
2923 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
2924 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
2925 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2926 return EFI_DEVICE_ERROR
;
2929 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
2930 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
2931 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2932 return EFI_DEVICE_ERROR
;
2935 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
2937 *Action
= ACTION_RETRY_COMMAND_LATER
;
2938 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
2942 *Action
= ACTION_NO_ACTION
;
2943 return EFI_DEVICE_ERROR
;
2946 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2947 DEBUG ((DEBUG_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
2952 Send read capacity command to device and get the device parameter.
2954 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2955 @param NeedRetry The pointer of flag indicates if need a retry
2956 @param SenseDataArray The pointer of an array of sense data
2957 @param NumberOfSenseKeys The number of sense key
2959 @retval EFI_DEVICE_ERROR Indicates that error occurs
2960 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
2964 ScsiDiskReadCapacity (
2965 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2966 OUT BOOLEAN
*NeedRetry
,
2967 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2968 OUT UINTN
*NumberOfSenseKeys
2971 UINT8 HostAdapterStatus
;
2973 EFI_STATUS CommandStatus
;
2977 UINT8 SenseDataLength
;
2978 UINT32 DataLength10
;
2979 UINT32 DataLength16
;
2980 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
2981 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
2983 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2984 if (CapacityData10
== NULL
) {
2986 return EFI_DEVICE_ERROR
;
2989 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2990 if (CapacityData16
== NULL
) {
2991 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2993 return EFI_DEVICE_ERROR
;
2996 SenseDataLength
= 0;
2997 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
2998 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
2999 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
3000 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
3002 *NumberOfSenseKeys
= 0;
3006 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
3007 // 16 byte command should be used to access large hard disk >2TB
3009 CommandStatus
= ScsiReadCapacityCommand (
3010 ScsiDiskDevice
->ScsiIo
,
3016 (VOID
*)CapacityData10
,
3021 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
3022 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
3023 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff))
3026 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
3028 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
3030 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
3031 // and LowestAlignedLba
3033 CommandStatus
= ScsiReadCapacity16Command (
3034 ScsiDiskDevice
->ScsiIo
,
3040 (VOID
*)CapacityData16
,
3047 // no need to check HostAdapterStatus and TargetStatus
3049 if (CommandStatus
== EFI_SUCCESS
) {
3050 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
3051 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
3052 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
3056 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
3057 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
3059 if (CommandStatus
== EFI_NOT_READY
) {
3061 return EFI_DEVICE_ERROR
;
3062 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
3064 return EFI_DEVICE_ERROR
;
3068 // go ahead to check HostAdapterStatus and TargetStatus
3069 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3072 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3073 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3075 return EFI_DEVICE_ERROR
;
3076 } else if (Status
== EFI_DEVICE_ERROR
) {
3078 // reset the scsi channel
3080 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3082 return EFI_DEVICE_ERROR
;
3085 Status
= CheckTargetStatus (TargetStatus
);
3086 if (Status
== EFI_NOT_READY
) {
3088 // reset the scsi device
3090 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3092 return EFI_DEVICE_ERROR
;
3093 } else if (Status
== EFI_DEVICE_ERROR
) {
3095 return EFI_DEVICE_ERROR
;
3099 // if goes here, meant ScsiReadCapacityCommand() failed.
3100 // if ScsiDiskRequestSenseKeys() succeeds at last,
3101 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
3104 for (Index
= 0; Index
< MaxRetry
; Index
++) {
3105 Status
= ScsiDiskRequestSenseKeys (
3112 if (!EFI_ERROR (Status
)) {
3117 return EFI_DEVICE_ERROR
;
3122 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
3123 // set *NeedRetry = FALSE to avoid the outside caller try again.
3126 return EFI_DEVICE_ERROR
;
3130 Check the HostAdapter status and re-interpret it in EFI_STATUS.
3132 @param HostAdapterStatus Host Adapter status
3134 @retval EFI_SUCCESS Host adapter is OK.
3135 @retval EFI_TIMEOUT Timeout.
3136 @retval EFI_NOT_READY Adapter NOT ready.
3137 @retval EFI_DEVICE_ERROR Adapter device error.
3141 CheckHostAdapterStatus (
3142 IN UINT8 HostAdapterStatus
3145 switch (HostAdapterStatus
) {
3146 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
3149 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
3150 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
3151 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
3154 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
3155 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
3156 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
3157 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
3158 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
3159 return EFI_NOT_READY
;
3161 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
3162 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
3163 return EFI_DEVICE_ERROR
;
3171 Check the target status and re-interpret it in EFI_STATUS.
3173 @param TargetStatus Target status
3175 @retval EFI_NOT_READY Device is NOT ready.
3176 @retval EFI_DEVICE_ERROR
3182 IN UINT8 TargetStatus
3185 switch (TargetStatus
) {
3186 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
3187 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
3188 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
3191 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
3192 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
3193 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
3194 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
3195 return EFI_NOT_READY
;
3197 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
3198 return EFI_DEVICE_ERROR
;
3206 Retrieve all sense keys from the device.
3208 When encountering error during the process, if retrieve sense keys before
3209 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
3210 and NeedRetry set to FALSE; otherwise, return the proper return status.
3212 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3213 @param NeedRetry The pointer of flag indicates if need a retry
3214 @param SenseDataArray The pointer of an array of sense data
3215 @param NumberOfSenseKeys The number of sense key
3216 @param AskResetIfError The flag indicates if need reset when error occurs
3218 @retval EFI_DEVICE_ERROR Indicates that error occurs
3219 @retval EFI_SUCCESS Successfully to request sense key
3223 ScsiDiskRequestSenseKeys (
3224 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
3225 OUT BOOLEAN
*NeedRetry
,
3226 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
3227 OUT UINTN
*NumberOfSenseKeys
,
3228 IN BOOLEAN AskResetIfError
3231 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
3232 UINT8 SenseDataLength
;
3235 EFI_STATUS FallStatus
;
3236 UINT8 HostAdapterStatus
;
3239 FallStatus
= EFI_SUCCESS
;
3240 SenseDataLength
= (UINT8
)sizeof (EFI_SCSI_SENSE_DATA
);
3243 ScsiDiskDevice
->SenseData
,
3244 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
3247 *NumberOfSenseKeys
= 0;
3248 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
3249 Status
= EFI_SUCCESS
;
3250 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
3251 if (PtrSenseData
== NULL
) {
3252 return EFI_DEVICE_ERROR
;
3255 for (SenseReq
= TRUE
; SenseReq
;) {
3256 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
3257 Status
= ScsiRequestSenseCommand (
3258 ScsiDiskDevice
->ScsiIo
,
3265 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
3266 FallStatus
= EFI_SUCCESS
;
3267 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3269 FallStatus
= EFI_DEVICE_ERROR
;
3270 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
3272 FallStatus
= EFI_DEVICE_ERROR
;
3273 } else if (Status
== EFI_DEVICE_ERROR
) {
3274 if (AskResetIfError
) {
3275 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3278 FallStatus
= EFI_DEVICE_ERROR
;
3281 if (EFI_ERROR (FallStatus
)) {
3282 if (*NumberOfSenseKeys
!= 0) {
3284 Status
= EFI_SUCCESS
;
3287 Status
= EFI_DEVICE_ERROR
;
3292 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
3293 (*NumberOfSenseKeys
) += 1;
3296 // no more sense key or number of sense keys exceeds predefined,
3299 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
3300 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
))
3307 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
3312 Get information from media read capacity command.
3314 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3315 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
3316 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
3321 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
3322 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
3323 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
3328 if (!ScsiDiskDevice
->Cdb16Byte
) {
3329 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= ((UINT32
)Capacity10
->LastLba3
<< 24) |
3330 (Capacity10
->LastLba2
<< 16) |
3331 (Capacity10
->LastLba1
<< 8) |
3332 Capacity10
->LastLba0
;
3334 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
3335 (Capacity10
->BlockSize2
<< 16) |
3336 (Capacity10
->BlockSize1
<< 8) |
3337 Capacity10
->BlockSize0
;
3338 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
3339 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
3340 if (!ScsiDiskDevice
->BlockLimitsVpdSupported
) {
3341 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
)ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
3344 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
3345 *Ptr
++ = Capacity16
->LastLba0
;
3346 *Ptr
++ = Capacity16
->LastLba1
;
3347 *Ptr
++ = Capacity16
->LastLba2
;
3348 *Ptr
++ = Capacity16
->LastLba3
;
3349 *Ptr
++ = Capacity16
->LastLba4
;
3350 *Ptr
++ = Capacity16
->LastLba5
;
3351 *Ptr
++ = Capacity16
->LastLba6
;
3352 *Ptr
= Capacity16
->LastLba7
;
3354 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
3355 (Capacity16
->BlockSize2
<< 16) |
3356 (Capacity16
->BlockSize1
<< 8) |
3357 Capacity16
->BlockSize0
;
3359 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
3360 Capacity16
->LowestAlignLogic1
;
3361 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
3362 if (!ScsiDiskDevice
->BlockLimitsVpdSupported
) {
3363 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
> (UINT32
)-1) {
3364 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
)-1;
3366 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
)ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
3371 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
3377 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3382 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
3385 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
)((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
3386 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
)(!ScsiDiskDevice
->FixedDevice
);
3390 Read sector from SCSI Disk.
3392 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3393 @param Buffer The buffer to fill in the read out data
3394 @param Lba Logic block address
3395 @param NumberOfBlocks The number of blocks to read
3397 @retval EFI_DEVICE_ERROR Indicates a device error.
3398 @retval EFI_SUCCESS Operation is successful.
3402 ScsiDiskReadSectors (
3403 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3406 IN UINTN NumberOfBlocks
3409 UINTN BlocksRemaining
;
3415 UINT32 NextSectorCount
;
3422 Status
= EFI_SUCCESS
;
3424 BlocksRemaining
= NumberOfBlocks
;
3425 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3428 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3430 if (!ScsiDiskDevice
->Cdb16Byte
) {
3433 MaxBlock
= 0xFFFFFFFF;
3438 while (BlocksRemaining
> 0) {
3439 if (BlocksRemaining
<= MaxBlock
) {
3440 if (!ScsiDiskDevice
->Cdb16Byte
) {
3441 SectorCount
= (UINT16
)BlocksRemaining
;
3443 SectorCount
= (UINT32
)BlocksRemaining
;
3446 SectorCount
= MaxBlock
;
3449 ByteCount
= SectorCount
* BlockSize
;
3451 // |------------------------|-----------------|------------------|-----------------|
3452 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3453 // |------------------------|-----------------|------------------|-----------------|
3454 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3455 // |------------------------|-----------------|------------------|-----------------|
3456 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3457 // |------------------------|-----------------|------------------|-----------------|
3458 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3459 // |------------------------|-----------------|------------------|-----------------|
3460 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3461 // |------------------------|-----------------|------------------|-----------------|
3462 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3463 // |------------------------|-----------------|------------------|-----------------|
3464 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3465 // |------------------------|-----------------|------------------|-----------------|
3466 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3467 // |------------------------|-----------------|------------------|-----------------|
3468 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3469 // |------------------------|-----------------|------------------|-----------------|
3470 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3471 // |------------------------|-----------------|------------------|-----------------|
3472 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3473 // |------------------------|-----------------|------------------|-----------------|
3475 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3476 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3477 // From the above table, we could know 2.1Mbytes per second is lowest one.
3478 // The timeout value is rounded up to nearest integer and here an additional 30s is added
3479 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3480 // commands in the Standby/Idle mode.
3482 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3485 for (Index
= 0; Index
< MaxRetry
; Index
++) {
3486 if (!ScsiDiskDevice
->Cdb16Byte
) {
3487 Status
= ScsiDiskRead10 (
3497 Status
= ScsiDiskRead16 (
3508 if (!EFI_ERROR (Status
)) {
3513 return EFI_DEVICE_ERROR
;
3517 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
3518 // lowered ByteCount on output, we must make sure that we lower
3519 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3520 // it is invalid to request more sectors in the CDB than the entire
3521 // transfer (ie. ByteCount) can carry.
3523 // In addition, ByteCount is only expected to go down, or stay unchanged.
3524 // Therefore we don't need to update Timeout: the original timeout should
3525 // accommodate shorter transfers too.
3527 NextSectorCount
= ByteCount
/ BlockSize
;
3528 if (NextSectorCount
< SectorCount
) {
3529 SectorCount
= NextSectorCount
;
3531 // Account for any rounding down.
3533 ByteCount
= SectorCount
* BlockSize
;
3537 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
3538 return EFI_DEVICE_ERROR
;
3542 // actual transferred sectors
3544 SectorCount
= ByteCount
/ BlockSize
;
3547 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3548 BlocksRemaining
-= SectorCount
;
3555 Write sector to SCSI Disk.
3557 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3558 @param Buffer The buffer of data to be written into SCSI Disk
3559 @param Lba Logic block address
3560 @param NumberOfBlocks The number of blocks to read
3562 @retval EFI_DEVICE_ERROR Indicates a device error.
3563 @retval EFI_SUCCESS Operation is successful.
3567 ScsiDiskWriteSectors (
3568 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3571 IN UINTN NumberOfBlocks
3574 UINTN BlocksRemaining
;
3580 UINT32 NextSectorCount
;
3587 Status
= EFI_SUCCESS
;
3589 BlocksRemaining
= NumberOfBlocks
;
3590 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3593 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3595 if (!ScsiDiskDevice
->Cdb16Byte
) {
3598 MaxBlock
= 0xFFFFFFFF;
3603 while (BlocksRemaining
> 0) {
3604 if (BlocksRemaining
<= MaxBlock
) {
3605 if (!ScsiDiskDevice
->Cdb16Byte
) {
3606 SectorCount
= (UINT16
)BlocksRemaining
;
3608 SectorCount
= (UINT32
)BlocksRemaining
;
3611 SectorCount
= MaxBlock
;
3614 ByteCount
= SectorCount
* BlockSize
;
3616 // |------------------------|-----------------|------------------|-----------------|
3617 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3618 // |------------------------|-----------------|------------------|-----------------|
3619 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3620 // |------------------------|-----------------|------------------|-----------------|
3621 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3622 // |------------------------|-----------------|------------------|-----------------|
3623 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3624 // |------------------------|-----------------|------------------|-----------------|
3625 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3626 // |------------------------|-----------------|------------------|-----------------|
3627 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3628 // |------------------------|-----------------|------------------|-----------------|
3629 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3630 // |------------------------|-----------------|------------------|-----------------|
3631 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3632 // |------------------------|-----------------|------------------|-----------------|
3633 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3634 // |------------------------|-----------------|------------------|-----------------|
3635 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3636 // |------------------------|-----------------|------------------|-----------------|
3637 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3638 // |------------------------|-----------------|------------------|-----------------|
3640 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3641 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3642 // From the above table, we could know 2.1Mbytes per second is lowest one.
3643 // The timeout value is rounded up to nearest integer and here an additional 30s is added
3644 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3645 // commands in the Standby/Idle mode.
3647 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3649 for (Index
= 0; Index
< MaxRetry
; Index
++) {
3650 if (!ScsiDiskDevice
->Cdb16Byte
) {
3651 Status
= ScsiDiskWrite10 (
3661 Status
= ScsiDiskWrite16 (
3672 if (!EFI_ERROR (Status
)) {
3677 return EFI_DEVICE_ERROR
;
3681 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
3682 // has lowered ByteCount on output, we must make sure that we lower
3683 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3684 // it is invalid to request more sectors in the CDB than the entire
3685 // transfer (ie. ByteCount) can carry.
3687 // In addition, ByteCount is only expected to go down, or stay unchanged.
3688 // Therefore we don't need to update Timeout: the original timeout should
3689 // accommodate shorter transfers too.
3691 NextSectorCount
= ByteCount
/ BlockSize
;
3692 if (NextSectorCount
< SectorCount
) {
3693 SectorCount
= NextSectorCount
;
3695 // Account for any rounding down.
3697 ByteCount
= SectorCount
* BlockSize
;
3701 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
3702 return EFI_DEVICE_ERROR
;
3706 // actual transferred sectors
3708 SectorCount
= ByteCount
/ BlockSize
;
3711 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3712 BlocksRemaining
-= SectorCount
;
3719 Asynchronously read sector from SCSI Disk.
3721 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3722 @param Buffer The buffer to fill in the read out data.
3723 @param Lba Logic block address.
3724 @param NumberOfBlocks The number of blocks to read.
3725 @param Token A pointer to the token associated with the
3726 non-blocking read request.
3728 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
3729 @retval EFI_DEVICE_ERROR Indicates a device error.
3730 @retval EFI_SUCCESS Operation is successful.
3734 ScsiDiskAsyncReadSectors (
3735 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3738 IN UINTN NumberOfBlocks
,
3739 IN EFI_BLOCK_IO2_TOKEN
*Token
3742 UINTN BlocksRemaining
;
3749 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
3753 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
3754 return EFI_INVALID_PARAMETER
;
3757 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
3758 if (BlkIo2Req
== NULL
) {
3759 return EFI_OUT_OF_RESOURCES
;
3762 BlkIo2Req
->Token
= Token
;
3764 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3765 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &BlkIo2Req
->Link
);
3766 gBS
->RestoreTPL (OldTpl
);
3768 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
3770 Status
= EFI_SUCCESS
;
3772 BlocksRemaining
= NumberOfBlocks
;
3773 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3776 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3779 if (!ScsiDiskDevice
->Cdb16Byte
) {
3782 MaxBlock
= 0xFFFFFFFF;
3787 while (BlocksRemaining
> 0) {
3788 if (BlocksRemaining
<= MaxBlock
) {
3789 if (!ScsiDiskDevice
->Cdb16Byte
) {
3790 SectorCount
= (UINT16
)BlocksRemaining
;
3792 SectorCount
= (UINT32
)BlocksRemaining
;
3795 SectorCount
= MaxBlock
;
3798 ByteCount
= SectorCount
* BlockSize
;
3800 // |------------------------|-----------------|------------------|-----------------|
3801 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3802 // |------------------------|-----------------|------------------|-----------------|
3803 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3804 // |------------------------|-----------------|------------------|-----------------|
3805 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3806 // |------------------------|-----------------|------------------|-----------------|
3807 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3808 // |------------------------|-----------------|------------------|-----------------|
3809 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3810 // |------------------------|-----------------|------------------|-----------------|
3811 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3812 // |------------------------|-----------------|------------------|-----------------|
3813 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3814 // |------------------------|-----------------|------------------|-----------------|
3815 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3816 // |------------------------|-----------------|------------------|-----------------|
3817 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3818 // |------------------------|-----------------|------------------|-----------------|
3819 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3820 // |------------------------|-----------------|------------------|-----------------|
3821 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3822 // |------------------------|-----------------|------------------|-----------------|
3824 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3825 // we have to use the lowest transfer rate to calculate the possible
3826 // maximum timeout value for each operation.
3827 // From the above table, we could know 2.1Mbytes per second is lowest one.
3828 // The timeout value is rounded up to nearest integer and here an additional
3829 // 30s is added to follow ATA spec in which it mentioned that the device
3830 // may take up to 30s to respond commands in the Standby/Idle mode.
3832 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3834 if (!ScsiDiskDevice
->Cdb16Byte
) {
3835 Status
= ScsiDiskAsyncRead10 (
3847 Status
= ScsiDiskAsyncRead16 (
3860 if (EFI_ERROR (Status
)) {
3862 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3863 // length of a SCSI I/O command is too large.
3864 // In this case, we retry sending the SCSI command with a data length
3865 // half of its previous value.
3867 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
3868 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
3869 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
3874 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3875 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3877 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3878 // SCSI sub-task running. Otherwise, it will be freed in the callback
3879 // function ScsiDiskNotify().
3881 RemoveEntryList (&BlkIo2Req
->Link
);
3882 FreePool (BlkIo2Req
);
3884 gBS
->RestoreTPL (OldTpl
);
3887 // It is safe to return error status to the caller, since there is no
3888 // previous SCSI sub-task executing.
3890 Status
= EFI_DEVICE_ERROR
;
3893 gBS
->RestoreTPL (OldTpl
);
3896 // There are previous SCSI commands still running, EFI_SUCCESS should
3897 // be returned to make sure that the caller does not free resources
3898 // still using by these SCSI commands.
3900 Status
= EFI_SUCCESS
;
3906 // Sectors submitted for transfer
3908 SectorCount
= ByteCount
/ BlockSize
;
3911 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3912 BlocksRemaining
-= SectorCount
;
3915 Status
= EFI_SUCCESS
;
3918 if (BlkIo2Req
!= NULL
) {
3919 BlkIo2Req
->LastScsiRW
= TRUE
;
3921 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3922 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3923 RemoveEntryList (&BlkIo2Req
->Link
);
3924 FreePool (BlkIo2Req
);
3927 gBS
->SignalEvent (Token
->Event
);
3930 gBS
->RestoreTPL (OldTpl
);
3937 Asynchronously write sector to SCSI Disk.
3939 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3940 @param Buffer The buffer of data to be written into SCSI Disk.
3941 @param Lba Logic block address.
3942 @param NumberOfBlocks The number of blocks to read.
3943 @param Token A pointer to the token associated with the
3944 non-blocking read request.
3946 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
3947 @retval EFI_DEVICE_ERROR Indicates a device error.
3948 @retval EFI_SUCCESS Operation is successful.
3952 ScsiDiskAsyncWriteSectors (
3953 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3956 IN UINTN NumberOfBlocks
,
3957 IN EFI_BLOCK_IO2_TOKEN
*Token
3960 UINTN BlocksRemaining
;
3967 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
3971 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
3972 return EFI_INVALID_PARAMETER
;
3975 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
3976 if (BlkIo2Req
== NULL
) {
3977 return EFI_OUT_OF_RESOURCES
;
3980 BlkIo2Req
->Token
= Token
;
3982 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3983 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &BlkIo2Req
->Link
);
3984 gBS
->RestoreTPL (OldTpl
);
3986 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
3988 Status
= EFI_SUCCESS
;
3990 BlocksRemaining
= NumberOfBlocks
;
3991 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3994 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3997 if (!ScsiDiskDevice
->Cdb16Byte
) {
4000 MaxBlock
= 0xFFFFFFFF;
4005 while (BlocksRemaining
> 0) {
4006 if (BlocksRemaining
<= MaxBlock
) {
4007 if (!ScsiDiskDevice
->Cdb16Byte
) {
4008 SectorCount
= (UINT16
)BlocksRemaining
;
4010 SectorCount
= (UINT32
)BlocksRemaining
;
4013 SectorCount
= MaxBlock
;
4016 ByteCount
= SectorCount
* BlockSize
;
4018 // |------------------------|-----------------|------------------|-----------------|
4019 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
4020 // |------------------------|-----------------|------------------|-----------------|
4021 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
4022 // |------------------------|-----------------|------------------|-----------------|
4023 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
4024 // |------------------------|-----------------|------------------|-----------------|
4025 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
4026 // |------------------------|-----------------|------------------|-----------------|
4027 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
4028 // |------------------------|-----------------|------------------|-----------------|
4029 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
4030 // |------------------------|-----------------|------------------|-----------------|
4031 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
4032 // |------------------------|-----------------|------------------|-----------------|
4033 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
4034 // |------------------------|-----------------|------------------|-----------------|
4035 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
4036 // |------------------------|-----------------|------------------|-----------------|
4037 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
4038 // |------------------------|-----------------|------------------|-----------------|
4039 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
4040 // |------------------------|-----------------|------------------|-----------------|
4042 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
4043 // we have to use the lowest transfer rate to calculate the possible
4044 // maximum timeout value for each operation.
4045 // From the above table, we could know 2.1Mbytes per second is lowest one.
4046 // The timeout value is rounded up to nearest integer and here an additional
4047 // 30s is added to follow ATA spec in which it mentioned that the device
4048 // may take up to 30s to respond commands in the Standby/Idle mode.
4050 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
4052 if (!ScsiDiskDevice
->Cdb16Byte
) {
4053 Status
= ScsiDiskAsyncWrite10 (
4065 Status
= ScsiDiskAsyncWrite16 (
4078 if (EFI_ERROR (Status
)) {
4080 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
4081 // length of a SCSI I/O command is too large.
4082 // In this case, we retry sending the SCSI command with a data length
4083 // half of its previous value.
4085 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
4086 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
4087 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
4092 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4093 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
4095 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
4096 // SCSI sub-task running. Otherwise, it will be freed in the callback
4097 // function ScsiDiskNotify().
4099 RemoveEntryList (&BlkIo2Req
->Link
);
4100 FreePool (BlkIo2Req
);
4102 gBS
->RestoreTPL (OldTpl
);
4105 // It is safe to return error status to the caller, since there is no
4106 // previous SCSI sub-task executing.
4108 Status
= EFI_DEVICE_ERROR
;
4111 gBS
->RestoreTPL (OldTpl
);
4114 // There are previous SCSI commands still running, EFI_SUCCESS should
4115 // be returned to make sure that the caller does not free resources
4116 // still using by these SCSI commands.
4118 Status
= EFI_SUCCESS
;
4124 // Sectors submitted for transfer
4126 SectorCount
= ByteCount
/ BlockSize
;
4129 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
4130 BlocksRemaining
-= SectorCount
;
4133 Status
= EFI_SUCCESS
;
4136 if (BlkIo2Req
!= NULL
) {
4137 BlkIo2Req
->LastScsiRW
= TRUE
;
4139 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4140 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
4141 RemoveEntryList (&BlkIo2Req
->Link
);
4142 FreePool (BlkIo2Req
);
4145 gBS
->SignalEvent (Token
->Event
);
4148 gBS
->RestoreTPL (OldTpl
);
4155 Submit Read(10) command.
4157 @param ScsiDiskDevice The pointer of ScsiDiskDevice
4158 @param NeedRetry The pointer of flag indicates if needs retry if error happens
4159 @param Timeout The time to complete the command
4160 @param DataBuffer The buffer to fill with the read out data
4161 @param DataLength The length of buffer
4162 @param StartLba The start logic block address
4163 @param SectorCount The number of blocks to read
4165 @return EFI_STATUS is returned by calling ScsiRead10Command().
4169 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4170 OUT BOOLEAN
*NeedRetry
,
4172 OUT UINT8
*DataBuffer
,
4173 IN OUT UINT32
*DataLength
,
4175 IN UINT32 SectorCount
4178 UINT8 SenseDataLength
;
4180 EFI_STATUS ReturnStatus
;
4181 UINT8 HostAdapterStatus
;
4186 // Implement a backoff algorithm to resolve some compatibility issues that
4187 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4188 // big data in a single operation.
4189 // This algorithm will at first try to execute original request. If the request fails
4190 // with media error sense data or else, it will reduce the transfer length to half and
4191 // try again till the operation succeeds or fails with one sector transfer length.
4195 Action
= ACTION_NO_ACTION
;
4196 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
4197 ReturnStatus
= ScsiRead10Command (
4198 ScsiDiskDevice
->ScsiIo
,
4200 ScsiDiskDevice
->SenseData
,
4210 if ((ReturnStatus
== EFI_NOT_READY
) || (ReturnStatus
== EFI_BAD_BUFFER_SIZE
)) {
4212 return EFI_DEVICE_ERROR
;
4213 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
4215 return ReturnStatus
;
4219 // go ahead to check HostAdapterStatus and TargetStatus
4220 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4222 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
4223 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4225 return EFI_DEVICE_ERROR
;
4226 } else if (Status
== EFI_DEVICE_ERROR
) {
4228 // reset the scsi channel
4230 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4232 return EFI_DEVICE_ERROR
;
4235 Status
= CheckTargetStatus (TargetStatus
);
4236 if (Status
== EFI_NOT_READY
) {
4238 // reset the scsi device
4240 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4242 return EFI_DEVICE_ERROR
;
4243 } else if (Status
== EFI_DEVICE_ERROR
) {
4245 return EFI_DEVICE_ERROR
;
4248 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
4249 DEBUG ((DEBUG_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
4250 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
4251 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4253 return EFI_DEVICE_ERROR
;
4254 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4255 if (SectorCount
<= 1) {
4257 // Jump out if the operation still fails with one sector transfer length.
4260 return EFI_DEVICE_ERROR
;
4264 // Try again with half length if the sense data shows we need to retry.
4267 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4271 return EFI_DEVICE_ERROR
;
4275 return ReturnStatus
;
4279 Submit Write(10) Command.
4281 @param ScsiDiskDevice The pointer of ScsiDiskDevice
4282 @param NeedRetry The pointer of flag indicates if needs retry if error happens
4283 @param Timeout The time to complete the command
4284 @param DataBuffer The buffer to fill with the read out data
4285 @param DataLength The length of buffer
4286 @param StartLba The start logic block address
4287 @param SectorCount The number of blocks to write
4289 @return EFI_STATUS is returned by calling ScsiWrite10Command().
4294 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4295 OUT BOOLEAN
*NeedRetry
,
4297 IN UINT8
*DataBuffer
,
4298 IN OUT UINT32
*DataLength
,
4300 IN UINT32 SectorCount
4304 EFI_STATUS ReturnStatus
;
4305 UINT8 SenseDataLength
;
4306 UINT8 HostAdapterStatus
;
4311 // Implement a backoff algorithm to resolve some compatibility issues that
4312 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4313 // big data in a single operation.
4314 // This algorithm will at first try to execute original request. If the request fails
4315 // with media error sense data or else, it will reduce the transfer length to half and
4316 // try again till the operation succeeds or fails with one sector transfer length.
4320 Action
= ACTION_NO_ACTION
;
4321 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
4322 ReturnStatus
= ScsiWrite10Command (
4323 ScsiDiskDevice
->ScsiIo
,
4325 ScsiDiskDevice
->SenseData
,
4334 if ((ReturnStatus
== EFI_NOT_READY
) || (ReturnStatus
== EFI_BAD_BUFFER_SIZE
)) {
4336 return EFI_DEVICE_ERROR
;
4337 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
4339 return ReturnStatus
;
4343 // go ahead to check HostAdapterStatus and TargetStatus
4344 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4346 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
4347 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4349 return EFI_DEVICE_ERROR
;
4350 } else if (Status
== EFI_DEVICE_ERROR
) {
4352 // reset the scsi channel
4354 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4356 return EFI_DEVICE_ERROR
;
4359 Status
= CheckTargetStatus (TargetStatus
);
4360 if (Status
== EFI_NOT_READY
) {
4362 // reset the scsi device
4364 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4366 return EFI_DEVICE_ERROR
;
4367 } else if (Status
== EFI_DEVICE_ERROR
) {
4369 return EFI_DEVICE_ERROR
;
4372 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
4373 DEBUG ((DEBUG_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
4374 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
4375 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4377 return EFI_DEVICE_ERROR
;
4378 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4379 if (SectorCount
<= 1) {
4381 // Jump out if the operation still fails with one sector transfer length.
4384 return EFI_DEVICE_ERROR
;
4388 // Try again with half length if the sense data shows we need to retry.
4391 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4395 return EFI_DEVICE_ERROR
;
4399 return ReturnStatus
;
4403 Submit Read(16) command.
4405 @param ScsiDiskDevice The pointer of ScsiDiskDevice
4406 @param NeedRetry The pointer of flag indicates if needs retry if error happens
4407 @param Timeout The time to complete the command
4408 @param DataBuffer The buffer to fill with the read out data
4409 @param DataLength The length of buffer
4410 @param StartLba The start logic block address
4411 @param SectorCount The number of blocks to read
4413 @return EFI_STATUS is returned by calling ScsiRead16Command().
4417 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4418 OUT BOOLEAN
*NeedRetry
,
4420 OUT UINT8
*DataBuffer
,
4421 IN OUT UINT32
*DataLength
,
4423 IN UINT32 SectorCount
4426 UINT8 SenseDataLength
;
4428 EFI_STATUS ReturnStatus
;
4429 UINT8 HostAdapterStatus
;
4434 // Implement a backoff algorithm to resolve some compatibility issues that
4435 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4436 // big data in a single operation.
4437 // This algorithm will at first try to execute original request. If the request fails
4438 // with media error sense data or else, it will reduce the transfer length to half and
4439 // try again till the operation succeeds or fails with one sector transfer length.
4443 Action
= ACTION_NO_ACTION
;
4444 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
4445 ReturnStatus
= ScsiRead16Command (
4446 ScsiDiskDevice
->ScsiIo
,
4448 ScsiDiskDevice
->SenseData
,
4457 if ((ReturnStatus
== EFI_NOT_READY
) || (ReturnStatus
== EFI_BAD_BUFFER_SIZE
)) {
4459 return EFI_DEVICE_ERROR
;
4460 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
4462 return ReturnStatus
;
4466 // go ahead to check HostAdapterStatus and TargetStatus
4467 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4469 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
4470 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4472 return EFI_DEVICE_ERROR
;
4473 } else if (Status
== EFI_DEVICE_ERROR
) {
4475 // reset the scsi channel
4477 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4479 return EFI_DEVICE_ERROR
;
4482 Status
= CheckTargetStatus (TargetStatus
);
4483 if (Status
== EFI_NOT_READY
) {
4485 // reset the scsi device
4487 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4489 return EFI_DEVICE_ERROR
;
4490 } else if (Status
== EFI_DEVICE_ERROR
) {
4492 return EFI_DEVICE_ERROR
;
4495 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
4496 DEBUG ((DEBUG_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
4497 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
4498 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4500 return EFI_DEVICE_ERROR
;
4501 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4502 if (SectorCount
<= 1) {
4504 // Jump out if the operation still fails with one sector transfer length.
4507 return EFI_DEVICE_ERROR
;
4511 // Try again with half length if the sense data shows we need to retry.
4514 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4518 return EFI_DEVICE_ERROR
;
4522 return ReturnStatus
;
4526 Submit Write(16) Command.
4528 @param ScsiDiskDevice The pointer of ScsiDiskDevice
4529 @param NeedRetry The pointer of flag indicates if needs retry if error happens
4530 @param Timeout The time to complete the command
4531 @param DataBuffer The buffer to fill with the read out data
4532 @param DataLength The length of buffer
4533 @param StartLba The start logic block address
4534 @param SectorCount The number of blocks to write
4536 @return EFI_STATUS is returned by calling ScsiWrite16Command().
4541 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4542 OUT BOOLEAN
*NeedRetry
,
4544 IN UINT8
*DataBuffer
,
4545 IN OUT UINT32
*DataLength
,
4547 IN UINT32 SectorCount
4551 EFI_STATUS ReturnStatus
;
4552 UINT8 SenseDataLength
;
4553 UINT8 HostAdapterStatus
;
4558 // Implement a backoff algorithm to resolve some compatibility issues that
4559 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4560 // big data in a single operation.
4561 // This algorithm will at first try to execute original request. If the request fails
4562 // with media error sense data or else, it will reduce the transfer length to half and
4563 // try again till the operation succeeds or fails with one sector transfer length.
4567 Action
= ACTION_NO_ACTION
;
4568 SenseDataLength
= (UINT8
)(ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
4569 ReturnStatus
= ScsiWrite16Command (
4570 ScsiDiskDevice
->ScsiIo
,
4572 ScsiDiskDevice
->SenseData
,
4581 if ((ReturnStatus
== EFI_NOT_READY
) || (ReturnStatus
== EFI_BAD_BUFFER_SIZE
)) {
4583 return EFI_DEVICE_ERROR
;
4584 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
4586 return ReturnStatus
;
4590 // go ahead to check HostAdapterStatus and TargetStatus
4591 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4593 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
4594 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4596 return EFI_DEVICE_ERROR
;
4597 } else if (Status
== EFI_DEVICE_ERROR
) {
4599 // reset the scsi channel
4601 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4603 return EFI_DEVICE_ERROR
;
4606 Status
= CheckTargetStatus (TargetStatus
);
4607 if (Status
== EFI_NOT_READY
) {
4609 // reset the scsi device
4611 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4613 return EFI_DEVICE_ERROR
;
4614 } else if (Status
== EFI_DEVICE_ERROR
) {
4616 return EFI_DEVICE_ERROR
;
4619 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
4620 DEBUG ((DEBUG_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
4621 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
4622 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4624 return EFI_DEVICE_ERROR
;
4625 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4626 if (SectorCount
<= 1) {
4628 // Jump out if the operation still fails with one sector transfer length.
4631 return EFI_DEVICE_ERROR
;
4635 // Try again with half length if the sense data shows we need to retry.
4638 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4642 return EFI_DEVICE_ERROR
;
4646 return ReturnStatus
;
4650 Internal helper notify function in which determine whether retry of a SCSI
4651 Read/Write command is needed and signal the event passed from Block I/O(2) if
4652 the SCSI I/O operation completes.
4654 @param Event The instance of EFI_EVENT.
4655 @param Context The parameter passed in.
4666 SCSI_ASYNC_RW_REQUEST
*Request
;
4667 SCSI_DISK_DEV
*ScsiDiskDevice
;
4668 EFI_BLOCK_IO2_TOKEN
*Token
;
4670 UINT32 OldDataLength
;
4671 UINT32 OldSectorCount
;
4674 gBS
->CloseEvent (Event
);
4676 Request
= (SCSI_ASYNC_RW_REQUEST
*)Context
;
4677 ScsiDiskDevice
= Request
->ScsiDiskDevice
;
4678 Token
= Request
->BlkIo2Req
->Token
;
4679 OldDataLength
= Request
->DataLength
;
4680 OldSectorCount
= Request
->SectorCount
;
4684 // If previous sub-tasks already fails, no need to process this sub-task.
4686 if (Token
->TransactionStatus
!= EFI_SUCCESS
) {
4691 // Check HostAdapterStatus and TargetStatus
4692 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4694 Status
= CheckHostAdapterStatus (Request
->HostAdapterStatus
);
4695 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4696 if (++Request
->TimesRetry
> MaxRetry
) {
4697 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4702 } else if (Status
== EFI_DEVICE_ERROR
) {
4704 // reset the scsi channel
4706 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4707 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4711 Status
= CheckTargetStatus (Request
->TargetStatus
);
4712 if (Status
== EFI_NOT_READY
) {
4714 // reset the scsi device
4716 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4717 if (++Request
->TimesRetry
> MaxRetry
) {
4718 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4723 } else if (Status
== EFI_DEVICE_ERROR
) {
4724 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4728 if (Request
->TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) {
4729 DEBUG ((DEBUG_ERROR
, "ScsiDiskNotify: Check Condition happened!\n"));
4731 Status
= DetectMediaParsingSenseKeys (
4734 Request
->SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
),
4737 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4738 if (++Request
->TimesRetry
> MaxRetry
) {
4739 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4744 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4745 if (Request
->SectorCount
<= 1) {
4747 // Jump out if the operation still fails with one sector transfer
4750 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4755 // Try again with two half length request if the sense data shows we need
4758 Request
->SectorCount
>>= 1;
4759 Request
->DataLength
= Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4760 Request
->TimesRetry
= 0;
4764 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4770 // This sub-task succeeds, no need to retry.
4775 if (Request
->InBuffer
!= NULL
) {
4777 // SCSI read command
4779 if (!ScsiDiskDevice
->Cdb16Byte
) {
4780 Status
= ScsiDiskAsyncRead10 (
4783 Request
->TimesRetry
,
4785 Request
->DataLength
,
4786 (UINT32
)Request
->StartLba
,
4787 Request
->SectorCount
,
4792 Status
= ScsiDiskAsyncRead16 (
4795 Request
->TimesRetry
,
4797 Request
->DataLength
,
4799 Request
->SectorCount
,
4805 if (EFI_ERROR (Status
)) {
4806 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4808 } else if (OldSectorCount
!= Request
->SectorCount
) {
4810 // Original sub-task will be split into two new sub-tasks with smaller
4813 if (!ScsiDiskDevice
->Cdb16Byte
) {
4814 Status
= ScsiDiskAsyncRead10 (
4818 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4819 OldDataLength
- Request
->DataLength
,
4820 (UINT32
)Request
->StartLba
+ Request
->SectorCount
,
4821 OldSectorCount
- Request
->SectorCount
,
4826 Status
= ScsiDiskAsyncRead16 (
4830 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4831 OldDataLength
- Request
->DataLength
,
4832 Request
->StartLba
+ Request
->SectorCount
,
4833 OldSectorCount
- Request
->SectorCount
,
4839 if (EFI_ERROR (Status
)) {
4840 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4846 // SCSI write command
4848 if (!ScsiDiskDevice
->Cdb16Byte
) {
4849 Status
= ScsiDiskAsyncWrite10 (
4852 Request
->TimesRetry
,
4854 Request
->DataLength
,
4855 (UINT32
)Request
->StartLba
,
4856 Request
->SectorCount
,
4861 Status
= ScsiDiskAsyncWrite16 (
4864 Request
->TimesRetry
,
4866 Request
->DataLength
,
4868 Request
->SectorCount
,
4874 if (EFI_ERROR (Status
)) {
4875 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4877 } else if (OldSectorCount
!= Request
->SectorCount
) {
4879 // Original sub-task will be split into two new sub-tasks with smaller
4882 if (!ScsiDiskDevice
->Cdb16Byte
) {
4883 Status
= ScsiDiskAsyncWrite10 (
4887 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4888 OldDataLength
- Request
->DataLength
,
4889 (UINT32
)Request
->StartLba
+ Request
->SectorCount
,
4890 OldSectorCount
- Request
->SectorCount
,
4895 Status
= ScsiDiskAsyncWrite16 (
4899 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4900 OldDataLength
- Request
->DataLength
,
4901 Request
->StartLba
+ Request
->SectorCount
,
4902 OldSectorCount
- Request
->SectorCount
,
4908 if (EFI_ERROR (Status
)) {
4909 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4916 RemoveEntryList (&Request
->Link
);
4917 if ((IsListEmpty (&Request
->BlkIo2Req
->ScsiRWQueue
)) &&
4918 (Request
->BlkIo2Req
->LastScsiRW
))
4921 // The last SCSI R/W command of a BlockIo2 request completes
4923 RemoveEntryList (&Request
->BlkIo2Req
->Link
);
4924 FreePool (Request
->BlkIo2Req
); // Should be freed only once
4925 gBS
->SignalEvent (Token
->Event
);
4928 FreePool (Request
->SenseData
);
4933 Submit Async Read(10) command.
4935 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4936 @param Timeout The time to complete the command.
4937 @param TimesRetry The number of times the command has been retried.
4938 @param DataBuffer The buffer to fill with the read out data.
4939 @param DataLength The length of buffer.
4940 @param StartLba The start logic block address.
4941 @param SectorCount The number of blocks to read.
4942 @param BlkIo2Req The upstream BlockIo2 request.
4943 @param Token The pointer to the token associated with the
4944 non-blocking read request.
4946 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4948 @return others Status returned by calling
4949 ScsiRead10CommandEx().
4953 ScsiDiskAsyncRead10 (
4954 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4956 IN UINT8 TimesRetry
,
4957 OUT UINT8
*DataBuffer
,
4958 IN UINT32 DataLength
,
4960 IN UINT32 SectorCount
,
4961 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4962 IN EFI_BLOCK_IO2_TOKEN
*Token
4966 SCSI_ASYNC_RW_REQUEST
*Request
;
4967 EFI_EVENT AsyncIoEvent
;
4970 AsyncIoEvent
= NULL
;
4972 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4973 if (Request
== NULL
) {
4974 return EFI_OUT_OF_RESOURCES
;
4977 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4978 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4979 gBS
->RestoreTPL (OldTpl
);
4981 Request
->SenseDataLength
= (UINT8
)(6 * sizeof (EFI_SCSI_SENSE_DATA
));
4982 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4983 if (Request
->SenseData
== NULL
) {
4984 Status
= EFI_OUT_OF_RESOURCES
;
4988 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4989 Request
->Timeout
= Timeout
;
4990 Request
->TimesRetry
= TimesRetry
;
4991 Request
->InBuffer
= DataBuffer
;
4992 Request
->DataLength
= DataLength
;
4993 Request
->StartLba
= StartLba
;
4994 Request
->SectorCount
= SectorCount
;
4995 Request
->BlkIo2Req
= BlkIo2Req
;
5000 Status
= gBS
->CreateEvent (
5007 if (EFI_ERROR (Status
)) {
5011 Status
= ScsiRead10CommandEx (
5012 ScsiDiskDevice
->ScsiIo
,
5015 &Request
->SenseDataLength
,
5016 &Request
->HostAdapterStatus
,
5017 &Request
->TargetStatus
,
5019 &Request
->DataLength
,
5020 (UINT32
)Request
->StartLba
,
5021 Request
->SectorCount
,
5024 if (EFI_ERROR (Status
)) {
5031 if (AsyncIoEvent
!= NULL
) {
5032 gBS
->CloseEvent (AsyncIoEvent
);
5035 if (Request
!= NULL
) {
5036 if (Request
->SenseData
!= NULL
) {
5037 FreePool (Request
->SenseData
);
5040 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5041 RemoveEntryList (&Request
->Link
);
5042 gBS
->RestoreTPL (OldTpl
);
5051 Submit Async Write(10) command.
5053 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
5054 @param Timeout The time to complete the command.
5055 @param TimesRetry The number of times the command has been retried.
5056 @param DataBuffer The buffer contains the data to write.
5057 @param DataLength The length of buffer.
5058 @param StartLba The start logic block address.
5059 @param SectorCount The number of blocks to write.
5060 @param BlkIo2Req The upstream BlockIo2 request.
5061 @param Token The pointer to the token associated with the
5062 non-blocking read request.
5064 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
5066 @return others Status returned by calling
5067 ScsiWrite10CommandEx().
5071 ScsiDiskAsyncWrite10 (
5072 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5074 IN UINT8 TimesRetry
,
5075 IN UINT8
*DataBuffer
,
5076 IN UINT32 DataLength
,
5078 IN UINT32 SectorCount
,
5079 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
5080 IN EFI_BLOCK_IO2_TOKEN
*Token
5084 SCSI_ASYNC_RW_REQUEST
*Request
;
5085 EFI_EVENT AsyncIoEvent
;
5088 AsyncIoEvent
= NULL
;
5090 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
5091 if (Request
== NULL
) {
5092 return EFI_OUT_OF_RESOURCES
;
5095 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5096 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
5097 gBS
->RestoreTPL (OldTpl
);
5099 Request
->SenseDataLength
= (UINT8
)(6 * sizeof (EFI_SCSI_SENSE_DATA
));
5100 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
5101 if (Request
->SenseData
== NULL
) {
5102 Status
= EFI_OUT_OF_RESOURCES
;
5106 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
5107 Request
->Timeout
= Timeout
;
5108 Request
->TimesRetry
= TimesRetry
;
5109 Request
->OutBuffer
= DataBuffer
;
5110 Request
->DataLength
= DataLength
;
5111 Request
->StartLba
= StartLba
;
5112 Request
->SectorCount
= SectorCount
;
5113 Request
->BlkIo2Req
= BlkIo2Req
;
5118 Status
= gBS
->CreateEvent (
5125 if (EFI_ERROR (Status
)) {
5129 Status
= ScsiWrite10CommandEx (
5130 ScsiDiskDevice
->ScsiIo
,
5133 &Request
->SenseDataLength
,
5134 &Request
->HostAdapterStatus
,
5135 &Request
->TargetStatus
,
5137 &Request
->DataLength
,
5138 (UINT32
)Request
->StartLba
,
5139 Request
->SectorCount
,
5142 if (EFI_ERROR (Status
)) {
5149 if (AsyncIoEvent
!= NULL
) {
5150 gBS
->CloseEvent (AsyncIoEvent
);
5153 if (Request
!= NULL
) {
5154 if (Request
->SenseData
!= NULL
) {
5155 FreePool (Request
->SenseData
);
5158 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5159 RemoveEntryList (&Request
->Link
);
5160 gBS
->RestoreTPL (OldTpl
);
5169 Submit Async Read(16) command.
5171 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
5172 @param Timeout The time to complete the command.
5173 @param TimesRetry The number of times the command has been retried.
5174 @param DataBuffer The buffer to fill with the read out data.
5175 @param DataLength The length of buffer.
5176 @param StartLba The start logic block address.
5177 @param SectorCount The number of blocks to read.
5178 @param BlkIo2Req The upstream BlockIo2 request.
5179 @param Token The pointer to the token associated with the
5180 non-blocking read request.
5182 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
5184 @return others Status returned by calling
5185 ScsiRead16CommandEx().
5189 ScsiDiskAsyncRead16 (
5190 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5192 IN UINT8 TimesRetry
,
5193 OUT UINT8
*DataBuffer
,
5194 IN UINT32 DataLength
,
5196 IN UINT32 SectorCount
,
5197 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
5198 IN EFI_BLOCK_IO2_TOKEN
*Token
5202 SCSI_ASYNC_RW_REQUEST
*Request
;
5203 EFI_EVENT AsyncIoEvent
;
5206 AsyncIoEvent
= NULL
;
5208 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
5209 if (Request
== NULL
) {
5210 return EFI_OUT_OF_RESOURCES
;
5213 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5214 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
5215 gBS
->RestoreTPL (OldTpl
);
5217 Request
->SenseDataLength
= (UINT8
)(6 * sizeof (EFI_SCSI_SENSE_DATA
));
5218 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
5219 if (Request
->SenseData
== NULL
) {
5220 Status
= EFI_OUT_OF_RESOURCES
;
5224 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
5225 Request
->Timeout
= Timeout
;
5226 Request
->TimesRetry
= TimesRetry
;
5227 Request
->InBuffer
= DataBuffer
;
5228 Request
->DataLength
= DataLength
;
5229 Request
->StartLba
= StartLba
;
5230 Request
->SectorCount
= SectorCount
;
5231 Request
->BlkIo2Req
= BlkIo2Req
;
5236 Status
= gBS
->CreateEvent (
5243 if (EFI_ERROR (Status
)) {
5247 Status
= ScsiRead16CommandEx (
5248 ScsiDiskDevice
->ScsiIo
,
5251 &Request
->SenseDataLength
,
5252 &Request
->HostAdapterStatus
,
5253 &Request
->TargetStatus
,
5255 &Request
->DataLength
,
5257 Request
->SectorCount
,
5260 if (EFI_ERROR (Status
)) {
5267 if (AsyncIoEvent
!= NULL
) {
5268 gBS
->CloseEvent (AsyncIoEvent
);
5271 if (Request
!= NULL
) {
5272 if (Request
->SenseData
!= NULL
) {
5273 FreePool (Request
->SenseData
);
5276 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5277 RemoveEntryList (&Request
->Link
);
5278 gBS
->RestoreTPL (OldTpl
);
5287 Submit Async Write(16) command.
5289 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
5290 @param Timeout The time to complete the command.
5291 @param TimesRetry The number of times the command has been retried.
5292 @param DataBuffer The buffer contains the data to write.
5293 @param DataLength The length of buffer.
5294 @param StartLba The start logic block address.
5295 @param SectorCount The number of blocks to write.
5296 @param BlkIo2Req The upstream BlockIo2 request.
5297 @param Token The pointer to the token associated with the
5298 non-blocking read request.
5300 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
5302 @return others Status returned by calling
5303 ScsiWrite16CommandEx().
5307 ScsiDiskAsyncWrite16 (
5308 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5310 IN UINT8 TimesRetry
,
5311 IN UINT8
*DataBuffer
,
5312 IN UINT32 DataLength
,
5314 IN UINT32 SectorCount
,
5315 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
5316 IN EFI_BLOCK_IO2_TOKEN
*Token
5320 SCSI_ASYNC_RW_REQUEST
*Request
;
5321 EFI_EVENT AsyncIoEvent
;
5324 AsyncIoEvent
= NULL
;
5326 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
5327 if (Request
== NULL
) {
5328 return EFI_OUT_OF_RESOURCES
;
5331 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5332 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
5333 gBS
->RestoreTPL (OldTpl
);
5335 Request
->SenseDataLength
= (UINT8
)(6 * sizeof (EFI_SCSI_SENSE_DATA
));
5336 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
5337 if (Request
->SenseData
== NULL
) {
5338 Status
= EFI_OUT_OF_RESOURCES
;
5342 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
5343 Request
->Timeout
= Timeout
;
5344 Request
->TimesRetry
= TimesRetry
;
5345 Request
->OutBuffer
= DataBuffer
;
5346 Request
->DataLength
= DataLength
;
5347 Request
->StartLba
= StartLba
;
5348 Request
->SectorCount
= SectorCount
;
5349 Request
->BlkIo2Req
= BlkIo2Req
;
5354 Status
= gBS
->CreateEvent (
5361 if (EFI_ERROR (Status
)) {
5365 Status
= ScsiWrite16CommandEx (
5366 ScsiDiskDevice
->ScsiIo
,
5369 &Request
->SenseDataLength
,
5370 &Request
->HostAdapterStatus
,
5371 &Request
->TargetStatus
,
5373 &Request
->DataLength
,
5375 Request
->SectorCount
,
5378 if (EFI_ERROR (Status
)) {
5385 if (AsyncIoEvent
!= NULL
) {
5386 gBS
->CloseEvent (AsyncIoEvent
);
5389 if (Request
!= NULL
) {
5390 if (Request
->SenseData
!= NULL
) {
5391 FreePool (Request
->SenseData
);
5394 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
5395 RemoveEntryList (&Request
->Link
);
5396 gBS
->RestoreTPL (OldTpl
);
5405 Check sense key to find if media presents.
5407 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5408 @param SenseCounts The number of sense key
5410 @retval TRUE NOT any media
5411 @retval FALSE Media presents
5415 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5416 IN UINTN SenseCounts
5419 EFI_SCSI_SENSE_DATA
*SensePtr
;
5424 SensePtr
= SenseData
;
5426 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5428 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
5429 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
5431 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
5432 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
))
5446 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5447 @param SenseCounts The number of sense key
5450 @retval FALSE NOT error
5454 ScsiDiskIsMediaError (
5455 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5456 IN UINTN SenseCounts
5459 EFI_SCSI_SENSE_DATA
*SensePtr
;
5464 SensePtr
= SenseData
;
5466 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5467 switch (SensePtr
->Sense_Key
) {
5468 case EFI_SCSI_SK_MEDIUM_ERROR
:
5470 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
5472 switch (SensePtr
->Addnl_Sense_Code
) {
5476 case EFI_SCSI_ASC_MEDIA_ERR1
:
5481 case EFI_SCSI_ASC_MEDIA_ERR2
:
5486 case EFI_SCSI_ASC_MEDIA_ERR3
:
5487 case EFI_SCSI_ASC_MEDIA_ERR4
:
5497 case EFI_SCSI_SK_NOT_READY
:
5499 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5501 switch (SensePtr
->Addnl_Sense_Code
) {
5503 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
5505 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
5526 Check sense key to find if hardware error happens.
5528 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5529 @param SenseCounts The number of sense key
5531 @retval TRUE Hardware error exits.
5532 @retval FALSE NO error.
5536 ScsiDiskIsHardwareError (
5537 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5538 IN UINTN SenseCounts
5541 EFI_SCSI_SENSE_DATA
*SensePtr
;
5546 SensePtr
= SenseData
;
5548 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5550 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
5552 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
5563 Check sense key to find if media has changed.
5565 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5566 @param SenseCounts The number of sense key
5568 @retval TRUE Media is changed.
5569 @retval FALSE Media is NOT changed.
5572 ScsiDiskIsMediaChange (
5573 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5574 IN UINTN SenseCounts
5577 EFI_SCSI_SENSE_DATA
*SensePtr
;
5579 BOOLEAN IsMediaChanged
;
5581 IsMediaChanged
= FALSE
;
5582 SensePtr
= SenseData
;
5584 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5586 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
5587 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
5589 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
5590 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
))
5592 IsMediaChanged
= TRUE
;
5598 return IsMediaChanged
;
5602 Check sense key to find if reset happens.
5604 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5605 @param SenseCounts The number of sense key
5607 @retval TRUE It is reset before.
5608 @retval FALSE It is NOT reset before.
5612 ScsiDiskIsResetBefore (
5613 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5614 IN UINTN SenseCounts
5617 EFI_SCSI_SENSE_DATA
*SensePtr
;
5619 BOOLEAN IsResetBefore
;
5621 IsResetBefore
= FALSE
;
5622 SensePtr
= SenseData
;
5624 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5626 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
5627 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
5629 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
5630 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
))
5632 IsResetBefore
= TRUE
;
5638 return IsResetBefore
;
5642 Check sense key to find if the drive is ready.
5644 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5645 @param SenseCounts The number of sense key
5646 @param RetryLater The flag means if need a retry
5648 @retval TRUE Drive is ready.
5649 @retval FALSE Drive is NOT ready.
5653 ScsiDiskIsDriveReady (
5654 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5655 IN UINTN SenseCounts
,
5656 OUT BOOLEAN
*RetryLater
5659 EFI_SCSI_SENSE_DATA
*SensePtr
;
5664 *RetryLater
= FALSE
;
5665 SensePtr
= SenseData
;
5667 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5668 switch (SensePtr
->Sense_Key
) {
5669 case EFI_SCSI_SK_NOT_READY
:
5671 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5673 switch (SensePtr
->Addnl_Sense_Code
) {
5674 case EFI_SCSI_ASC_NOT_READY
:
5676 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
5678 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
5679 case EFI_SCSI_ASCQ_IN_PROGRESS
:
5681 // Additional Sense Code Qualifier is
5682 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
5690 *RetryLater
= FALSE
;
5713 Check sense key to find if it has sense key.
5715 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
5716 @param SenseCounts - The number of sense key
5718 @retval TRUE It has sense key.
5719 @retval FALSE It has NOT any sense key.
5723 ScsiDiskHaveSenseKey (
5724 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5725 IN UINTN SenseCounts
5728 EFI_SCSI_SENSE_DATA
*SensePtr
;
5730 BOOLEAN HaveSenseKey
;
5732 if (SenseCounts
== 0) {
5733 HaveSenseKey
= FALSE
;
5735 HaveSenseKey
= TRUE
;
5738 SensePtr
= SenseData
;
5740 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5742 // Sense Key is SK_NO_SENSE (0x0)
5744 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
5747 HaveSenseKey
= FALSE
;
5753 return HaveSenseKey
;
5757 Release resource about disk device.
5759 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
5763 ReleaseScsiDiskDeviceResources (
5764 IN SCSI_DISK_DEV
*ScsiDiskDevice
5767 if (ScsiDiskDevice
== NULL
) {
5771 if (ScsiDiskDevice
->SenseData
!= NULL
) {
5772 FreePool (ScsiDiskDevice
->SenseData
);
5773 ScsiDiskDevice
->SenseData
= NULL
;
5776 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
5777 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
5778 ScsiDiskDevice
->ControllerNameTable
= NULL
;
5781 FreePool (ScsiDiskDevice
);
5783 ScsiDiskDevice
= NULL
;
5787 Determine if Block Io & Block Io2 should be produced.
5790 @param ChildHandle Child Handle to retrieve Parent information.
5792 @retval TRUE Should produce Block Io & Block Io2.
5793 @retval FALSE Should not produce Block Io & Block Io2.
5797 DetermineInstallBlockIo (
5798 IN EFI_HANDLE ChildHandle
5801 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
5802 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
5805 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
5806 // check its attribute, logic or physical.
5808 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
5809 if (ExtScsiPassThru
!= NULL
) {
5810 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
5816 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
5817 // check its attribute, logic or physical.
5819 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
5820 if (ScsiPassThru
!= NULL
) {
5821 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
5830 Search protocol database and check to see if the protocol
5831 specified by ProtocolGuid is present on a ControllerHandle and opened by
5832 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
5833 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
5834 will be opened on it.
5837 @param ProtocolGuid ProtocolGuid pointer.
5838 @param ChildHandle Child Handle to retrieve Parent information.
5844 IN EFI_GUID
*ProtocolGuid
,
5845 IN EFI_HANDLE ChildHandle
5852 EFI_HANDLE
*HandleBuffer
;
5855 // Retrieve the list of all handles from the handle database
5857 Status
= gBS
->LocateHandleBuffer (
5865 if (EFI_ERROR (Status
)) {
5870 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
5872 for (Index
= 0; Index
< HandleCount
; Index
++) {
5873 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
5874 if (!EFI_ERROR (Status
)) {
5875 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
5876 if (!EFI_ERROR (Status
)) {
5877 gBS
->FreePool (HandleBuffer
);
5883 gBS
->FreePool (HandleBuffer
);
5888 Determine if EFI Erase Block Protocol should be produced.
5890 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
5891 @param ChildHandle Handle of device.
5893 @retval TRUE Should produce EFI Erase Block Protocol.
5894 @retval FALSE Should not produce EFI Erase Block Protocol.
5898 DetermineInstallEraseBlock (
5899 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5900 IN EFI_HANDLE ChildHandle
5903 UINT8 HostAdapterStatus
;
5905 EFI_STATUS CommandStatus
;
5909 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
5910 UINT8 SenseDataLength
;
5911 UINT32 DataLength16
;
5912 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
5916 CapacityData16
= NULL
;
5919 // UNMAP command is not supported by any of the UFS WLUNs.
5921 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_WLUN
) {
5926 Status
= gBS
->HandleProtocol (
5928 &gEfiDevicePathProtocolGuid
,
5929 (VOID
**)&DevicePathNode
5932 // Device Path protocol must be installed on the device handle.
5934 ASSERT_EFI_ERROR (Status
);
5936 while (!IsDevicePathEndType (DevicePathNode
)) {
5938 // For now, only support Erase Block Protocol on UFS devices.
5940 if ((DevicePathNode
->Type
== MESSAGING_DEVICE_PATH
) &&
5941 (DevicePathNode
->SubType
== MSG_UFS_DP
))
5947 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
5956 // Check whether the erase functionality is enabled on the UFS device.
5958 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
5959 if (CapacityData16
== NULL
) {
5964 SenseDataLength
= 0;
5965 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
5966 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
5968 CommandStatus
= ScsiReadCapacity16Command (
5969 ScsiDiskDevice
->ScsiIo
,
5975 (VOID
*)CapacityData16
,
5980 if (CommandStatus
== EFI_SUCCESS
) {
5982 // Universal Flash Storage (UFS) Version 2.0
5984 // Bits TPE and TPRZ should both be set to enable the erase feature on UFS.
5986 if (((CapacityData16
->LowestAlignLogic2
& BIT7
) == 0) ||
5987 ((CapacityData16
->LowestAlignLogic2
& BIT6
) == 0))
5991 "ScsiDisk EraseBlock: Either TPE or TPRZ is not set: 0x%x.\n",
5992 CapacityData16
->LowestAlignLogic2
6001 "ScsiDisk EraseBlock: ReadCapacity16 failed with status %r.\n",
6010 // Check whether the UFS device server implements the UNMAP command.
6012 if ((ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
== 0) ||
6013 (ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
== 0))
6017 "ScsiDisk EraseBlock: The device server does not implement the UNMAP command.\n"
6025 if (CapacityData16
!= NULL
) {
6026 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
6033 Determine if EFI Storage Security Command Protocol should be produced.
6035 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
6036 @param ChildHandle Handle of device.
6038 @retval TRUE Should produce EFI Storage Security Command Protocol.
6039 @retval FALSE Should not produce EFI Storage Security Command Protocol.
6043 DetermineInstallStorageSecurity (
6044 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
6045 IN EFI_HANDLE ChildHandle
6049 UFS_DEVICE_PATH
*UfsDevice
;
6051 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
6056 Status
= gBS
->HandleProtocol (
6058 &gEfiDevicePathProtocolGuid
,
6059 (VOID
**)&DevicePathNode
6062 // Device Path protocol must be installed on the device handle.
6064 ASSERT_EFI_ERROR (Status
);
6066 while (!IsDevicePathEndType (DevicePathNode
)) {
6068 // For now, only support Storage Security Command Protocol on UFS devices.
6070 if ((DevicePathNode
->Type
== MESSAGING_DEVICE_PATH
) &&
6071 (DevicePathNode
->SubType
== MSG_UFS_DP
))
6073 UfsDevice
= (UFS_DEVICE_PATH
*)DevicePathNode
;
6077 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
6080 if (UfsDevice
== NULL
) {
6085 if (UfsDevice
->Lun
!= UFS_WLUN_RPMB
) {
6094 Provides inquiry information for the controller type.
6096 This function is used by the IDE bus driver to get inquiry data. Data format
6097 of Identify data is defined by the Interface GUID.
6099 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
6100 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
6101 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
6103 @retval EFI_SUCCESS The command was accepted without any errors.
6104 @retval EFI_NOT_FOUND Device does not support this data class
6105 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
6106 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
6111 ScsiDiskInfoInquiry (
6112 IN EFI_DISK_INFO_PROTOCOL
*This
,
6113 IN OUT VOID
*InquiryData
,
6114 IN OUT UINT32
*InquiryDataSize
6118 SCSI_DISK_DEV
*ScsiDiskDevice
;
6120 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
6122 Status
= EFI_BUFFER_TOO_SMALL
;
6123 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
6124 Status
= EFI_SUCCESS
;
6125 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
6128 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
6133 Provides identify information for the controller type.
6135 This function is used by the IDE bus driver to get identify data. Data format
6136 of Identify data is defined by the Interface GUID.
6138 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
6140 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
6141 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
6144 @retval EFI_SUCCESS The command was accepted without any errors.
6145 @retval EFI_NOT_FOUND Device does not support this data class
6146 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
6147 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
6152 ScsiDiskInfoIdentify (
6153 IN EFI_DISK_INFO_PROTOCOL
*This
,
6154 IN OUT VOID
*IdentifyData
,
6155 IN OUT UINT32
*IdentifyDataSize
6159 SCSI_DISK_DEV
*ScsiDiskDevice
;
6161 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
6163 // Physical SCSI bus does not support this data class.
6165 return EFI_NOT_FOUND
;
6168 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
6170 Status
= EFI_BUFFER_TOO_SMALL
;
6171 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
6172 Status
= EFI_SUCCESS
;
6173 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
6176 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
6181 Provides sense data information for the controller type.
6183 This function is used by the IDE bus driver to get sense data.
6184 Data format of Sense data is defined by the Interface GUID.
6186 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
6187 @param[in, out] SenseData Pointer to the SenseData.
6188 @param[in, out] SenseDataSize Size of SenseData in bytes.
6189 @param[out] SenseDataNumber Pointer to the value for the sense data size.
6191 @retval EFI_SUCCESS The command was accepted without any errors.
6192 @retval EFI_NOT_FOUND Device does not support this data class.
6193 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
6194 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
6199 ScsiDiskInfoSenseData (
6200 IN EFI_DISK_INFO_PROTOCOL
*This
,
6201 IN OUT VOID
*SenseData
,
6202 IN OUT UINT32
*SenseDataSize
,
6203 OUT UINT8
*SenseDataNumber
6206 return EFI_NOT_FOUND
;
6210 This function is used by the IDE bus driver to get controller information.
6212 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
6213 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
6214 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
6216 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
6217 @retval EFI_UNSUPPORTED This is not an IDE device.
6222 ScsiDiskInfoWhichIde (
6223 IN EFI_DISK_INFO_PROTOCOL
*This
,
6224 OUT UINT32
*IdeChannel
,
6225 OUT UINT32
*IdeDevice
6228 SCSI_DISK_DEV
*ScsiDiskDevice
;
6230 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
6232 // This is not an IDE physical device.
6234 return EFI_UNSUPPORTED
;
6237 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
6238 *IdeChannel
= ScsiDiskDevice
->Channel
;
6239 *IdeDevice
= ScsiDiskDevice
->Device
;
6245 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
6247 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
6248 implement Identify() interface for DiskInfo protocol. The ATA command is sent
6249 via SCSI Request Packet.
6251 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
6253 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
6254 @retval others Some error occurred during the identification that ATAPI device.
6258 AtapiIdentifyDevice (
6259 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
6262 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
6266 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
6268 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
6269 ZeroMem (Cdb
, sizeof (Cdb
));
6271 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
6272 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
6273 CommandPacket
.Cdb
= Cdb
;
6274 CommandPacket
.CdbLength
= (UINT8
)sizeof (Cdb
);
6275 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
6276 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
6278 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
6282 Initialize the installation of DiskInfo protocol.
6284 This function prepares for the installation of DiskInfo protocol on the child handle.
6285 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
6286 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
6287 to be IDE/AHCI interface GUID.
6289 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
6290 @param ChildHandle Child handle to install DiskInfo protocol.
6294 InitializeInstallDiskInfo (
6295 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
6296 IN EFI_HANDLE ChildHandle
6300 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
6301 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
6302 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
6303 SATA_DEVICE_PATH
*SataDevicePath
;
6304 UINTN IdentifyRetry
;
6306 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePathNode
);
6308 // Device Path protocol must be installed on the device handle.
6310 ASSERT_EFI_ERROR (Status
);
6312 // Copy the DiskInfo protocol template.
6314 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
6316 while (!IsDevicePathEnd (DevicePathNode
)) {
6317 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
6318 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
6319 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
6320 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
6321 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
6322 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
)))
6327 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
6328 // with IDE/AHCI interface GUID.
6330 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
6331 if (!EFI_ERROR (Status
)) {
6332 if (DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) {
6334 // We find the valid ATAPI device path
6336 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*)ChildDevicePathNode
;
6337 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
6338 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
6340 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
6342 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
6345 // We find the valid SATA device path
6347 SataDevicePath
= (SATA_DEVICE_PATH
*)ChildDevicePathNode
;
6348 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
6349 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
6351 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
6353 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
6358 } while (--IdentifyRetry
> 0);
6359 } else if ((DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
6360 (DevicePathSubType (ChildDevicePathNode
) == MSG_UFS_DP
))
6362 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoUfsInterfaceGuid
);
6366 DevicePathNode
= ChildDevicePathNode
;