2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding
= {
13 ScsiDiskDriverBindingSupported
,
14 ScsiDiskDriverBindingStart
,
15 ScsiDiskDriverBindingStop
,
21 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate
= {
22 EFI_DISK_INFO_SCSI_INTERFACE_GUID
,
25 ScsiDiskInfoSenseData
,
30 Allocates an aligned buffer for SCSI disk.
32 This function allocates an aligned buffer for the SCSI disk to perform
33 SCSI IO operations. The alignment requirement is from SCSI IO interface.
35 @param ScsiDiskDevice The SCSI disk involved for the operation.
36 @param BufferSize The request buffer size.
38 @return A pointer to the aligned buffer or NULL if the allocation fails.
42 AllocateAlignedBuffer (
43 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
47 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), ScsiDiskDevice
->ScsiIo
->IoAlign
);
51 Frees an aligned buffer for SCSI disk.
53 This function frees an aligned buffer for the SCSI disk to perform
56 @param Buffer The aligned buffer to be freed.
57 @param BufferSize The request buffer size.
67 FreeAlignedPages (Buffer
, EFI_SIZE_TO_PAGES (BufferSize
));
72 The user Entry Point for module ScsiDisk.
74 The user code starts with this function.
76 @param ImageHandle The firmware allocated handle for the EFI image.
77 @param SystemTable A pointer to the EFI System Table.
79 @retval EFI_SUCCESS The entry point is executed successfully.
80 @retval other Some error occurs when executing this entry point.
86 IN EFI_HANDLE ImageHandle
,
87 IN EFI_SYSTEM_TABLE
*SystemTable
93 // Install driver model protocol(s).
95 Status
= EfiLibInstallDriverBindingComponentName2 (
98 &gScsiDiskDriverBinding
,
100 &gScsiDiskComponentName
,
101 &gScsiDiskComponentName2
103 ASSERT_EFI_ERROR (Status
);
110 Test to see if this driver supports ControllerHandle.
112 This service is called by the EFI boot service ConnectController(). In order
113 to make drivers as small as possible, there are a few calling restrictions for
114 this service. ConnectController() must follow these calling restrictions.
115 If any other agent wishes to call Supported() it must also follow these
116 calling restrictions.
118 @param This Protocol instance pointer.
119 @param ControllerHandle Handle of device to test
120 @param RemainingDevicePath Optional parameter use to pick a specific child
123 @retval EFI_SUCCESS This driver supports this device
124 @retval EFI_ALREADY_STARTED This driver is already running on this device
125 @retval other This driver does not support this device
130 ScsiDiskDriverBindingSupported (
131 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
132 IN EFI_HANDLE Controller
,
133 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
137 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
140 Status
= gBS
->OpenProtocol (
142 &gEfiScsiIoProtocolGuid
,
144 This
->DriverBindingHandle
,
146 EFI_OPEN_PROTOCOL_BY_DRIVER
148 if (EFI_ERROR (Status
)) {
152 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
153 if (!EFI_ERROR (Status
)) {
154 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) || (DeviceType
== EFI_SCSI_TYPE_CDROM
)) {
155 Status
= EFI_SUCCESS
;
157 Status
= EFI_UNSUPPORTED
;
163 &gEfiScsiIoProtocolGuid
,
164 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
->EraseBlock
.Revision
= EFI_ERASE_BLOCK_PROTOCOL_REVISION
;
242 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
= 1;
243 ScsiDiskDevice
->EraseBlock
.EraseBlocks
= ScsiDiskEraseBlocks
;
244 ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
= 1;
245 ScsiDiskDevice
->BlockLimitsVpdSupported
= FALSE
;
246 ScsiDiskDevice
->Handle
= Controller
;
247 InitializeListHead (&ScsiDiskDevice
->AsyncTaskQueue
);
249 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
250 switch (ScsiDiskDevice
->DeviceType
) {
251 case EFI_SCSI_TYPE_DISK
:
252 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
253 MustReadCapacity
= TRUE
;
256 case EFI_SCSI_TYPE_CDROM
:
257 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
258 ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
= TRUE
;
259 MustReadCapacity
= FALSE
;
263 // The Sense Data Array's initial size is 6
265 ScsiDiskDevice
->SenseDataNumber
= 6;
266 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
267 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
269 if (ScsiDiskDevice
->SenseData
== NULL
) {
272 &gEfiScsiIoProtocolGuid
,
273 This
->DriverBindingHandle
,
276 FreePool (ScsiDiskDevice
);
277 return EFI_OUT_OF_RESOURCES
;
281 // Retrieve device information
284 for (Index
= 0; Index
< MaxRetry
; Index
++) {
285 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
286 if (!EFI_ERROR (Status
)) {
291 FreePool (ScsiDiskDevice
->SenseData
);
294 &gEfiScsiIoProtocolGuid
,
295 This
->DriverBindingHandle
,
298 FreePool (ScsiDiskDevice
);
299 return EFI_DEVICE_ERROR
;
303 // The second parameter "TRUE" means must
304 // retrieve media capacity
306 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, MustReadCapacity
, &Temp
);
307 if (!EFI_ERROR (Status
)) {
309 // Determine if Block IO & Block IO2 should be produced on this controller
312 if (DetermineInstallBlockIo(Controller
)) {
313 InitializeInstallDiskInfo(ScsiDiskDevice
, Controller
);
314 Status
= gBS
->InstallMultipleProtocolInterfaces (
316 &gEfiBlockIoProtocolGuid
,
317 &ScsiDiskDevice
->BlkIo
,
318 &gEfiBlockIo2ProtocolGuid
,
319 &ScsiDiskDevice
->BlkIo2
,
320 &gEfiDiskInfoProtocolGuid
,
321 &ScsiDiskDevice
->DiskInfo
,
324 if (!EFI_ERROR(Status
)) {
325 if (DetermineInstallEraseBlock(ScsiDiskDevice
, Controller
)) {
326 Status
= gBS
->InstallProtocolInterface (
328 &gEfiEraseBlockProtocolGuid
,
329 EFI_NATIVE_INTERFACE
,
330 &ScsiDiskDevice
->EraseBlock
332 if (EFI_ERROR(Status
)) {
333 DEBUG ((EFI_D_ERROR
, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", Status
));
336 ScsiDiskDevice
->ControllerNameTable
= NULL
;
339 gScsiDiskComponentName
.SupportedLanguages
,
340 &ScsiDiskDevice
->ControllerNameTable
,
346 gScsiDiskComponentName2
.SupportedLanguages
,
347 &ScsiDiskDevice
->ControllerNameTable
,
356 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
357 gBS
->FreePool (ScsiDiskDevice
);
360 &gEfiScsiIoProtocolGuid
,
361 This
->DriverBindingHandle
,
370 Stop this driver on ControllerHandle.
372 This service is called by the EFI boot service DisconnectController().
373 In order to make drivers as small as possible, there are a few calling
374 restrictions for this service. DisconnectController() must follow these
375 calling restrictions. If any other agent wishes to call Stop() it must
376 also follow these calling restrictions.
378 @param This Protocol instance pointer.
379 @param ControllerHandle Handle of device to stop driver on
380 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
381 children is zero stop the entire bus driver.
382 @param ChildHandleBuffer List of Child Handles to Stop.
384 @retval EFI_SUCCESS This driver is removed ControllerHandle
385 @retval other This driver was not removed from this device
390 ScsiDiskDriverBindingStop (
391 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
392 IN EFI_HANDLE Controller
,
393 IN UINTN NumberOfChildren
,
394 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
397 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
398 EFI_ERASE_BLOCK_PROTOCOL
*EraseBlock
;
399 SCSI_DISK_DEV
*ScsiDiskDevice
;
402 Status
= gBS
->OpenProtocol (
404 &gEfiBlockIoProtocolGuid
,
406 This
->DriverBindingHandle
,
408 EFI_OPEN_PROTOCOL_GET_PROTOCOL
410 if (EFI_ERROR (Status
)) {
414 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (BlkIo
);
417 // Wait for the BlockIo2 requests queue to become empty
419 while (!IsListEmpty (&ScsiDiskDevice
->AsyncTaskQueue
));
422 // If Erase Block Protocol is installed, then uninstall this protocol.
424 Status
= gBS
->OpenProtocol (
426 &gEfiEraseBlockProtocolGuid
,
427 (VOID
**) &EraseBlock
,
428 This
->DriverBindingHandle
,
430 EFI_OPEN_PROTOCOL_GET_PROTOCOL
433 if (!EFI_ERROR (Status
)) {
434 Status
= gBS
->UninstallProtocolInterface (
436 &gEfiEraseBlockProtocolGuid
,
437 &ScsiDiskDevice
->EraseBlock
439 if (EFI_ERROR (Status
)) {
444 Status
= gBS
->UninstallMultipleProtocolInterfaces (
446 &gEfiBlockIoProtocolGuid
,
447 &ScsiDiskDevice
->BlkIo
,
448 &gEfiBlockIo2ProtocolGuid
,
449 &ScsiDiskDevice
->BlkIo2
,
450 &gEfiDiskInfoProtocolGuid
,
451 &ScsiDiskDevice
->DiskInfo
,
454 if (!EFI_ERROR (Status
)) {
457 &gEfiScsiIoProtocolGuid
,
458 This
->DriverBindingHandle
,
462 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
476 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
477 @param ExtendedVerification The flag about if extend verificate
479 @retval EFI_SUCCESS The device was reset.
480 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
482 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
488 IN EFI_BLOCK_IO_PROTOCOL
*This
,
489 IN BOOLEAN ExtendedVerification
493 SCSI_DISK_DEV
*ScsiDiskDevice
;
496 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
498 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
500 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
502 if (EFI_ERROR (Status
)) {
503 if (Status
== EFI_UNSUPPORTED
) {
504 Status
= EFI_SUCCESS
;
506 Status
= EFI_DEVICE_ERROR
;
511 if (!ExtendedVerification
) {
515 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
517 if (EFI_ERROR (Status
)) {
518 Status
= EFI_DEVICE_ERROR
;
523 gBS
->RestoreTPL (OldTpl
);
528 The function is to Read Block from SCSI Disk.
530 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
531 @param MediaId The Id of Media detected
532 @param Lba The logic block address
533 @param BufferSize The size of Buffer
534 @param Buffer The buffer to fill the read out data
536 @retval EFI_SUCCESS Successfully to read out block.
537 @retval EFI_DEVICE_ERROR Fail to detect media.
538 @retval EFI_NO_MEDIA Media is not present.
539 @retval EFI_MEDIA_CHANGED Media has changed.
540 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
541 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
547 IN EFI_BLOCK_IO_PROTOCOL
*This
,
554 SCSI_DISK_DEV
*ScsiDiskDevice
;
555 EFI_BLOCK_IO_MEDIA
*Media
;
558 UINTN NumberOfBlocks
;
563 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
564 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
565 Media
= ScsiDiskDevice
->BlkIo
.Media
;
567 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
569 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
570 if (EFI_ERROR (Status
)) {
571 Status
= EFI_DEVICE_ERROR
;
576 gBS
->ReinstallProtocolInterface (
577 ScsiDiskDevice
->Handle
,
578 &gEfiBlockIoProtocolGuid
,
579 &ScsiDiskDevice
->BlkIo
,
580 &ScsiDiskDevice
->BlkIo
582 gBS
->ReinstallProtocolInterface (
583 ScsiDiskDevice
->Handle
,
584 &gEfiBlockIo2ProtocolGuid
,
585 &ScsiDiskDevice
->BlkIo2
,
586 &ScsiDiskDevice
->BlkIo2
588 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
589 gBS
->ReinstallProtocolInterface (
590 ScsiDiskDevice
->Handle
,
591 &gEfiEraseBlockProtocolGuid
,
592 &ScsiDiskDevice
->EraseBlock
,
593 &ScsiDiskDevice
->EraseBlock
596 if (Media
->MediaPresent
) {
597 Status
= EFI_MEDIA_CHANGED
;
599 Status
= EFI_NO_MEDIA
;
605 // Get the intrinsic block size
607 BlockSize
= Media
->BlockSize
;
609 NumberOfBlocks
= BufferSize
/ BlockSize
;
611 if (!(Media
->MediaPresent
)) {
612 Status
= EFI_NO_MEDIA
;
616 if (MediaId
!= Media
->MediaId
) {
617 Status
= EFI_MEDIA_CHANGED
;
621 if (Buffer
== NULL
) {
622 Status
= EFI_INVALID_PARAMETER
;
626 if (BufferSize
== 0) {
627 Status
= EFI_SUCCESS
;
631 if (BufferSize
% BlockSize
!= 0) {
632 Status
= EFI_BAD_BUFFER_SIZE
;
636 if (Lba
> Media
->LastBlock
) {
637 Status
= EFI_INVALID_PARAMETER
;
641 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
642 Status
= EFI_INVALID_PARAMETER
;
646 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
647 Status
= EFI_INVALID_PARAMETER
;
652 // If all the parameters are valid, then perform read sectors command
653 // to transfer data from device to host.
655 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
658 gBS
->RestoreTPL (OldTpl
);
663 The function is to Write Block to SCSI Disk.
665 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
666 @param MediaId The Id of Media detected
667 @param Lba The logic block address
668 @param BufferSize The size of Buffer
669 @param Buffer The buffer to fill the read out data
671 @retval EFI_SUCCESS Successfully to read out block.
672 @retval EFI_WRITE_PROTECTED The device can not be written to.
673 @retval EFI_DEVICE_ERROR Fail to detect media.
674 @retval EFI_NO_MEDIA Media is not present.
675 @retval EFI_MEDIA_CHNAGED Media has changed.
676 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
677 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
682 ScsiDiskWriteBlocks (
683 IN EFI_BLOCK_IO_PROTOCOL
*This
,
690 SCSI_DISK_DEV
*ScsiDiskDevice
;
691 EFI_BLOCK_IO_MEDIA
*Media
;
694 UINTN NumberOfBlocks
;
699 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
700 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
701 Media
= ScsiDiskDevice
->BlkIo
.Media
;
703 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
705 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
706 if (EFI_ERROR (Status
)) {
707 Status
= EFI_DEVICE_ERROR
;
712 gBS
->ReinstallProtocolInterface (
713 ScsiDiskDevice
->Handle
,
714 &gEfiBlockIoProtocolGuid
,
715 &ScsiDiskDevice
->BlkIo
,
716 &ScsiDiskDevice
->BlkIo
718 gBS
->ReinstallProtocolInterface (
719 ScsiDiskDevice
->Handle
,
720 &gEfiBlockIo2ProtocolGuid
,
721 &ScsiDiskDevice
->BlkIo2
,
722 &ScsiDiskDevice
->BlkIo2
724 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
725 gBS
->ReinstallProtocolInterface (
726 ScsiDiskDevice
->Handle
,
727 &gEfiEraseBlockProtocolGuid
,
728 &ScsiDiskDevice
->EraseBlock
,
729 &ScsiDiskDevice
->EraseBlock
732 if (Media
->MediaPresent
) {
733 Status
= EFI_MEDIA_CHANGED
;
735 Status
= EFI_NO_MEDIA
;
741 // Get the intrinsic block size
743 BlockSize
= Media
->BlockSize
;
745 NumberOfBlocks
= BufferSize
/ BlockSize
;
747 if (!(Media
->MediaPresent
)) {
748 Status
= EFI_NO_MEDIA
;
752 if (MediaId
!= Media
->MediaId
) {
753 Status
= EFI_MEDIA_CHANGED
;
757 if (Media
->ReadOnly
) {
758 Status
= EFI_WRITE_PROTECTED
;
762 if (BufferSize
== 0) {
763 Status
= EFI_SUCCESS
;
767 if (Buffer
== NULL
) {
768 Status
= EFI_INVALID_PARAMETER
;
772 if (BufferSize
% BlockSize
!= 0) {
773 Status
= EFI_BAD_BUFFER_SIZE
;
777 if (Lba
> Media
->LastBlock
) {
778 Status
= EFI_INVALID_PARAMETER
;
782 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
783 Status
= EFI_INVALID_PARAMETER
;
787 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
788 Status
= EFI_INVALID_PARAMETER
;
792 // if all the parameters are valid, then perform read sectors command
793 // to transfer data from device to host.
795 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
798 gBS
->RestoreTPL (OldTpl
);
805 EFI_SUCCESS is returned directly.
807 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
809 @retval EFI_SUCCESS All outstanding data was written to the device
814 ScsiDiskFlushBlocks (
815 IN EFI_BLOCK_IO_PROTOCOL
*This
828 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
829 @param ExtendedVerification The flag about if extend verificate.
831 @retval EFI_SUCCESS The device was reset.
832 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
834 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
840 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
841 IN BOOLEAN ExtendedVerification
845 SCSI_DISK_DEV
*ScsiDiskDevice
;
848 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
850 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
852 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
854 if (EFI_ERROR (Status
)) {
855 if (Status
== EFI_UNSUPPORTED
) {
856 Status
= EFI_SUCCESS
;
858 Status
= EFI_DEVICE_ERROR
;
863 if (!ExtendedVerification
) {
867 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
869 if (EFI_ERROR (Status
)) {
870 Status
= EFI_DEVICE_ERROR
;
875 gBS
->RestoreTPL (OldTpl
);
880 The function is to Read Block from SCSI Disk.
882 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
883 @param MediaId The Id of Media detected.
884 @param Lba The logic block address.
885 @param Token A pointer to the token associated with the transaction.
886 @param BufferSize The size of Buffer.
887 @param Buffer The buffer to fill the read out data.
889 @retval EFI_SUCCESS The read request was queued if Token-> Event is
890 not NULL. The data was read correctly from the
891 device if theToken-> Event is NULL.
892 @retval EFI_DEVICE_ERROR The device reported an error while attempting
893 to perform the read operation.
894 @retval EFI_NO_MEDIA There is no media in the device.
895 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
896 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
897 the intrinsic block size of the device.
898 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
899 valid, or the buffer is not on proper
901 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
907 ScsiDiskReadBlocksEx (
908 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
911 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
916 SCSI_DISK_DEV
*ScsiDiskDevice
;
917 EFI_BLOCK_IO_MEDIA
*Media
;
920 UINTN NumberOfBlocks
;
925 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
926 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
927 Media
= ScsiDiskDevice
->BlkIo
.Media
;
929 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
931 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
932 if (EFI_ERROR (Status
)) {
933 Status
= EFI_DEVICE_ERROR
;
938 gBS
->ReinstallProtocolInterface (
939 ScsiDiskDevice
->Handle
,
940 &gEfiBlockIoProtocolGuid
,
941 &ScsiDiskDevice
->BlkIo
,
942 &ScsiDiskDevice
->BlkIo
944 gBS
->ReinstallProtocolInterface (
945 ScsiDiskDevice
->Handle
,
946 &gEfiBlockIo2ProtocolGuid
,
947 &ScsiDiskDevice
->BlkIo2
,
948 &ScsiDiskDevice
->BlkIo2
950 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
951 gBS
->ReinstallProtocolInterface (
952 ScsiDiskDevice
->Handle
,
953 &gEfiEraseBlockProtocolGuid
,
954 &ScsiDiskDevice
->EraseBlock
,
955 &ScsiDiskDevice
->EraseBlock
958 if (Media
->MediaPresent
) {
959 Status
= EFI_MEDIA_CHANGED
;
961 Status
= EFI_NO_MEDIA
;
967 // Get the intrinsic block size
969 BlockSize
= Media
->BlockSize
;
971 NumberOfBlocks
= BufferSize
/ BlockSize
;
973 if (!(Media
->MediaPresent
)) {
974 Status
= EFI_NO_MEDIA
;
978 if (MediaId
!= Media
->MediaId
) {
979 Status
= EFI_MEDIA_CHANGED
;
983 if (Buffer
== NULL
) {
984 Status
= EFI_INVALID_PARAMETER
;
988 if (BufferSize
== 0) {
989 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
990 Token
->TransactionStatus
= EFI_SUCCESS
;
991 gBS
->SignalEvent (Token
->Event
);
994 Status
= EFI_SUCCESS
;
998 if (BufferSize
% BlockSize
!= 0) {
999 Status
= EFI_BAD_BUFFER_SIZE
;
1003 if (Lba
> Media
->LastBlock
) {
1004 Status
= EFI_INVALID_PARAMETER
;
1008 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1009 Status
= EFI_INVALID_PARAMETER
;
1013 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1014 Status
= EFI_INVALID_PARAMETER
;
1019 // If all the parameters are valid, then perform read sectors command
1020 // to transfer data from device to host.
1022 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1023 Token
->TransactionStatus
= EFI_SUCCESS
;
1024 Status
= ScsiDiskAsyncReadSectors (
1032 Status
= ScsiDiskReadSectors (
1041 gBS
->RestoreTPL (OldTpl
);
1046 The function is to Write Block to SCSI Disk.
1048 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
1049 @param MediaId The Id of Media detected.
1050 @param Lba The logic block address.
1051 @param Token A pointer to the token associated with the transaction.
1052 @param BufferSize The size of Buffer.
1053 @param Buffer The buffer to fill the read out data.
1055 @retval EFI_SUCCESS The data were written correctly to the device.
1056 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1057 @retval EFI_NO_MEDIA There is no media in the device.
1058 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1059 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1060 to perform the write operation.
1061 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
1062 the intrinsic block size of the device.
1063 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
1064 valid, or the buffer is not on proper
1070 ScsiDiskWriteBlocksEx (
1071 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1074 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1075 IN UINTN BufferSize
,
1079 SCSI_DISK_DEV
*ScsiDiskDevice
;
1080 EFI_BLOCK_IO_MEDIA
*Media
;
1083 UINTN NumberOfBlocks
;
1084 BOOLEAN MediaChange
;
1087 MediaChange
= FALSE
;
1088 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1089 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1090 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1092 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1094 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1095 if (EFI_ERROR (Status
)) {
1096 Status
= EFI_DEVICE_ERROR
;
1101 gBS
->ReinstallProtocolInterface (
1102 ScsiDiskDevice
->Handle
,
1103 &gEfiBlockIoProtocolGuid
,
1104 &ScsiDiskDevice
->BlkIo
,
1105 &ScsiDiskDevice
->BlkIo
1107 gBS
->ReinstallProtocolInterface (
1108 ScsiDiskDevice
->Handle
,
1109 &gEfiBlockIo2ProtocolGuid
,
1110 &ScsiDiskDevice
->BlkIo2
,
1111 &ScsiDiskDevice
->BlkIo2
1113 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1114 gBS
->ReinstallProtocolInterface (
1115 ScsiDiskDevice
->Handle
,
1116 &gEfiEraseBlockProtocolGuid
,
1117 &ScsiDiskDevice
->EraseBlock
,
1118 &ScsiDiskDevice
->EraseBlock
1121 if (Media
->MediaPresent
) {
1122 Status
= EFI_MEDIA_CHANGED
;
1124 Status
= EFI_NO_MEDIA
;
1130 // Get the intrinsic block size
1132 BlockSize
= Media
->BlockSize
;
1134 NumberOfBlocks
= BufferSize
/ BlockSize
;
1136 if (!(Media
->MediaPresent
)) {
1137 Status
= EFI_NO_MEDIA
;
1141 if (MediaId
!= Media
->MediaId
) {
1142 Status
= EFI_MEDIA_CHANGED
;
1146 if (Media
->ReadOnly
) {
1147 Status
= EFI_WRITE_PROTECTED
;
1151 if (BufferSize
== 0) {
1152 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1153 Token
->TransactionStatus
= EFI_SUCCESS
;
1154 gBS
->SignalEvent (Token
->Event
);
1157 Status
= EFI_SUCCESS
;
1161 if (Buffer
== NULL
) {
1162 Status
= EFI_INVALID_PARAMETER
;
1166 if (BufferSize
% BlockSize
!= 0) {
1167 Status
= EFI_BAD_BUFFER_SIZE
;
1171 if (Lba
> Media
->LastBlock
) {
1172 Status
= EFI_INVALID_PARAMETER
;
1176 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1177 Status
= EFI_INVALID_PARAMETER
;
1181 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1182 Status
= EFI_INVALID_PARAMETER
;
1187 // if all the parameters are valid, then perform write sectors command
1188 // to transfer data from device to host.
1190 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1191 Token
->TransactionStatus
= EFI_SUCCESS
;
1192 Status
= ScsiDiskAsyncWriteSectors (
1200 Status
= ScsiDiskWriteSectors (
1209 gBS
->RestoreTPL (OldTpl
);
1214 Flush the Block Device.
1216 @param This Indicates a pointer to the calling context.
1217 @param Token A pointer to the token associated with the transaction.
1219 @retval EFI_SUCCESS All outstanding data was written to the device.
1220 @retval EFI_DEVICE_ERROR The device reported an error while attempting to
1222 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1223 @retval EFI_NO_MEDIA There is no media in the device.
1224 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1229 ScsiDiskFlushBlocksEx (
1230 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1231 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1234 SCSI_DISK_DEV
*ScsiDiskDevice
;
1235 EFI_BLOCK_IO_MEDIA
*Media
;
1237 BOOLEAN MediaChange
;
1240 MediaChange
= FALSE
;
1241 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1242 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1243 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1245 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1247 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1248 if (EFI_ERROR (Status
)) {
1249 Status
= EFI_DEVICE_ERROR
;
1254 gBS
->ReinstallProtocolInterface (
1255 ScsiDiskDevice
->Handle
,
1256 &gEfiBlockIoProtocolGuid
,
1257 &ScsiDiskDevice
->BlkIo
,
1258 &ScsiDiskDevice
->BlkIo
1260 gBS
->ReinstallProtocolInterface (
1261 ScsiDiskDevice
->Handle
,
1262 &gEfiBlockIo2ProtocolGuid
,
1263 &ScsiDiskDevice
->BlkIo2
,
1264 &ScsiDiskDevice
->BlkIo2
1266 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1267 gBS
->ReinstallProtocolInterface (
1268 ScsiDiskDevice
->Handle
,
1269 &gEfiEraseBlockProtocolGuid
,
1270 &ScsiDiskDevice
->EraseBlock
,
1271 &ScsiDiskDevice
->EraseBlock
1274 if (Media
->MediaPresent
) {
1275 Status
= EFI_MEDIA_CHANGED
;
1277 Status
= EFI_NO_MEDIA
;
1283 if (!(Media
->MediaPresent
)) {
1284 Status
= EFI_NO_MEDIA
;
1288 if (Media
->ReadOnly
) {
1289 Status
= EFI_WRITE_PROTECTED
;
1294 // Wait for the BlockIo2 requests queue to become empty
1296 while (!IsListEmpty (&ScsiDiskDevice
->AsyncTaskQueue
));
1298 Status
= EFI_SUCCESS
;
1301 // Signal caller event
1303 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1304 Token
->TransactionStatus
= EFI_SUCCESS
;
1305 gBS
->SignalEvent (Token
->Event
);
1309 gBS
->RestoreTPL (OldTpl
);
1315 Internal helper notify function which process the result of an asynchronous
1316 SCSI UNMAP Command and signal the event passed from EraseBlocks.
1318 @param Event The instance of EFI_EVENT.
1319 @param Context The parameter passed in.
1324 ScsiDiskAsyncUnmapNotify (
1329 SCSI_ERASEBLK_REQUEST
*EraseBlkReq
;
1330 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*CommandPacket
;
1331 EFI_ERASE_BLOCK_TOKEN
*Token
;
1334 gBS
->CloseEvent (Event
);
1336 EraseBlkReq
= (SCSI_ERASEBLK_REQUEST
*) Context
;
1337 CommandPacket
= &EraseBlkReq
->CommandPacket
;
1338 Token
= EraseBlkReq
->Token
;
1339 Token
->TransactionStatus
= EFI_SUCCESS
;
1341 Status
= CheckHostAdapterStatus (CommandPacket
->HostAdapterStatus
);
1342 if (EFI_ERROR(Status
)) {
1345 "ScsiDiskAsyncUnmapNotify: Host adapter indicating error status 0x%x.\n",
1346 CommandPacket
->HostAdapterStatus
1349 Token
->TransactionStatus
= Status
;
1353 Status
= CheckTargetStatus (CommandPacket
->TargetStatus
);
1354 if (EFI_ERROR(Status
)) {
1357 "ScsiDiskAsyncUnmapNotify: Target indicating error status 0x%x.\n",
1358 CommandPacket
->HostAdapterStatus
1361 Token
->TransactionStatus
= Status
;
1366 RemoveEntryList (&EraseBlkReq
->Link
);
1367 FreePool (CommandPacket
->OutDataBuffer
);
1368 FreePool (EraseBlkReq
->CommandPacket
.Cdb
);
1369 FreePool (EraseBlkReq
);
1371 gBS
->SignalEvent (Token
->Event
);
1375 Require the device server to cause one or more LBAs to be unmapped.
1377 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
1378 @param Lba The start block number.
1379 @param Blocks Total block number to be unmapped.
1380 @param Token The pointer to the token associated with the
1381 non-blocking erase block request.
1383 @retval EFI_SUCCESS Target blocks have been successfully unmapped.
1384 @retval EFI_DEVICE_ERROR Fail to unmap the target blocks.
1389 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1392 IN EFI_ERASE_BLOCK_TOKEN
*Token OPTIONAL
1395 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
1396 SCSI_ERASEBLK_REQUEST
*EraseBlkReq
;
1397 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*CommandPacket
;
1398 EFI_SCSI_DISK_UNMAP_BLOCK_DESP
*BlkDespPtr
;
1400 EFI_STATUS ReturnStatus
;
1403 UINT32 MaxBlkDespCnt
;
1405 UINT16 UnmapParamListLen
;
1406 VOID
*UnmapParamList
;
1407 EFI_EVENT AsyncUnmapEvent
;
1410 ScsiIo
= ScsiDiskDevice
->ScsiIo
;
1411 MaxLbaCnt
= ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
;
1412 MaxBlkDespCnt
= ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
;
1414 UnmapParamList
= NULL
;
1415 AsyncUnmapEvent
= NULL
;
1416 ReturnStatus
= EFI_SUCCESS
;
1418 if (Blocks
/ (UINTN
) MaxLbaCnt
> MaxBlkDespCnt
) {
1419 ReturnStatus
= EFI_DEVICE_ERROR
;
1423 EraseBlkReq
= AllocateZeroPool (sizeof (SCSI_ERASEBLK_REQUEST
));
1424 if (EraseBlkReq
== NULL
) {
1425 ReturnStatus
= EFI_DEVICE_ERROR
;
1429 EraseBlkReq
->CommandPacket
.Cdb
= AllocateZeroPool (0xA);
1430 if (EraseBlkReq
->CommandPacket
.Cdb
== NULL
) {
1431 ReturnStatus
= EFI_DEVICE_ERROR
;
1435 BlkDespCnt
= (UINT32
) ((Blocks
- 1) / MaxLbaCnt
+ 1);
1436 UnmapParamListLen
= (UINT16
) (sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
)
1437 + BlkDespCnt
* sizeof (EFI_SCSI_DISK_UNMAP_BLOCK_DESP
));
1438 UnmapParamList
= AllocateZeroPool (UnmapParamListLen
);
1439 if (UnmapParamList
== NULL
) {
1440 ReturnStatus
= EFI_DEVICE_ERROR
;
1444 *((UINT16
*)UnmapParamList
) = SwapBytes16 (UnmapParamListLen
- 2);
1445 *((UINT16
*)UnmapParamList
+ 1) = SwapBytes16 (UnmapParamListLen
- sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
));
1447 BlkDespPtr
= (EFI_SCSI_DISK_UNMAP_BLOCK_DESP
*)((UINT8
*)UnmapParamList
+ sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
));
1448 while (Blocks
> 0) {
1449 if (Blocks
> MaxLbaCnt
) {
1450 *(UINT64
*)(&BlkDespPtr
->Lba
) = SwapBytes64 (Lba
);
1451 *(UINT32
*)(&BlkDespPtr
->BlockNum
) = SwapBytes32 (MaxLbaCnt
);
1452 Blocks
-= MaxLbaCnt
;
1455 *(UINT64
*)(&BlkDespPtr
->Lba
) = SwapBytes64 (Lba
);
1456 *(UINT32
*)(&BlkDespPtr
->BlockNum
) = SwapBytes32 ((UINT32
) Blocks
);
1463 CommandPacket
= &EraseBlkReq
->CommandPacket
;
1464 CommandPacket
->Timeout
= SCSI_DISK_TIMEOUT
;
1465 CommandPacket
->OutDataBuffer
= UnmapParamList
;
1466 CommandPacket
->OutTransferLength
= UnmapParamListLen
;
1467 CommandPacket
->CdbLength
= 0xA;
1468 CommandPacket
->DataDirection
= EFI_SCSI_DATA_OUT
;
1470 // Fill Cdb for UNMAP Command
1472 Cdb
= CommandPacket
->Cdb
;
1473 Cdb
[0] = EFI_SCSI_OP_UNMAP
;
1474 WriteUnaligned16 ((UINT16
*)&Cdb
[7], SwapBytes16 (UnmapParamListLen
));
1476 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1478 // Non-blocking UNMAP request
1480 Status
= gBS
->CreateEvent (
1483 ScsiDiskAsyncUnmapNotify
,
1487 if (EFI_ERROR(Status
)) {
1488 ReturnStatus
= EFI_DEVICE_ERROR
;
1492 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1493 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &EraseBlkReq
->Link
);
1494 gBS
->RestoreTPL (OldTpl
);
1496 EraseBlkReq
->Token
= Token
;
1498 Status
= ScsiIo
->ExecuteScsiCommand (
1503 if (EFI_ERROR(Status
)) {
1504 ReturnStatus
= EFI_DEVICE_ERROR
;
1506 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1507 RemoveEntryList (&EraseBlkReq
->Link
);
1508 gBS
->RestoreTPL (OldTpl
);
1513 // Directly return if the non-blocking UNMAP request is queued.
1519 // Blocking UNMAP request
1521 Status
= ScsiIo
->ExecuteScsiCommand (
1526 if (EFI_ERROR(Status
)) {
1527 ReturnStatus
= EFI_DEVICE_ERROR
;
1533 // Only blocking UNMAP request will reach here.
1535 Status
= CheckHostAdapterStatus (CommandPacket
->HostAdapterStatus
);
1536 if (EFI_ERROR(Status
)) {
1539 "ScsiDiskUnmap: Host adapter indicating error status 0x%x.\n",
1540 CommandPacket
->HostAdapterStatus
1543 ReturnStatus
= EFI_DEVICE_ERROR
;
1547 Status
= CheckTargetStatus (CommandPacket
->TargetStatus
);
1548 if (EFI_ERROR(Status
)) {
1551 "ScsiDiskUnmap: Target indicating error status 0x%x.\n",
1552 CommandPacket
->HostAdapterStatus
1555 ReturnStatus
= EFI_DEVICE_ERROR
;
1560 if (EraseBlkReq
!= NULL
) {
1561 if (EraseBlkReq
->CommandPacket
.Cdb
!= NULL
) {
1562 FreePool (EraseBlkReq
->CommandPacket
.Cdb
);
1564 FreePool (EraseBlkReq
);
1567 if (UnmapParamList
!= NULL
) {
1568 FreePool (UnmapParamList
);
1571 if (AsyncUnmapEvent
!= NULL
) {
1572 gBS
->CloseEvent (AsyncUnmapEvent
);
1575 return ReturnStatus
;
1579 Erase a specified number of device blocks.
1581 @param[in] This Indicates a pointer to the calling context.
1582 @param[in] MediaId The media ID that the erase request is for.
1583 @param[in] Lba The starting logical block address to be
1584 erased. The caller is responsible for erasing
1585 only legitimate locations.
1586 @param[in, out] Token A pointer to the token associated with the
1588 @param[in] Size The size in bytes to be erased. This must be
1589 a multiple of the physical block size of the
1592 @retval EFI_SUCCESS The erase request was queued if Event is not
1593 NULL. The data was erased correctly to the
1594 device if the Event is NULL.to the device.
1595 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
1597 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1598 to perform the erase operation.
1599 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
1601 @retval EFI_NO_MEDIA There is no media in the device.
1602 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1607 ScsiDiskEraseBlocks (
1608 IN EFI_ERASE_BLOCK_PROTOCOL
*This
,
1611 IN OUT EFI_ERASE_BLOCK_TOKEN
*Token
,
1615 SCSI_DISK_DEV
*ScsiDiskDevice
;
1616 EFI_BLOCK_IO_MEDIA
*Media
;
1619 UINTN NumberOfBlocks
;
1620 BOOLEAN MediaChange
;
1623 MediaChange
= FALSE
;
1624 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1625 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_ERASEBLK (This
);
1627 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1628 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1629 if (EFI_ERROR (Status
)) {
1630 Status
= EFI_DEVICE_ERROR
;
1635 gBS
->ReinstallProtocolInterface (
1636 ScsiDiskDevice
->Handle
,
1637 &gEfiBlockIoProtocolGuid
,
1638 &ScsiDiskDevice
->BlkIo
,
1639 &ScsiDiskDevice
->BlkIo
1641 gBS
->ReinstallProtocolInterface (
1642 ScsiDiskDevice
->Handle
,
1643 &gEfiBlockIo2ProtocolGuid
,
1644 &ScsiDiskDevice
->BlkIo2
,
1645 &ScsiDiskDevice
->BlkIo2
1647 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1648 gBS
->ReinstallProtocolInterface (
1649 ScsiDiskDevice
->Handle
,
1650 &gEfiEraseBlockProtocolGuid
,
1651 &ScsiDiskDevice
->EraseBlock
,
1652 &ScsiDiskDevice
->EraseBlock
1655 Status
= EFI_MEDIA_CHANGED
;
1660 // Get the intrinsic block size
1662 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1664 if (!(Media
->MediaPresent
)) {
1665 Status
= EFI_NO_MEDIA
;
1669 if (MediaId
!= Media
->MediaId
) {
1670 Status
= EFI_MEDIA_CHANGED
;
1674 if (Media
->ReadOnly
) {
1675 Status
= EFI_WRITE_PROTECTED
;
1680 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1681 Token
->TransactionStatus
= EFI_SUCCESS
;
1682 gBS
->SignalEvent (Token
->Event
);
1684 Status
= EFI_SUCCESS
;
1688 BlockSize
= Media
->BlockSize
;
1689 if ((Size
% BlockSize
) != 0) {
1690 Status
= EFI_INVALID_PARAMETER
;
1694 NumberOfBlocks
= Size
/ BlockSize
;
1695 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1696 Status
= EFI_INVALID_PARAMETER
;
1700 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1701 Status
= ScsiDiskUnmap (ScsiDiskDevice
, Lba
, NumberOfBlocks
, Token
);
1703 Status
= ScsiDiskUnmap (ScsiDiskDevice
, Lba
, NumberOfBlocks
, NULL
);
1707 gBS
->RestoreTPL (OldTpl
);
1713 Detect Device and read out capacity ,if error occurs, parse the sense key.
1715 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1716 @param MustReadCapacity The flag about reading device capacity
1717 @param MediaChange The pointer of flag indicates if media has changed
1719 @retval EFI_DEVICE_ERROR Indicates that error occurs
1720 @retval EFI_SUCCESS Successfully to detect media
1724 ScsiDiskDetectMedia (
1725 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1726 IN BOOLEAN MustReadCapacity
,
1727 OUT BOOLEAN
*MediaChange
1731 EFI_SCSI_SENSE_DATA
*SenseData
;
1732 UINTN NumberOfSenseKeys
;
1734 BOOLEAN NeedReadCapacity
;
1737 EFI_BLOCK_IO_MEDIA OldMedia
;
1739 EFI_EVENT TimeoutEvt
;
1741 Status
= EFI_SUCCESS
;
1743 NumberOfSenseKeys
= 0;
1746 Action
= ACTION_NO_ACTION
;
1747 NeedReadCapacity
= FALSE
;
1748 *MediaChange
= FALSE
;
1751 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
1753 Status
= gBS
->CreateEvent (
1760 if (EFI_ERROR (Status
)) {
1764 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
1765 if (EFI_ERROR (Status
)) {
1770 // Sending Test_Unit cmd to poll device status.
1771 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
1772 // We limit the upper boundary to 120 seconds.
1774 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
1775 Status
= ScsiDiskTestUnitReady (
1781 if (!EFI_ERROR (Status
)) {
1782 Status
= DetectMediaParsingSenseKeys (
1788 if (EFI_ERROR (Status
)) {
1790 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1797 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1803 if (EFI_ERROR (Status
)) {
1808 // ACTION_NO_ACTION: need not read capacity
1809 // other action code: need read capacity
1811 if (Action
== ACTION_READ_CAPACITY
) {
1812 NeedReadCapacity
= TRUE
;
1816 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
1817 // retrieve capacity via Read Capacity command
1819 if (NeedReadCapacity
|| MustReadCapacity
) {
1821 // retrieve media information
1823 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
1824 Status
= ScsiDiskReadCapacity (
1830 if (!EFI_ERROR (Status
)) {
1832 // analyze sense key to action
1834 Status
= DetectMediaParsingSenseKeys (
1840 if (EFI_ERROR (Status
)) {
1842 // if Status is error, it may indicate crisis error,
1843 // so return without retry.
1846 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1854 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1860 if (EFI_ERROR (Status
)) {
1865 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
1867 // Media change information got from the device
1869 *MediaChange
= TRUE
;
1872 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
1873 *MediaChange
= TRUE
;
1874 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1877 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
1878 *MediaChange
= TRUE
;
1879 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1882 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
1883 *MediaChange
= TRUE
;
1884 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1887 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
1888 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
1890 // when change from no media to media present, reset the MediaId to 1.
1892 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
1895 // when no media, reset the MediaId to zero.
1897 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
1900 *MediaChange
= TRUE
;
1904 if (TimeoutEvt
!= NULL
) {
1905 gBS
->CloseEvent (TimeoutEvt
);
1912 Send out Inquiry command to Device.
1914 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1915 @param NeedRetry Indicates if needs try again when error happens
1917 @retval EFI_DEVICE_ERROR Indicates that error occurs
1918 @retval EFI_SUCCESS Successfully to detect media
1922 ScsiDiskInquiryDevice (
1923 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1924 OUT BOOLEAN
*NeedRetry
1927 UINT32 InquiryDataLength
;
1928 UINT8 SenseDataLength
;
1929 UINT8 HostAdapterStatus
;
1931 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
1932 UINTN NumberOfSenseKeys
;
1936 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
1937 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
1940 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1941 SenseDataLength
= 0;
1943 Status
= ScsiInquiryCommand (
1944 ScsiDiskDevice
->ScsiIo
,
1950 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
1955 // no need to check HostAdapterStatus and TargetStatus
1957 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1958 ParseInquiryData (ScsiDiskDevice
);
1960 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1962 // Check whether the device supports Block Limits VPD page (0xB0)
1964 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1965 if (SupportedVpdPages
== NULL
) {
1967 return EFI_DEVICE_ERROR
;
1969 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1970 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
1971 SenseDataLength
= 0;
1972 Status
= ScsiInquiryCommandEx (
1973 ScsiDiskDevice
->ScsiIo
,
1979 (VOID
*) SupportedVpdPages
,
1982 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
1984 if (!EFI_ERROR (Status
)) {
1985 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
1986 | SupportedVpdPages
->PageLength1
;
1989 // Sanity checks for coping with broken devices
1991 if (PageLength
> sizeof SupportedVpdPages
->SupportedVpdPageList
) {
1993 "%a: invalid PageLength (%u) in Supported VPD Pages page\n",
1994 __FUNCTION__
, (UINT32
)PageLength
));
1998 if ((PageLength
> 0) &&
1999 (SupportedVpdPages
->SupportedVpdPageList
[0] !=
2000 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
)) {
2002 "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",
2003 __FUNCTION__
, EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
));
2008 // Locate the code for the Block Limits VPD page
2010 for (Index
= 0; Index
< PageLength
; Index
++) {
2015 (SupportedVpdPages
->SupportedVpdPageList
[Index
] <=
2016 SupportedVpdPages
->SupportedVpdPageList
[Index
- 1])) {
2018 "%a: non-ascending code in Supported VPD Pages page @ %u\n",
2019 __FUNCTION__
, Index
));
2025 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
2031 // Query the Block Limits VPD page
2033 if (Index
< PageLength
) {
2034 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2035 if (BlockLimits
== NULL
) {
2036 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2038 return EFI_DEVICE_ERROR
;
2040 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2041 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
2042 SenseDataLength
= 0;
2043 Status
= ScsiInquiryCommandEx (
2044 ScsiDiskDevice
->ScsiIo
,
2050 (VOID
*) BlockLimits
,
2053 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
2055 if (!EFI_ERROR (Status
)) {
2056 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
2057 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
2058 BlockLimits
->OptimalTransferLengthGranularity1
;
2060 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
=
2061 (BlockLimits
->MaximumUnmapLbaCount4
<< 24) |
2062 (BlockLimits
->MaximumUnmapLbaCount3
<< 16) |
2063 (BlockLimits
->MaximumUnmapLbaCount2
<< 8) |
2064 BlockLimits
->MaximumUnmapLbaCount1
;
2065 ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
=
2066 (BlockLimits
->MaximumUnmapBlockDescriptorCount4
<< 24) |
2067 (BlockLimits
->MaximumUnmapBlockDescriptorCount3
<< 16) |
2068 (BlockLimits
->MaximumUnmapBlockDescriptorCount2
<< 8) |
2069 BlockLimits
->MaximumUnmapBlockDescriptorCount1
;
2070 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
=
2071 (BlockLimits
->OptimalUnmapGranularity4
<< 24) |
2072 (BlockLimits
->OptimalUnmapGranularity3
<< 16) |
2073 (BlockLimits
->OptimalUnmapGranularity2
<< 8) |
2074 BlockLimits
->OptimalUnmapGranularity1
;
2075 if (BlockLimits
->UnmapGranularityAlignmentValid
!= 0) {
2076 ScsiDiskDevice
->UnmapInfo
.GranularityAlignment
=
2077 (BlockLimits
->UnmapGranularityAlignment4
<< 24) |
2078 (BlockLimits
->UnmapGranularityAlignment3
<< 16) |
2079 (BlockLimits
->UnmapGranularityAlignment2
<< 8) |
2080 BlockLimits
->UnmapGranularityAlignment1
;
2083 if (ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
== 0) {
2085 // A value of 0 indicates that the optimal unmap granularity is
2088 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
= 1;
2091 ScsiDiskDevice
->BlockLimitsVpdSupported
= TRUE
;
2094 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2098 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2102 if (!EFI_ERROR (Status
)) {
2105 } else if (Status
== EFI_NOT_READY
) {
2107 return EFI_DEVICE_ERROR
;
2109 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2111 return EFI_DEVICE_ERROR
;
2114 // go ahead to check HostAdapterStatus and TargetStatus
2115 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
2118 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2119 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2121 return EFI_DEVICE_ERROR
;
2122 } else if (Status
== EFI_DEVICE_ERROR
) {
2124 // reset the scsi channel
2126 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2128 return EFI_DEVICE_ERROR
;
2131 Status
= CheckTargetStatus (TargetStatus
);
2132 if (Status
== EFI_NOT_READY
) {
2134 // reset the scsi device
2136 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2138 return EFI_DEVICE_ERROR
;
2140 } else if (Status
== EFI_DEVICE_ERROR
) {
2142 return EFI_DEVICE_ERROR
;
2146 // if goes here, meant ScsiInquiryCommand() failed.
2147 // if ScsiDiskRequestSenseKeys() succeeds at last,
2148 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
2151 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2152 Status
= ScsiDiskRequestSenseKeys (
2159 if (!EFI_ERROR (Status
)) {
2161 return EFI_DEVICE_ERROR
;
2165 return EFI_DEVICE_ERROR
;
2169 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2170 // set *NeedRetry = FALSE to avoid the outside caller try again.
2173 return EFI_DEVICE_ERROR
;
2179 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
2180 When Test Unit Ready command encounters any error caused by host adapter or
2181 target, return error without retrieving Sense Keys.
2183 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2184 @param NeedRetry The pointer of flag indicates try again
2185 @param SenseDataArray The pointer of an array of sense data
2186 @param NumberOfSenseKeys The pointer of the number of sense data array
2188 @retval EFI_DEVICE_ERROR Indicates that error occurs
2189 @retval EFI_SUCCESS Successfully to test unit
2193 ScsiDiskTestUnitReady (
2194 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2195 OUT BOOLEAN
*NeedRetry
,
2196 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2197 OUT UINTN
*NumberOfSenseKeys
2201 UINT8 SenseDataLength
;
2202 UINT8 HostAdapterStatus
;
2207 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2208 *NumberOfSenseKeys
= 0;
2211 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
2213 Status
= ScsiTestUnitReadyCommand (
2214 ScsiDiskDevice
->ScsiIo
,
2216 ScsiDiskDevice
->SenseData
,
2222 // no need to check HostAdapterStatus and TargetStatus
2224 if (Status
== EFI_NOT_READY
) {
2226 return EFI_DEVICE_ERROR
;
2228 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2230 return EFI_DEVICE_ERROR
;
2233 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
2236 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2237 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2239 return EFI_DEVICE_ERROR
;
2241 } else if (Status
== EFI_DEVICE_ERROR
) {
2243 // reset the scsi channel
2245 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2247 return EFI_DEVICE_ERROR
;
2250 Status
= CheckTargetStatus (TargetStatus
);
2251 if (Status
== EFI_NOT_READY
) {
2253 // reset the scsi device
2255 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2257 return EFI_DEVICE_ERROR
;
2259 } else if (Status
== EFI_DEVICE_ERROR
) {
2261 return EFI_DEVICE_ERROR
;
2264 if (SenseDataLength
!= 0) {
2265 *NumberOfSenseKeys
= SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
);
2266 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2271 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2272 Status
= ScsiDiskRequestSenseKeys (
2279 if (!EFI_ERROR (Status
)) {
2284 return EFI_DEVICE_ERROR
;
2288 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2289 // set *NeedRetry = FALSE to avoid the outside caller try again.
2292 return EFI_DEVICE_ERROR
;
2296 Parsing Sense Keys which got from request sense command.
2298 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2299 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2300 @param NumberOfSenseKeys The number of sense key
2301 @param Action The pointer of action which indicates what is need to do next
2303 @retval EFI_DEVICE_ERROR Indicates that error occurs
2304 @retval EFI_SUCCESS Successfully to complete the parsing
2308 DetectMediaParsingSenseKeys (
2309 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2310 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2311 IN UINTN NumberOfSenseKeys
,
2318 // Default is to read capacity, unless..
2320 *Action
= ACTION_READ_CAPACITY
;
2322 if (NumberOfSenseKeys
== 0) {
2323 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
2324 *Action
= ACTION_NO_ACTION
;
2329 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
2331 // No Sense Key returned from last submitted command
2333 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
2334 *Action
= ACTION_NO_ACTION
;
2339 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
2340 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
2341 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
2342 *Action
= ACTION_NO_ACTION
;
2343 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
2347 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
2348 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
2349 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
2353 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
2354 *Action
= ACTION_RETRY_COMMAND_LATER
;
2355 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
2359 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
2360 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
2361 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2362 return EFI_DEVICE_ERROR
;
2365 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
2366 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
2367 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2368 return EFI_DEVICE_ERROR
;
2371 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
2373 *Action
= ACTION_RETRY_COMMAND_LATER
;
2374 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
2377 *Action
= ACTION_NO_ACTION
;
2378 return EFI_DEVICE_ERROR
;
2381 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2382 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
2388 Send read capacity command to device and get the device parameter.
2390 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2391 @param NeedRetry The pointer of flag indicates if need a retry
2392 @param SenseDataArray The pointer of an array of sense data
2393 @param NumberOfSenseKeys The number of sense key
2395 @retval EFI_DEVICE_ERROR Indicates that error occurs
2396 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
2400 ScsiDiskReadCapacity (
2401 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2402 OUT BOOLEAN
*NeedRetry
,
2403 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2404 OUT UINTN
*NumberOfSenseKeys
2407 UINT8 HostAdapterStatus
;
2409 EFI_STATUS CommandStatus
;
2413 UINT8 SenseDataLength
;
2414 UINT32 DataLength10
;
2415 UINT32 DataLength16
;
2416 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
2417 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
2419 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2420 if (CapacityData10
== NULL
) {
2422 return EFI_DEVICE_ERROR
;
2424 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2425 if (CapacityData16
== NULL
) {
2426 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2428 return EFI_DEVICE_ERROR
;
2431 SenseDataLength
= 0;
2432 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
2433 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
2434 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2435 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2437 *NumberOfSenseKeys
= 0;
2441 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
2442 // 16 byte command should be used to access large hard disk >2TB
2444 CommandStatus
= ScsiReadCapacityCommand (
2445 ScsiDiskDevice
->ScsiIo
,
2451 (VOID
*) CapacityData10
,
2456 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
2457 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
2458 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff)) {
2460 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
2462 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
2464 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
2465 // and LowestAlignedLba
2467 CommandStatus
= ScsiReadCapacity16Command (
2468 ScsiDiskDevice
->ScsiIo
,
2474 (VOID
*) CapacityData16
,
2481 // no need to check HostAdapterStatus and TargetStatus
2483 if (CommandStatus
== EFI_SUCCESS
) {
2484 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
2485 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2486 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2490 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2491 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2493 if (CommandStatus
== EFI_NOT_READY
) {
2495 return EFI_DEVICE_ERROR
;
2496 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
2498 return EFI_DEVICE_ERROR
;
2502 // go ahead to check HostAdapterStatus and TargetStatus
2503 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2506 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2507 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2509 return EFI_DEVICE_ERROR
;
2511 } else if (Status
== EFI_DEVICE_ERROR
) {
2513 // reset the scsi channel
2515 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2517 return EFI_DEVICE_ERROR
;
2520 Status
= CheckTargetStatus (TargetStatus
);
2521 if (Status
== EFI_NOT_READY
) {
2523 // reset the scsi device
2525 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2527 return EFI_DEVICE_ERROR
;
2529 } else if (Status
== EFI_DEVICE_ERROR
) {
2531 return EFI_DEVICE_ERROR
;
2535 // if goes here, meant ScsiReadCapacityCommand() failed.
2536 // if ScsiDiskRequestSenseKeys() succeeds at last,
2537 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
2540 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2542 Status
= ScsiDiskRequestSenseKeys (
2549 if (!EFI_ERROR (Status
)) {
2554 return EFI_DEVICE_ERROR
;
2558 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2559 // set *NeedRetry = FALSE to avoid the outside caller try again.
2562 return EFI_DEVICE_ERROR
;
2566 Check the HostAdapter status and re-interpret it in EFI_STATUS.
2568 @param HostAdapterStatus Host Adapter status
2570 @retval EFI_SUCCESS Host adapter is OK.
2571 @retval EFI_TIMEOUT Timeout.
2572 @retval EFI_NOT_READY Adapter NOT ready.
2573 @retval EFI_DEVICE_ERROR Adapter device error.
2577 CheckHostAdapterStatus (
2578 IN UINT8 HostAdapterStatus
2581 switch (HostAdapterStatus
) {
2582 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
2585 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
2586 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
2587 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
2590 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
2591 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
2592 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
2593 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
2594 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
2595 return EFI_NOT_READY
;
2597 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
2598 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
2599 return EFI_DEVICE_ERROR
;
2608 Check the target status and re-interpret it in EFI_STATUS.
2610 @param TargetStatus Target status
2612 @retval EFI_NOT_READY Device is NOT ready.
2613 @retval EFI_DEVICE_ERROR
2619 IN UINT8 TargetStatus
2622 switch (TargetStatus
) {
2623 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
2624 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
2625 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
2628 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
2629 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
2630 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
2631 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
2632 return EFI_NOT_READY
;
2634 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
2635 return EFI_DEVICE_ERROR
;
2644 Retrieve all sense keys from the device.
2646 When encountering error during the process, if retrieve sense keys before
2647 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
2648 and NeedRetry set to FALSE; otherwize, return the proper return status.
2650 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2651 @param NeedRetry The pointer of flag indicates if need a retry
2652 @param SenseDataArray The pointer of an array of sense data
2653 @param NumberOfSenseKeys The number of sense key
2654 @param AskResetIfError The flag indicates if need reset when error occurs
2656 @retval EFI_DEVICE_ERROR Indicates that error occurs
2657 @retval EFI_SUCCESS Successfully to request sense key
2661 ScsiDiskRequestSenseKeys (
2662 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2663 OUT BOOLEAN
*NeedRetry
,
2664 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2665 OUT UINTN
*NumberOfSenseKeys
,
2666 IN BOOLEAN AskResetIfError
2669 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
2670 UINT8 SenseDataLength
;
2673 EFI_STATUS FallStatus
;
2674 UINT8 HostAdapterStatus
;
2677 FallStatus
= EFI_SUCCESS
;
2678 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
2681 ScsiDiskDevice
->SenseData
,
2682 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
2685 *NumberOfSenseKeys
= 0;
2686 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2687 Status
= EFI_SUCCESS
;
2688 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
2689 if (PtrSenseData
== NULL
) {
2690 return EFI_DEVICE_ERROR
;
2693 for (SenseReq
= TRUE
; SenseReq
;) {
2694 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2695 Status
= ScsiRequestSenseCommand (
2696 ScsiDiskDevice
->ScsiIo
,
2703 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
2704 FallStatus
= EFI_SUCCESS
;
2706 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2708 FallStatus
= EFI_DEVICE_ERROR
;
2710 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2712 FallStatus
= EFI_DEVICE_ERROR
;
2714 } else if (Status
== EFI_DEVICE_ERROR
) {
2715 if (AskResetIfError
) {
2716 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2719 FallStatus
= EFI_DEVICE_ERROR
;
2722 if (EFI_ERROR (FallStatus
)) {
2723 if (*NumberOfSenseKeys
!= 0) {
2725 Status
= EFI_SUCCESS
;
2728 Status
= EFI_DEVICE_ERROR
;
2733 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
2734 (*NumberOfSenseKeys
) += 1;
2737 // no more sense key or number of sense keys exceeds predefined,
2740 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
2741 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
2747 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2753 Get information from media read capacity command.
2755 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2756 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
2757 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
2762 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2763 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
2764 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
2769 if (!ScsiDiskDevice
->Cdb16Byte
) {
2770 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= ((UINT32
) Capacity10
->LastLba3
<< 24) |
2771 (Capacity10
->LastLba2
<< 16) |
2772 (Capacity10
->LastLba1
<< 8) |
2773 Capacity10
->LastLba0
;
2775 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
2776 (Capacity10
->BlockSize2
<< 16) |
2777 (Capacity10
->BlockSize1
<< 8) |
2778 Capacity10
->BlockSize0
;
2779 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
2780 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
2781 if (!ScsiDiskDevice
->BlockLimitsVpdSupported
) {
2782 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
) ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2785 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2786 *Ptr
++ = Capacity16
->LastLba0
;
2787 *Ptr
++ = Capacity16
->LastLba1
;
2788 *Ptr
++ = Capacity16
->LastLba2
;
2789 *Ptr
++ = Capacity16
->LastLba3
;
2790 *Ptr
++ = Capacity16
->LastLba4
;
2791 *Ptr
++ = Capacity16
->LastLba5
;
2792 *Ptr
++ = Capacity16
->LastLba6
;
2793 *Ptr
= Capacity16
->LastLba7
;
2795 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
2796 (Capacity16
->BlockSize2
<< 16) |
2797 (Capacity16
->BlockSize1
<< 8) |
2798 Capacity16
->BlockSize0
;
2800 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
2801 Capacity16
->LowestAlignLogic1
;
2802 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
2803 if (!ScsiDiskDevice
->BlockLimitsVpdSupported
) {
2804 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
> (UINT32
) -1) {
2805 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
) -1;
2807 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
) ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2812 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
2818 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2823 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2826 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
2827 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
2831 Read sector from SCSI Disk.
2833 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2834 @param Buffer The buffer to fill in the read out data
2835 @param Lba Logic block address
2836 @param NumberOfBlocks The number of blocks to read
2838 @retval EFI_DEVICE_ERROR Indicates a device error.
2839 @retval EFI_SUCCESS Operation is successful.
2843 ScsiDiskReadSectors (
2844 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2847 IN UINTN NumberOfBlocks
2850 UINTN BlocksRemaining
;
2856 UINT32 NextSectorCount
;
2863 Status
= EFI_SUCCESS
;
2865 BlocksRemaining
= NumberOfBlocks
;
2866 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2869 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2871 if (!ScsiDiskDevice
->Cdb16Byte
) {
2874 MaxBlock
= 0xFFFFFFFF;
2879 while (BlocksRemaining
> 0) {
2881 if (BlocksRemaining
<= MaxBlock
) {
2882 if (!ScsiDiskDevice
->Cdb16Byte
) {
2883 SectorCount
= (UINT16
) BlocksRemaining
;
2885 SectorCount
= (UINT32
) BlocksRemaining
;
2888 SectorCount
= MaxBlock
;
2891 ByteCount
= SectorCount
* BlockSize
;
2893 // |------------------------|-----------------|------------------|-----------------|
2894 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2895 // |------------------------|-----------------|------------------|-----------------|
2896 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2897 // |------------------------|-----------------|------------------|-----------------|
2898 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2899 // |------------------------|-----------------|------------------|-----------------|
2900 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2901 // |------------------------|-----------------|------------------|-----------------|
2902 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2903 // |------------------------|-----------------|------------------|-----------------|
2904 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2905 // |------------------------|-----------------|------------------|-----------------|
2906 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2907 // |------------------------|-----------------|------------------|-----------------|
2908 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2909 // |------------------------|-----------------|------------------|-----------------|
2910 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2911 // |------------------------|-----------------|------------------|-----------------|
2912 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2913 // |------------------------|-----------------|------------------|-----------------|
2914 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2915 // |------------------------|-----------------|------------------|-----------------|
2917 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2918 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2919 // From the above table, we could know 2.1Mbytes per second is lowest one.
2920 // The timout value is rounded up to nearest integar and here an additional 30s is added
2921 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2922 // commands in the Standby/Idle mode.
2924 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2927 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2928 if (!ScsiDiskDevice
->Cdb16Byte
) {
2929 Status
= ScsiDiskRead10 (
2939 Status
= ScsiDiskRead16 (
2949 if (!EFI_ERROR (Status
)) {
2954 return EFI_DEVICE_ERROR
;
2958 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
2959 // lowered ByteCount on output, we must make sure that we lower
2960 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2961 // it is invalid to request more sectors in the CDB than the entire
2962 // transfer (ie. ByteCount) can carry.
2964 // In addition, ByteCount is only expected to go down, or stay unchaged.
2965 // Therefore we don't need to update Timeout: the original timeout should
2966 // accommodate shorter transfers too.
2968 NextSectorCount
= ByteCount
/ BlockSize
;
2969 if (NextSectorCount
< SectorCount
) {
2970 SectorCount
= NextSectorCount
;
2972 // Account for any rounding down.
2974 ByteCount
= SectorCount
* BlockSize
;
2978 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2979 return EFI_DEVICE_ERROR
;
2983 // actual transferred sectors
2985 SectorCount
= ByteCount
/ BlockSize
;
2988 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2989 BlocksRemaining
-= SectorCount
;
2996 Write sector to SCSI Disk.
2998 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2999 @param Buffer The buffer of data to be written into SCSI Disk
3000 @param Lba Logic block address
3001 @param NumberOfBlocks The number of blocks to read
3003 @retval EFI_DEVICE_ERROR Indicates a device error.
3004 @retval EFI_SUCCESS Operation is successful.
3008 ScsiDiskWriteSectors (
3009 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3012 IN UINTN NumberOfBlocks
3015 UINTN BlocksRemaining
;
3021 UINT32 NextSectorCount
;
3028 Status
= EFI_SUCCESS
;
3030 BlocksRemaining
= NumberOfBlocks
;
3031 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3034 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3036 if (!ScsiDiskDevice
->Cdb16Byte
) {
3039 MaxBlock
= 0xFFFFFFFF;
3044 while (BlocksRemaining
> 0) {
3046 if (BlocksRemaining
<= MaxBlock
) {
3047 if (!ScsiDiskDevice
->Cdb16Byte
) {
3048 SectorCount
= (UINT16
) BlocksRemaining
;
3050 SectorCount
= (UINT32
) BlocksRemaining
;
3053 SectorCount
= MaxBlock
;
3056 ByteCount
= SectorCount
* BlockSize
;
3058 // |------------------------|-----------------|------------------|-----------------|
3059 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3060 // |------------------------|-----------------|------------------|-----------------|
3061 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3062 // |------------------------|-----------------|------------------|-----------------|
3063 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3064 // |------------------------|-----------------|------------------|-----------------|
3065 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3066 // |------------------------|-----------------|------------------|-----------------|
3067 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3068 // |------------------------|-----------------|------------------|-----------------|
3069 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3070 // |------------------------|-----------------|------------------|-----------------|
3071 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3072 // |------------------------|-----------------|------------------|-----------------|
3073 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3074 // |------------------------|-----------------|------------------|-----------------|
3075 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3076 // |------------------------|-----------------|------------------|-----------------|
3077 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3078 // |------------------------|-----------------|------------------|-----------------|
3079 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3080 // |------------------------|-----------------|------------------|-----------------|
3082 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3083 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3084 // From the above table, we could know 2.1Mbytes per second is lowest one.
3085 // The timout value is rounded up to nearest integar and here an additional 30s is added
3086 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3087 // commands in the Standby/Idle mode.
3089 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3091 for (Index
= 0; Index
< MaxRetry
; Index
++) {
3092 if (!ScsiDiskDevice
->Cdb16Byte
) {
3093 Status
= ScsiDiskWrite10 (
3103 Status
= ScsiDiskWrite16 (
3113 if (!EFI_ERROR (Status
)) {
3118 return EFI_DEVICE_ERROR
;
3122 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
3123 // has lowered ByteCount on output, we must make sure that we lower
3124 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3125 // it is invalid to request more sectors in the CDB than the entire
3126 // transfer (ie. ByteCount) can carry.
3128 // In addition, ByteCount is only expected to go down, or stay unchaged.
3129 // Therefore we don't need to update Timeout: the original timeout should
3130 // accommodate shorter transfers too.
3132 NextSectorCount
= ByteCount
/ BlockSize
;
3133 if (NextSectorCount
< SectorCount
) {
3134 SectorCount
= NextSectorCount
;
3136 // Account for any rounding down.
3138 ByteCount
= SectorCount
* BlockSize
;
3142 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
3143 return EFI_DEVICE_ERROR
;
3146 // actual transferred sectors
3148 SectorCount
= ByteCount
/ BlockSize
;
3151 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3152 BlocksRemaining
-= SectorCount
;
3159 Asynchronously read sector from SCSI Disk.
3161 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3162 @param Buffer The buffer to fill in the read out data.
3163 @param Lba Logic block address.
3164 @param NumberOfBlocks The number of blocks to read.
3165 @param Token A pointer to the token associated with the
3166 non-blocking read request.
3168 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
3169 @retval EFI_DEVICE_ERROR Indicates a device error.
3170 @retval EFI_SUCCESS Operation is successful.
3174 ScsiDiskAsyncReadSectors (
3175 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3178 IN UINTN NumberOfBlocks
,
3179 IN EFI_BLOCK_IO2_TOKEN
*Token
3182 UINTN BlocksRemaining
;
3189 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
3193 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
3194 return EFI_INVALID_PARAMETER
;
3197 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
3198 if (BlkIo2Req
== NULL
) {
3199 return EFI_OUT_OF_RESOURCES
;
3202 BlkIo2Req
->Token
= Token
;
3204 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3205 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &BlkIo2Req
->Link
);
3206 gBS
->RestoreTPL (OldTpl
);
3208 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
3210 Status
= EFI_SUCCESS
;
3212 BlocksRemaining
= NumberOfBlocks
;
3213 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3216 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3219 if (!ScsiDiskDevice
->Cdb16Byte
) {
3222 MaxBlock
= 0xFFFFFFFF;
3227 while (BlocksRemaining
> 0) {
3229 if (BlocksRemaining
<= MaxBlock
) {
3230 if (!ScsiDiskDevice
->Cdb16Byte
) {
3231 SectorCount
= (UINT16
) BlocksRemaining
;
3233 SectorCount
= (UINT32
) BlocksRemaining
;
3236 SectorCount
= MaxBlock
;
3239 ByteCount
= SectorCount
* BlockSize
;
3241 // |------------------------|-----------------|------------------|-----------------|
3242 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3243 // |------------------------|-----------------|------------------|-----------------|
3244 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3245 // |------------------------|-----------------|------------------|-----------------|
3246 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3247 // |------------------------|-----------------|------------------|-----------------|
3248 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3249 // |------------------------|-----------------|------------------|-----------------|
3250 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3251 // |------------------------|-----------------|------------------|-----------------|
3252 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3253 // |------------------------|-----------------|------------------|-----------------|
3254 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3255 // |------------------------|-----------------|------------------|-----------------|
3256 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3257 // |------------------------|-----------------|------------------|-----------------|
3258 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3259 // |------------------------|-----------------|------------------|-----------------|
3260 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3261 // |------------------------|-----------------|------------------|-----------------|
3262 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3263 // |------------------------|-----------------|------------------|-----------------|
3265 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3266 // we have to use the lowest transfer rate to calculate the possible
3267 // maximum timeout value for each operation.
3268 // From the above table, we could know 2.1Mbytes per second is lowest one.
3269 // The timout value is rounded up to nearest integar and here an additional
3270 // 30s is added to follow ATA spec in which it mentioned that the device
3271 // may take up to 30s to respond commands in the Standby/Idle mode.
3273 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3275 if (!ScsiDiskDevice
->Cdb16Byte
) {
3276 Status
= ScsiDiskAsyncRead10 (
3288 Status
= ScsiDiskAsyncRead16 (
3300 if (EFI_ERROR (Status
)) {
3302 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3303 // length of a SCSI I/O command is too large.
3304 // In this case, we retry sending the SCSI command with a data length
3305 // half of its previous value.
3307 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
3308 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
3309 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
3314 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3315 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3317 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3318 // SCSI sub-task running. Otherwise, it will be freed in the callback
3319 // function ScsiDiskNotify().
3321 RemoveEntryList (&BlkIo2Req
->Link
);
3322 FreePool (BlkIo2Req
);
3324 gBS
->RestoreTPL (OldTpl
);
3327 // It is safe to return error status to the caller, since there is no
3328 // previous SCSI sub-task executing.
3330 Status
= EFI_DEVICE_ERROR
;
3333 gBS
->RestoreTPL (OldTpl
);
3336 // There are previous SCSI commands still running, EFI_SUCCESS should
3337 // be returned to make sure that the caller does not free resources
3338 // still using by these SCSI commands.
3340 Status
= EFI_SUCCESS
;
3346 // Sectors submitted for transfer
3348 SectorCount
= ByteCount
/ BlockSize
;
3351 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3352 BlocksRemaining
-= SectorCount
;
3355 Status
= EFI_SUCCESS
;
3358 if (BlkIo2Req
!= NULL
) {
3359 BlkIo2Req
->LastScsiRW
= TRUE
;
3361 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3362 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3363 RemoveEntryList (&BlkIo2Req
->Link
);
3364 FreePool (BlkIo2Req
);
3367 gBS
->SignalEvent (Token
->Event
);
3369 gBS
->RestoreTPL (OldTpl
);
3376 Asynchronously write sector to SCSI Disk.
3378 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3379 @param Buffer The buffer of data to be written into SCSI Disk.
3380 @param Lba Logic block address.
3381 @param NumberOfBlocks The number of blocks to read.
3382 @param Token A pointer to the token associated with the
3383 non-blocking read request.
3385 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
3386 @retval EFI_DEVICE_ERROR Indicates a device error.
3387 @retval EFI_SUCCESS Operation is successful.
3391 ScsiDiskAsyncWriteSectors (
3392 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3395 IN UINTN NumberOfBlocks
,
3396 IN EFI_BLOCK_IO2_TOKEN
*Token
3399 UINTN BlocksRemaining
;
3406 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
3410 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
3411 return EFI_INVALID_PARAMETER
;
3414 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
3415 if (BlkIo2Req
== NULL
) {
3416 return EFI_OUT_OF_RESOURCES
;
3419 BlkIo2Req
->Token
= Token
;
3421 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3422 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &BlkIo2Req
->Link
);
3423 gBS
->RestoreTPL (OldTpl
);
3425 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
3427 Status
= EFI_SUCCESS
;
3429 BlocksRemaining
= NumberOfBlocks
;
3430 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3433 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3436 if (!ScsiDiskDevice
->Cdb16Byte
) {
3439 MaxBlock
= 0xFFFFFFFF;
3444 while (BlocksRemaining
> 0) {
3446 if (BlocksRemaining
<= MaxBlock
) {
3447 if (!ScsiDiskDevice
->Cdb16Byte
) {
3448 SectorCount
= (UINT16
) BlocksRemaining
;
3450 SectorCount
= (UINT32
) BlocksRemaining
;
3453 SectorCount
= MaxBlock
;
3456 ByteCount
= SectorCount
* BlockSize
;
3458 // |------------------------|-----------------|------------------|-----------------|
3459 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3460 // |------------------------|-----------------|------------------|-----------------|
3461 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3462 // |------------------------|-----------------|------------------|-----------------|
3463 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3464 // |------------------------|-----------------|------------------|-----------------|
3465 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3466 // |------------------------|-----------------|------------------|-----------------|
3467 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3468 // |------------------------|-----------------|------------------|-----------------|
3469 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3470 // |------------------------|-----------------|------------------|-----------------|
3471 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3472 // |------------------------|-----------------|------------------|-----------------|
3473 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3474 // |------------------------|-----------------|------------------|-----------------|
3475 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3476 // |------------------------|-----------------|------------------|-----------------|
3477 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3478 // |------------------------|-----------------|------------------|-----------------|
3479 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3480 // |------------------------|-----------------|------------------|-----------------|
3482 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3483 // we have to use the lowest transfer rate to calculate the possible
3484 // maximum timeout value for each operation.
3485 // From the above table, we could know 2.1Mbytes per second is lowest one.
3486 // The timout value is rounded up to nearest integar and here an additional
3487 // 30s is added to follow ATA spec in which it mentioned that the device
3488 // may take up to 30s to respond commands in the Standby/Idle mode.
3490 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3492 if (!ScsiDiskDevice
->Cdb16Byte
) {
3493 Status
= ScsiDiskAsyncWrite10 (
3505 Status
= ScsiDiskAsyncWrite16 (
3517 if (EFI_ERROR (Status
)) {
3519 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3520 // length of a SCSI I/O command is too large.
3521 // In this case, we retry sending the SCSI command with a data length
3522 // half of its previous value.
3524 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
3525 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
3526 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
3531 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3532 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3534 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3535 // SCSI sub-task running. Otherwise, it will be freed in the callback
3536 // function ScsiDiskNotify().
3538 RemoveEntryList (&BlkIo2Req
->Link
);
3539 FreePool (BlkIo2Req
);
3541 gBS
->RestoreTPL (OldTpl
);
3544 // It is safe to return error status to the caller, since there is no
3545 // previous SCSI sub-task executing.
3547 Status
= EFI_DEVICE_ERROR
;
3550 gBS
->RestoreTPL (OldTpl
);
3553 // There are previous SCSI commands still running, EFI_SUCCESS should
3554 // be returned to make sure that the caller does not free resources
3555 // still using by these SCSI commands.
3557 Status
= EFI_SUCCESS
;
3563 // Sectors submitted for transfer
3565 SectorCount
= ByteCount
/ BlockSize
;
3568 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3569 BlocksRemaining
-= SectorCount
;
3572 Status
= EFI_SUCCESS
;
3575 if (BlkIo2Req
!= NULL
) {
3576 BlkIo2Req
->LastScsiRW
= TRUE
;
3578 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3579 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3580 RemoveEntryList (&BlkIo2Req
->Link
);
3581 FreePool (BlkIo2Req
);
3584 gBS
->SignalEvent (Token
->Event
);
3586 gBS
->RestoreTPL (OldTpl
);
3594 Submit Read(10) command.
3596 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3597 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3598 @param Timeout The time to complete the command
3599 @param DataBuffer The buffer to fill with the read out data
3600 @param DataLength The length of buffer
3601 @param StartLba The start logic block address
3602 @param SectorCount The number of blocks to read
3604 @return EFI_STATUS is returned by calling ScsiRead10Command().
3608 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3609 OUT BOOLEAN
*NeedRetry
,
3611 OUT UINT8
*DataBuffer
,
3612 IN OUT UINT32
*DataLength
,
3614 IN UINT32 SectorCount
3617 UINT8 SenseDataLength
;
3619 EFI_STATUS ReturnStatus
;
3620 UINT8 HostAdapterStatus
;
3625 // Implement a backoff algorithem to resolve some compatibility issues that
3626 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3627 // big data in a single operation.
3628 // This algorithem will at first try to execute original request. If the request fails
3629 // with media error sense data or else, it will reduce the transfer length to half and
3630 // try again till the operation succeeds or fails with one sector transfer length.
3634 Action
= ACTION_NO_ACTION
;
3635 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3636 ReturnStatus
= ScsiRead10Command (
3637 ScsiDiskDevice
->ScsiIo
,
3639 ScsiDiskDevice
->SenseData
,
3649 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3651 return EFI_DEVICE_ERROR
;
3652 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3654 return ReturnStatus
;
3658 // go ahead to check HostAdapterStatus and TargetStatus
3659 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3661 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3662 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3664 return EFI_DEVICE_ERROR
;
3665 } else if (Status
== EFI_DEVICE_ERROR
) {
3667 // reset the scsi channel
3669 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3671 return EFI_DEVICE_ERROR
;
3674 Status
= CheckTargetStatus (TargetStatus
);
3675 if (Status
== EFI_NOT_READY
) {
3677 // reset the scsi device
3679 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3681 return EFI_DEVICE_ERROR
;
3682 } else if (Status
== EFI_DEVICE_ERROR
) {
3684 return EFI_DEVICE_ERROR
;
3687 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3688 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
3689 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3690 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3692 return EFI_DEVICE_ERROR
;
3693 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3694 if (SectorCount
<= 1) {
3696 // Jump out if the operation still fails with one sector transfer length.
3699 return EFI_DEVICE_ERROR
;
3702 // Try again with half length if the sense data shows we need to retry.
3705 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3709 return EFI_DEVICE_ERROR
;
3713 return ReturnStatus
;
3718 Submit Write(10) Command.
3720 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3721 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3722 @param Timeout The time to complete the command
3723 @param DataBuffer The buffer to fill with the read out data
3724 @param DataLength The length of buffer
3725 @param StartLba The start logic block address
3726 @param SectorCount The number of blocks to write
3728 @return EFI_STATUS is returned by calling ScsiWrite10Command().
3733 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3734 OUT BOOLEAN
*NeedRetry
,
3736 IN UINT8
*DataBuffer
,
3737 IN OUT UINT32
*DataLength
,
3739 IN UINT32 SectorCount
3743 EFI_STATUS ReturnStatus
;
3744 UINT8 SenseDataLength
;
3745 UINT8 HostAdapterStatus
;
3750 // Implement a backoff algorithem to resolve some compatibility issues that
3751 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3752 // big data in a single operation.
3753 // This algorithem will at first try to execute original request. If the request fails
3754 // with media error sense data or else, it will reduce the transfer length to half and
3755 // try again till the operation succeeds or fails with one sector transfer length.
3759 Action
= ACTION_NO_ACTION
;
3760 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3761 ReturnStatus
= ScsiWrite10Command (
3762 ScsiDiskDevice
->ScsiIo
,
3764 ScsiDiskDevice
->SenseData
,
3773 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3775 return EFI_DEVICE_ERROR
;
3776 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3778 return ReturnStatus
;
3782 // go ahead to check HostAdapterStatus and TargetStatus
3783 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3785 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3786 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3788 return EFI_DEVICE_ERROR
;
3789 } else if (Status
== EFI_DEVICE_ERROR
) {
3791 // reset the scsi channel
3793 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3795 return EFI_DEVICE_ERROR
;
3798 Status
= CheckTargetStatus (TargetStatus
);
3799 if (Status
== EFI_NOT_READY
) {
3801 // reset the scsi device
3803 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3805 return EFI_DEVICE_ERROR
;
3806 } else if (Status
== EFI_DEVICE_ERROR
) {
3808 return EFI_DEVICE_ERROR
;
3811 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3812 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
3813 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3814 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3816 return EFI_DEVICE_ERROR
;
3817 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3818 if (SectorCount
<= 1) {
3820 // Jump out if the operation still fails with one sector transfer length.
3823 return EFI_DEVICE_ERROR
;
3826 // Try again with half length if the sense data shows we need to retry.
3829 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3833 return EFI_DEVICE_ERROR
;
3837 return ReturnStatus
;
3842 Submit Read(16) command.
3844 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3845 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3846 @param Timeout The time to complete the command
3847 @param DataBuffer The buffer to fill with the read out data
3848 @param DataLength The length of buffer
3849 @param StartLba The start logic block address
3850 @param SectorCount The number of blocks to read
3852 @return EFI_STATUS is returned by calling ScsiRead16Command().
3856 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3857 OUT BOOLEAN
*NeedRetry
,
3859 OUT UINT8
*DataBuffer
,
3860 IN OUT UINT32
*DataLength
,
3862 IN UINT32 SectorCount
3865 UINT8 SenseDataLength
;
3867 EFI_STATUS ReturnStatus
;
3868 UINT8 HostAdapterStatus
;
3873 // Implement a backoff algorithem to resolve some compatibility issues that
3874 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3875 // big data in a single operation.
3876 // This algorithem will at first try to execute original request. If the request fails
3877 // with media error sense data or else, it will reduce the transfer length to half and
3878 // try again till the operation succeeds or fails with one sector transfer length.
3882 Action
= ACTION_NO_ACTION
;
3883 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3884 ReturnStatus
= ScsiRead16Command (
3885 ScsiDiskDevice
->ScsiIo
,
3887 ScsiDiskDevice
->SenseData
,
3896 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3898 return EFI_DEVICE_ERROR
;
3899 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3901 return ReturnStatus
;
3905 // go ahead to check HostAdapterStatus and TargetStatus
3906 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3908 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3909 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3911 return EFI_DEVICE_ERROR
;
3912 } else if (Status
== EFI_DEVICE_ERROR
) {
3914 // reset the scsi channel
3916 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3918 return EFI_DEVICE_ERROR
;
3921 Status
= CheckTargetStatus (TargetStatus
);
3922 if (Status
== EFI_NOT_READY
) {
3924 // reset the scsi device
3926 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3928 return EFI_DEVICE_ERROR
;
3929 } else if (Status
== EFI_DEVICE_ERROR
) {
3931 return EFI_DEVICE_ERROR
;
3934 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3935 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
3936 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3937 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3939 return EFI_DEVICE_ERROR
;
3940 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3941 if (SectorCount
<= 1) {
3943 // Jump out if the operation still fails with one sector transfer length.
3946 return EFI_DEVICE_ERROR
;
3949 // Try again with half length if the sense data shows we need to retry.
3952 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3956 return EFI_DEVICE_ERROR
;
3960 return ReturnStatus
;
3965 Submit Write(16) Command.
3967 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3968 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3969 @param Timeout The time to complete the command
3970 @param DataBuffer The buffer to fill with the read out data
3971 @param DataLength The length of buffer
3972 @param StartLba The start logic block address
3973 @param SectorCount The number of blocks to write
3975 @return EFI_STATUS is returned by calling ScsiWrite16Command().
3980 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3981 OUT BOOLEAN
*NeedRetry
,
3983 IN UINT8
*DataBuffer
,
3984 IN OUT UINT32
*DataLength
,
3986 IN UINT32 SectorCount
3990 EFI_STATUS ReturnStatus
;
3991 UINT8 SenseDataLength
;
3992 UINT8 HostAdapterStatus
;
3997 // Implement a backoff algorithem to resolve some compatibility issues that
3998 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3999 // big data in a single operation.
4000 // This algorithem will at first try to execute original request. If the request fails
4001 // with media error sense data or else, it will reduce the transfer length to half and
4002 // try again till the operation succeeds or fails with one sector transfer length.
4006 Action
= ACTION_NO_ACTION
;
4007 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
4008 ReturnStatus
= ScsiWrite16Command (
4009 ScsiDiskDevice
->ScsiIo
,
4011 ScsiDiskDevice
->SenseData
,
4020 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
4022 return EFI_DEVICE_ERROR
;
4023 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
4025 return ReturnStatus
;
4029 // go ahead to check HostAdapterStatus and TargetStatus
4030 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4032 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
4033 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4035 return EFI_DEVICE_ERROR
;
4036 } else if (Status
== EFI_DEVICE_ERROR
) {
4038 // reset the scsi channel
4040 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4042 return EFI_DEVICE_ERROR
;
4045 Status
= CheckTargetStatus (TargetStatus
);
4046 if (Status
== EFI_NOT_READY
) {
4048 // reset the scsi device
4050 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4052 return EFI_DEVICE_ERROR
;
4053 } else if (Status
== EFI_DEVICE_ERROR
) {
4055 return EFI_DEVICE_ERROR
;
4058 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
4059 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
4060 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
4061 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4063 return EFI_DEVICE_ERROR
;
4064 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4065 if (SectorCount
<= 1) {
4067 // Jump out if the operation still fails with one sector transfer length.
4070 return EFI_DEVICE_ERROR
;
4073 // Try again with half length if the sense data shows we need to retry.
4076 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4080 return EFI_DEVICE_ERROR
;
4084 return ReturnStatus
;
4089 Internal helper notify function in which determine whether retry of a SCSI
4090 Read/Write command is needed and signal the event passed from Block I/O(2) if
4091 the SCSI I/O operation completes.
4093 @param Event The instance of EFI_EVENT.
4094 @param Context The parameter passed in.
4105 SCSI_ASYNC_RW_REQUEST
*Request
;
4106 SCSI_DISK_DEV
*ScsiDiskDevice
;
4107 EFI_BLOCK_IO2_TOKEN
*Token
;
4109 UINT32 OldDataLength
;
4110 UINT32 OldSectorCount
;
4113 gBS
->CloseEvent (Event
);
4115 Request
= (SCSI_ASYNC_RW_REQUEST
*) Context
;
4116 ScsiDiskDevice
= Request
->ScsiDiskDevice
;
4117 Token
= Request
->BlkIo2Req
->Token
;
4118 OldDataLength
= Request
->DataLength
;
4119 OldSectorCount
= Request
->SectorCount
;
4123 // If previous sub-tasks already fails, no need to process this sub-task.
4125 if (Token
->TransactionStatus
!= EFI_SUCCESS
) {
4130 // Check HostAdapterStatus and TargetStatus
4131 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4133 Status
= CheckHostAdapterStatus (Request
->HostAdapterStatus
);
4134 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4135 if (++Request
->TimesRetry
> MaxRetry
) {
4136 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4141 } else if (Status
== EFI_DEVICE_ERROR
) {
4143 // reset the scsi channel
4145 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4146 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4150 Status
= CheckTargetStatus (Request
->TargetStatus
);
4151 if (Status
== EFI_NOT_READY
) {
4153 // reset the scsi device
4155 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4156 if (++Request
->TimesRetry
> MaxRetry
) {
4157 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4162 } else if (Status
== EFI_DEVICE_ERROR
) {
4163 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4167 if (Request
->TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) {
4168 DEBUG ((EFI_D_ERROR
, "ScsiDiskNotify: Check Condition happened!\n"));
4170 Status
= DetectMediaParsingSenseKeys (
4173 Request
->SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
),
4176 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4177 if (++Request
->TimesRetry
> MaxRetry
) {
4178 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4183 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4184 if (Request
->SectorCount
<= 1) {
4186 // Jump out if the operation still fails with one sector transfer
4189 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4193 // Try again with two half length request if the sense data shows we need
4196 Request
->SectorCount
>>= 1;
4197 Request
->DataLength
= Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4198 Request
->TimesRetry
= 0;
4202 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4208 // This sub-task succeeds, no need to retry.
4213 if (Request
->InBuffer
!= NULL
) {
4215 // SCSI read command
4217 if (!ScsiDiskDevice
->Cdb16Byte
) {
4218 Status
= ScsiDiskAsyncRead10 (
4221 Request
->TimesRetry
,
4223 Request
->DataLength
,
4224 (UINT32
) Request
->StartLba
,
4225 Request
->SectorCount
,
4230 Status
= ScsiDiskAsyncRead16 (
4233 Request
->TimesRetry
,
4235 Request
->DataLength
,
4237 Request
->SectorCount
,
4243 if (EFI_ERROR (Status
)) {
4244 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4246 } else if (OldSectorCount
!= Request
->SectorCount
) {
4248 // Original sub-task will be split into two new sub-tasks with smaller
4251 if (!ScsiDiskDevice
->Cdb16Byte
) {
4252 Status
= ScsiDiskAsyncRead10 (
4256 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4257 OldDataLength
- Request
->DataLength
,
4258 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
4259 OldSectorCount
- Request
->SectorCount
,
4264 Status
= ScsiDiskAsyncRead16 (
4268 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4269 OldDataLength
- Request
->DataLength
,
4270 Request
->StartLba
+ Request
->SectorCount
,
4271 OldSectorCount
- Request
->SectorCount
,
4276 if (EFI_ERROR (Status
)) {
4277 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4283 // SCSI write command
4285 if (!ScsiDiskDevice
->Cdb16Byte
) {
4286 Status
= ScsiDiskAsyncWrite10 (
4289 Request
->TimesRetry
,
4291 Request
->DataLength
,
4292 (UINT32
) Request
->StartLba
,
4293 Request
->SectorCount
,
4298 Status
= ScsiDiskAsyncWrite16 (
4301 Request
->TimesRetry
,
4303 Request
->DataLength
,
4305 Request
->SectorCount
,
4311 if (EFI_ERROR (Status
)) {
4312 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4314 } else if (OldSectorCount
!= Request
->SectorCount
) {
4316 // Original sub-task will be split into two new sub-tasks with smaller
4319 if (!ScsiDiskDevice
->Cdb16Byte
) {
4320 Status
= ScsiDiskAsyncWrite10 (
4324 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4325 OldDataLength
- Request
->DataLength
,
4326 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
4327 OldSectorCount
- Request
->SectorCount
,
4332 Status
= ScsiDiskAsyncWrite16 (
4336 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4337 OldDataLength
- Request
->DataLength
,
4338 Request
->StartLba
+ Request
->SectorCount
,
4339 OldSectorCount
- Request
->SectorCount
,
4344 if (EFI_ERROR (Status
)) {
4345 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4352 RemoveEntryList (&Request
->Link
);
4353 if ((IsListEmpty (&Request
->BlkIo2Req
->ScsiRWQueue
)) &&
4354 (Request
->BlkIo2Req
->LastScsiRW
)) {
4356 // The last SCSI R/W command of a BlockIo2 request completes
4358 RemoveEntryList (&Request
->BlkIo2Req
->Link
);
4359 FreePool (Request
->BlkIo2Req
); // Should be freed only once
4360 gBS
->SignalEvent (Token
->Event
);
4363 FreePool (Request
->SenseData
);
4369 Submit Async Read(10) command.
4371 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4372 @param Timeout The time to complete the command.
4373 @param TimesRetry The number of times the command has been retried.
4374 @param DataBuffer The buffer to fill with the read out data.
4375 @param DataLength The length of buffer.
4376 @param StartLba The start logic block address.
4377 @param SectorCount The number of blocks to read.
4378 @param BlkIo2Req The upstream BlockIo2 request.
4379 @param Token The pointer to the token associated with the
4380 non-blocking read request.
4382 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4384 @return others Status returned by calling
4385 ScsiRead10CommandEx().
4389 ScsiDiskAsyncRead10 (
4390 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4392 IN UINT8 TimesRetry
,
4393 OUT UINT8
*DataBuffer
,
4394 IN UINT32 DataLength
,
4396 IN UINT32 SectorCount
,
4397 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4398 IN EFI_BLOCK_IO2_TOKEN
*Token
4402 SCSI_ASYNC_RW_REQUEST
*Request
;
4403 EFI_EVENT AsyncIoEvent
;
4406 AsyncIoEvent
= NULL
;
4408 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4409 if (Request
== NULL
) {
4410 return EFI_OUT_OF_RESOURCES
;
4413 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4414 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4415 gBS
->RestoreTPL (OldTpl
);
4417 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4418 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4419 if (Request
->SenseData
== NULL
) {
4420 Status
= EFI_OUT_OF_RESOURCES
;
4424 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4425 Request
->Timeout
= Timeout
;
4426 Request
->TimesRetry
= TimesRetry
;
4427 Request
->InBuffer
= DataBuffer
;
4428 Request
->DataLength
= DataLength
;
4429 Request
->StartLba
= StartLba
;
4430 Request
->SectorCount
= SectorCount
;
4431 Request
->BlkIo2Req
= BlkIo2Req
;
4436 Status
= gBS
->CreateEvent (
4443 if (EFI_ERROR(Status
)) {
4447 Status
= ScsiRead10CommandEx (
4448 ScsiDiskDevice
->ScsiIo
,
4451 &Request
->SenseDataLength
,
4452 &Request
->HostAdapterStatus
,
4453 &Request
->TargetStatus
,
4455 &Request
->DataLength
,
4456 (UINT32
) Request
->StartLba
,
4457 Request
->SectorCount
,
4460 if (EFI_ERROR(Status
)) {
4467 if (AsyncIoEvent
!= NULL
) {
4468 gBS
->CloseEvent (AsyncIoEvent
);
4471 if (Request
!= NULL
) {
4472 if (Request
->SenseData
!= NULL
) {
4473 FreePool (Request
->SenseData
);
4476 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4477 RemoveEntryList (&Request
->Link
);
4478 gBS
->RestoreTPL (OldTpl
);
4488 Submit Async Write(10) command.
4490 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4491 @param Timeout The time to complete the command.
4492 @param TimesRetry The number of times the command has been retried.
4493 @param DataBuffer The buffer contains the data to write.
4494 @param DataLength The length of buffer.
4495 @param StartLba The start logic block address.
4496 @param SectorCount The number of blocks to write.
4497 @param BlkIo2Req The upstream BlockIo2 request.
4498 @param Token The pointer to the token associated with the
4499 non-blocking read request.
4501 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4503 @return others Status returned by calling
4504 ScsiWrite10CommandEx().
4508 ScsiDiskAsyncWrite10 (
4509 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4511 IN UINT8 TimesRetry
,
4512 IN UINT8
*DataBuffer
,
4513 IN UINT32 DataLength
,
4515 IN UINT32 SectorCount
,
4516 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4517 IN EFI_BLOCK_IO2_TOKEN
*Token
4521 SCSI_ASYNC_RW_REQUEST
*Request
;
4522 EFI_EVENT AsyncIoEvent
;
4525 AsyncIoEvent
= NULL
;
4527 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4528 if (Request
== NULL
) {
4529 return EFI_OUT_OF_RESOURCES
;
4532 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4533 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4534 gBS
->RestoreTPL (OldTpl
);
4536 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4537 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4538 if (Request
->SenseData
== NULL
) {
4539 Status
= EFI_OUT_OF_RESOURCES
;
4543 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4544 Request
->Timeout
= Timeout
;
4545 Request
->TimesRetry
= TimesRetry
;
4546 Request
->OutBuffer
= DataBuffer
;
4547 Request
->DataLength
= DataLength
;
4548 Request
->StartLba
= StartLba
;
4549 Request
->SectorCount
= SectorCount
;
4550 Request
->BlkIo2Req
= BlkIo2Req
;
4555 Status
= gBS
->CreateEvent (
4562 if (EFI_ERROR(Status
)) {
4566 Status
= ScsiWrite10CommandEx (
4567 ScsiDiskDevice
->ScsiIo
,
4570 &Request
->SenseDataLength
,
4571 &Request
->HostAdapterStatus
,
4572 &Request
->TargetStatus
,
4574 &Request
->DataLength
,
4575 (UINT32
) Request
->StartLba
,
4576 Request
->SectorCount
,
4579 if (EFI_ERROR(Status
)) {
4586 if (AsyncIoEvent
!= NULL
) {
4587 gBS
->CloseEvent (AsyncIoEvent
);
4590 if (Request
!= NULL
) {
4591 if (Request
->SenseData
!= NULL
) {
4592 FreePool (Request
->SenseData
);
4595 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4596 RemoveEntryList (&Request
->Link
);
4597 gBS
->RestoreTPL (OldTpl
);
4607 Submit Async Read(16) command.
4609 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4610 @param Timeout The time to complete the command.
4611 @param TimesRetry The number of times the command has been retried.
4612 @param DataBuffer The buffer to fill with the read out data.
4613 @param DataLength The length of buffer.
4614 @param StartLba The start logic block address.
4615 @param SectorCount The number of blocks to read.
4616 @param BlkIo2Req The upstream BlockIo2 request.
4617 @param Token The pointer to the token associated with the
4618 non-blocking read request.
4620 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4622 @return others Status returned by calling
4623 ScsiRead16CommandEx().
4627 ScsiDiskAsyncRead16 (
4628 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4630 IN UINT8 TimesRetry
,
4631 OUT UINT8
*DataBuffer
,
4632 IN UINT32 DataLength
,
4634 IN UINT32 SectorCount
,
4635 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4636 IN EFI_BLOCK_IO2_TOKEN
*Token
4640 SCSI_ASYNC_RW_REQUEST
*Request
;
4641 EFI_EVENT AsyncIoEvent
;
4644 AsyncIoEvent
= NULL
;
4646 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4647 if (Request
== NULL
) {
4648 return EFI_OUT_OF_RESOURCES
;
4651 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4652 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4653 gBS
->RestoreTPL (OldTpl
);
4655 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4656 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4657 if (Request
->SenseData
== NULL
) {
4658 Status
= EFI_OUT_OF_RESOURCES
;
4662 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4663 Request
->Timeout
= Timeout
;
4664 Request
->TimesRetry
= TimesRetry
;
4665 Request
->InBuffer
= DataBuffer
;
4666 Request
->DataLength
= DataLength
;
4667 Request
->StartLba
= StartLba
;
4668 Request
->SectorCount
= SectorCount
;
4669 Request
->BlkIo2Req
= BlkIo2Req
;
4674 Status
= gBS
->CreateEvent (
4681 if (EFI_ERROR(Status
)) {
4685 Status
= ScsiRead16CommandEx (
4686 ScsiDiskDevice
->ScsiIo
,
4689 &Request
->SenseDataLength
,
4690 &Request
->HostAdapterStatus
,
4691 &Request
->TargetStatus
,
4693 &Request
->DataLength
,
4695 Request
->SectorCount
,
4698 if (EFI_ERROR(Status
)) {
4705 if (AsyncIoEvent
!= NULL
) {
4706 gBS
->CloseEvent (AsyncIoEvent
);
4709 if (Request
!= NULL
) {
4710 if (Request
->SenseData
!= NULL
) {
4711 FreePool (Request
->SenseData
);
4714 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4715 RemoveEntryList (&Request
->Link
);
4716 gBS
->RestoreTPL (OldTpl
);
4726 Submit Async Write(16) command.
4728 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4729 @param Timeout The time to complete the command.
4730 @param TimesRetry The number of times the command has been retried.
4731 @param DataBuffer The buffer contains the data to write.
4732 @param DataLength The length of buffer.
4733 @param StartLba The start logic block address.
4734 @param SectorCount The number of blocks to write.
4735 @param BlkIo2Req The upstream BlockIo2 request.
4736 @param Token The pointer to the token associated with the
4737 non-blocking read request.
4739 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4741 @return others Status returned by calling
4742 ScsiWrite16CommandEx().
4746 ScsiDiskAsyncWrite16 (
4747 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4749 IN UINT8 TimesRetry
,
4750 IN UINT8
*DataBuffer
,
4751 IN UINT32 DataLength
,
4753 IN UINT32 SectorCount
,
4754 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4755 IN EFI_BLOCK_IO2_TOKEN
*Token
4759 SCSI_ASYNC_RW_REQUEST
*Request
;
4760 EFI_EVENT AsyncIoEvent
;
4763 AsyncIoEvent
= NULL
;
4765 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4766 if (Request
== NULL
) {
4767 return EFI_OUT_OF_RESOURCES
;
4770 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4771 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4772 gBS
->RestoreTPL (OldTpl
);
4774 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4775 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4776 if (Request
->SenseData
== NULL
) {
4777 Status
= EFI_OUT_OF_RESOURCES
;
4781 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4782 Request
->Timeout
= Timeout
;
4783 Request
->TimesRetry
= TimesRetry
;
4784 Request
->OutBuffer
= DataBuffer
;
4785 Request
->DataLength
= DataLength
;
4786 Request
->StartLba
= StartLba
;
4787 Request
->SectorCount
= SectorCount
;
4788 Request
->BlkIo2Req
= BlkIo2Req
;
4793 Status
= gBS
->CreateEvent (
4800 if (EFI_ERROR(Status
)) {
4804 Status
= ScsiWrite16CommandEx (
4805 ScsiDiskDevice
->ScsiIo
,
4808 &Request
->SenseDataLength
,
4809 &Request
->HostAdapterStatus
,
4810 &Request
->TargetStatus
,
4812 &Request
->DataLength
,
4814 Request
->SectorCount
,
4817 if (EFI_ERROR(Status
)) {
4824 if (AsyncIoEvent
!= NULL
) {
4825 gBS
->CloseEvent (AsyncIoEvent
);
4828 if (Request
!= NULL
) {
4829 if (Request
->SenseData
!= NULL
) {
4830 FreePool (Request
->SenseData
);
4833 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4834 RemoveEntryList (&Request
->Link
);
4835 gBS
->RestoreTPL (OldTpl
);
4845 Check sense key to find if media presents.
4847 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4848 @param SenseCounts The number of sense key
4850 @retval TRUE NOT any media
4851 @retval FALSE Media presents
4855 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4856 IN UINTN SenseCounts
4859 EFI_SCSI_SENSE_DATA
*SensePtr
;
4864 SensePtr
= SenseData
;
4866 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4868 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
4869 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
4871 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
4872 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
4885 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4886 @param SenseCounts The number of sense key
4889 @retval FALSE NOT error
4893 ScsiDiskIsMediaError (
4894 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4895 IN UINTN SenseCounts
4898 EFI_SCSI_SENSE_DATA
*SensePtr
;
4903 SensePtr
= SenseData
;
4905 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4907 switch (SensePtr
->Sense_Key
) {
4909 case EFI_SCSI_SK_MEDIUM_ERROR
:
4911 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
4913 switch (SensePtr
->Addnl_Sense_Code
) {
4918 case EFI_SCSI_ASC_MEDIA_ERR1
:
4923 case EFI_SCSI_ASC_MEDIA_ERR2
:
4928 case EFI_SCSI_ASC_MEDIA_ERR3
:
4929 case EFI_SCSI_ASC_MEDIA_ERR4
:
4939 case EFI_SCSI_SK_NOT_READY
:
4941 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4943 switch (SensePtr
->Addnl_Sense_Code
) {
4945 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
4947 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
4968 Check sense key to find if hardware error happens.
4970 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4971 @param SenseCounts The number of sense key
4973 @retval TRUE Hardware error exits.
4974 @retval FALSE NO error.
4978 ScsiDiskIsHardwareError (
4979 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4980 IN UINTN SenseCounts
4983 EFI_SCSI_SENSE_DATA
*SensePtr
;
4988 SensePtr
= SenseData
;
4990 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4993 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
4995 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
5007 Check sense key to find if media has changed.
5009 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5010 @param SenseCounts The number of sense key
5012 @retval TRUE Media is changed.
5013 @retval FALSE Media is NOT changed.
5016 ScsiDiskIsMediaChange (
5017 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5018 IN UINTN SenseCounts
5021 EFI_SCSI_SENSE_DATA
*SensePtr
;
5023 BOOLEAN IsMediaChanged
;
5025 IsMediaChanged
= FALSE
;
5026 SensePtr
= SenseData
;
5028 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5030 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
5031 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
5033 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
5034 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
5035 IsMediaChanged
= TRUE
;
5041 return IsMediaChanged
;
5045 Check sense key to find if reset happens.
5047 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5048 @param SenseCounts The number of sense key
5050 @retval TRUE It is reset before.
5051 @retval FALSE It is NOT reset before.
5055 ScsiDiskIsResetBefore (
5056 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5057 IN UINTN SenseCounts
5060 EFI_SCSI_SENSE_DATA
*SensePtr
;
5062 BOOLEAN IsResetBefore
;
5064 IsResetBefore
= FALSE
;
5065 SensePtr
= SenseData
;
5067 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5070 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
5071 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
5073 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
5074 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
5075 IsResetBefore
= TRUE
;
5081 return IsResetBefore
;
5085 Check sense key to find if the drive is ready.
5087 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5088 @param SenseCounts The number of sense key
5089 @param RetryLater The flag means if need a retry
5091 @retval TRUE Drive is ready.
5092 @retval FALSE Drive is NOT ready.
5096 ScsiDiskIsDriveReady (
5097 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5098 IN UINTN SenseCounts
,
5099 OUT BOOLEAN
*RetryLater
5102 EFI_SCSI_SENSE_DATA
*SensePtr
;
5107 *RetryLater
= FALSE
;
5108 SensePtr
= SenseData
;
5110 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5112 switch (SensePtr
->Sense_Key
) {
5114 case EFI_SCSI_SK_NOT_READY
:
5116 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5118 switch (SensePtr
->Addnl_Sense_Code
) {
5119 case EFI_SCSI_ASC_NOT_READY
:
5121 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
5123 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
5124 case EFI_SCSI_ASCQ_IN_PROGRESS
:
5126 // Additional Sense Code Qualifier is
5127 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
5135 *RetryLater
= FALSE
;
5156 Check sense key to find if it has sense key.
5158 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
5159 @param SenseCounts - The number of sense key
5161 @retval TRUE It has sense key.
5162 @retval FALSE It has NOT any sense key.
5166 ScsiDiskHaveSenseKey (
5167 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5168 IN UINTN SenseCounts
5171 EFI_SCSI_SENSE_DATA
*SensePtr
;
5173 BOOLEAN HaveSenseKey
;
5175 if (SenseCounts
== 0) {
5176 HaveSenseKey
= FALSE
;
5178 HaveSenseKey
= TRUE
;
5181 SensePtr
= SenseData
;
5183 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5186 // Sense Key is SK_NO_SENSE (0x0)
5188 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
5190 HaveSenseKey
= FALSE
;
5196 return HaveSenseKey
;
5200 Release resource about disk device.
5202 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
5206 ReleaseScsiDiskDeviceResources (
5207 IN SCSI_DISK_DEV
*ScsiDiskDevice
5210 if (ScsiDiskDevice
== NULL
) {
5214 if (ScsiDiskDevice
->SenseData
!= NULL
) {
5215 FreePool (ScsiDiskDevice
->SenseData
);
5216 ScsiDiskDevice
->SenseData
= NULL
;
5219 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
5220 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
5221 ScsiDiskDevice
->ControllerNameTable
= NULL
;
5224 FreePool (ScsiDiskDevice
);
5226 ScsiDiskDevice
= NULL
;
5230 Determine if Block Io & Block Io2 should be produced.
5233 @param ChildHandle Child Handle to retrieve Parent information.
5235 @retval TRUE Should produce Block Io & Block Io2.
5236 @retval FALSE Should not produce Block Io & Block Io2.
5240 DetermineInstallBlockIo (
5241 IN EFI_HANDLE ChildHandle
5244 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
5245 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
5248 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
5249 // check its attribute, logic or physical.
5251 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
5252 if (ExtScsiPassThru
!= NULL
) {
5253 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
5259 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
5260 // check its attribute, logic or physical.
5262 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
5263 if (ScsiPassThru
!= NULL
) {
5264 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
5273 Search protocol database and check to see if the protocol
5274 specified by ProtocolGuid is present on a ControllerHandle and opened by
5275 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
5276 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
5277 will be opened on it.
5280 @param ProtocolGuid ProtocolGuid pointer.
5281 @param ChildHandle Child Handle to retrieve Parent information.
5287 IN EFI_GUID
*ProtocolGuid
,
5288 IN EFI_HANDLE ChildHandle
5295 EFI_HANDLE
*HandleBuffer
;
5298 // Retrieve the list of all handles from the handle database
5300 Status
= gBS
->LocateHandleBuffer (
5308 if (EFI_ERROR (Status
)) {
5313 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
5315 for (Index
= 0; Index
< HandleCount
; Index
++) {
5316 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
5317 if (!EFI_ERROR (Status
)) {
5318 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
5319 if (!EFI_ERROR (Status
)) {
5320 gBS
->FreePool (HandleBuffer
);
5326 gBS
->FreePool (HandleBuffer
);
5331 Determine if EFI Erase Block Protocol should be produced.
5333 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
5334 @param ChildHandle Handle of device.
5336 @retval TRUE Should produce EFI Erase Block Protocol.
5337 @retval FALSE Should not produce EFI Erase Block Protocol.
5341 DetermineInstallEraseBlock (
5342 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5343 IN EFI_HANDLE ChildHandle
5346 UINT8 HostAdapterStatus
;
5348 EFI_STATUS CommandStatus
;
5352 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
5353 UINT8 SenseDataLength
;
5354 UINT32 DataLength16
;
5355 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
5359 CapacityData16
= NULL
;
5361 Status
= gBS
->HandleProtocol (
5363 &gEfiDevicePathProtocolGuid
,
5364 (VOID
**) &DevicePathNode
5367 // Device Path protocol must be installed on the device handle.
5369 ASSERT_EFI_ERROR (Status
);
5371 while (!IsDevicePathEndType (DevicePathNode
)) {
5373 // For now, only support Erase Block Protocol on UFS devices.
5375 if ((DevicePathNode
->Type
== MESSAGING_DEVICE_PATH
) &&
5376 (DevicePathNode
->SubType
== MSG_UFS_DP
)) {
5381 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
5389 // Check whether the erase functionality is enabled on the UFS device.
5391 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
5392 if (CapacityData16
== NULL
) {
5397 SenseDataLength
= 0;
5398 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
5399 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
5401 CommandStatus
= ScsiReadCapacity16Command (
5402 ScsiDiskDevice
->ScsiIo
,
5408 (VOID
*) CapacityData16
,
5413 if (CommandStatus
== EFI_SUCCESS
) {
5415 // Universal Flash Storage (UFS) Version 2.0
5417 // Bits TPE and TPRZ should both be set to enable the erase feature on UFS.
5419 if (((CapacityData16
->LowestAlignLogic2
& BIT7
) == 0) ||
5420 ((CapacityData16
->LowestAlignLogic2
& BIT6
) == 0)) {
5423 "ScsiDisk EraseBlock: Either TPE or TPRZ is not set: 0x%x.\n",
5424 CapacityData16
->LowestAlignLogic2
5433 "ScsiDisk EraseBlock: ReadCapacity16 failed with status %r.\n",
5442 // Check whether the UFS device server implements the UNMAP command.
5444 if ((ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
== 0) ||
5445 (ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
== 0)) {
5448 "ScsiDisk EraseBlock: The device server does not implement the UNMAP command.\n"
5456 if (CapacityData16
!= NULL
) {
5457 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
5464 Provides inquiry information for the controller type.
5466 This function is used by the IDE bus driver to get inquiry data. Data format
5467 of Identify data is defined by the Interface GUID.
5469 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
5470 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
5471 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
5473 @retval EFI_SUCCESS The command was accepted without any errors.
5474 @retval EFI_NOT_FOUND Device does not support this data class
5475 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
5476 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
5481 ScsiDiskInfoInquiry (
5482 IN EFI_DISK_INFO_PROTOCOL
*This
,
5483 IN OUT VOID
*InquiryData
,
5484 IN OUT UINT32
*InquiryDataSize
5488 SCSI_DISK_DEV
*ScsiDiskDevice
;
5490 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
5492 Status
= EFI_BUFFER_TOO_SMALL
;
5493 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
5494 Status
= EFI_SUCCESS
;
5495 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
5497 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
5503 Provides identify information for the controller type.
5505 This function is used by the IDE bus driver to get identify data. Data format
5506 of Identify data is defined by the Interface GUID.
5508 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
5510 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
5511 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
5514 @retval EFI_SUCCESS The command was accepted without any errors.
5515 @retval EFI_NOT_FOUND Device does not support this data class
5516 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
5517 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
5522 ScsiDiskInfoIdentify (
5523 IN EFI_DISK_INFO_PROTOCOL
*This
,
5524 IN OUT VOID
*IdentifyData
,
5525 IN OUT UINT32
*IdentifyDataSize
5529 SCSI_DISK_DEV
*ScsiDiskDevice
;
5531 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
5533 // Physical SCSI bus does not support this data class.
5535 return EFI_NOT_FOUND
;
5538 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
5540 Status
= EFI_BUFFER_TOO_SMALL
;
5541 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
5542 Status
= EFI_SUCCESS
;
5543 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
5545 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
5550 Provides sense data information for the controller type.
5552 This function is used by the IDE bus driver to get sense data.
5553 Data format of Sense data is defined by the Interface GUID.
5555 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
5556 @param[in, out] SenseData Pointer to the SenseData.
5557 @param[in, out] SenseDataSize Size of SenseData in bytes.
5558 @param[out] SenseDataNumber Pointer to the value for the sense data size.
5560 @retval EFI_SUCCESS The command was accepted without any errors.
5561 @retval EFI_NOT_FOUND Device does not support this data class.
5562 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
5563 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
5568 ScsiDiskInfoSenseData (
5569 IN EFI_DISK_INFO_PROTOCOL
*This
,
5570 IN OUT VOID
*SenseData
,
5571 IN OUT UINT32
*SenseDataSize
,
5572 OUT UINT8
*SenseDataNumber
5575 return EFI_NOT_FOUND
;
5580 This function is used by the IDE bus driver to get controller information.
5582 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
5583 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
5584 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
5586 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
5587 @retval EFI_UNSUPPORTED This is not an IDE device.
5592 ScsiDiskInfoWhichIde (
5593 IN EFI_DISK_INFO_PROTOCOL
*This
,
5594 OUT UINT32
*IdeChannel
,
5595 OUT UINT32
*IdeDevice
5598 SCSI_DISK_DEV
*ScsiDiskDevice
;
5600 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
5602 // This is not an IDE physical device.
5604 return EFI_UNSUPPORTED
;
5607 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
5608 *IdeChannel
= ScsiDiskDevice
->Channel
;
5609 *IdeDevice
= ScsiDiskDevice
->Device
;
5616 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
5618 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
5619 implement Identify() interface for DiskInfo protocol. The ATA command is sent
5620 via SCSI Request Packet.
5622 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
5624 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
5625 @retval others Some error occurred during the identification that ATAPI device.
5629 AtapiIdentifyDevice (
5630 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
5633 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
5637 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
5639 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
5640 ZeroMem (Cdb
, sizeof (Cdb
));
5642 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
5643 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
5644 CommandPacket
.Cdb
= Cdb
;
5645 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
5646 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
5647 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
5649 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
5654 Initialize the installation of DiskInfo protocol.
5656 This function prepares for the installation of DiskInfo protocol on the child handle.
5657 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
5658 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
5659 to be IDE/AHCI interface GUID.
5661 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
5662 @param ChildHandle Child handle to install DiskInfo protocol.
5666 InitializeInstallDiskInfo (
5667 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5668 IN EFI_HANDLE ChildHandle
5672 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
5673 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
5674 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
5675 SATA_DEVICE_PATH
*SataDevicePath
;
5676 UINTN IdentifyRetry
;
5678 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
5680 // Device Path protocol must be installed on the device handle.
5682 ASSERT_EFI_ERROR (Status
);
5684 // Copy the DiskInfo protocol template.
5686 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
5688 while (!IsDevicePathEnd (DevicePathNode
)) {
5689 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
5690 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
5691 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
5692 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
5693 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
5694 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
5699 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
5700 // with IDE/AHCI interface GUID.
5702 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
5703 if (!EFI_ERROR (Status
)) {
5704 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
5706 // We find the valid ATAPI device path
5708 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
5709 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
5710 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
5712 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
5714 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
5717 // We find the valid SATA device path
5719 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
5720 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
5721 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
5723 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
5725 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
5729 } while (--IdentifyRetry
> 0);
5730 } else if ((DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
5731 (DevicePathSubType (ChildDevicePathNode
) == MSG_UFS_DP
)) {
5732 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoUfsInterfaceGuid
);
5735 DevicePathNode
= ChildDevicePathNode
;