2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding
= {
19 ScsiDiskDriverBindingSupported
,
20 ScsiDiskDriverBindingStart
,
21 ScsiDiskDriverBindingStop
,
27 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate
= {
28 EFI_DISK_INFO_SCSI_INTERFACE_GUID
,
31 ScsiDiskInfoSenseData
,
36 Allocates an aligned buffer for SCSI disk.
38 This function allocates an aligned buffer for the SCSI disk to perform
39 SCSI IO operations. The alignment requirement is from SCSI IO interface.
41 @param ScsiDiskDevice The SCSI disk involved for the operation.
42 @param BufferSize The request buffer size.
44 @return A pointer to the aligned buffer or NULL if the allocation fails.
48 AllocateAlignedBuffer (
49 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
53 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), ScsiDiskDevice
->ScsiIo
->IoAlign
);
57 Frees an aligned buffer for SCSI disk.
59 This function frees an aligned buffer for the SCSI disk to perform
62 @param Buffer The aligned buffer to be freed.
63 @param BufferSize The request buffer size.
73 FreeAlignedPages (Buffer
, EFI_SIZE_TO_PAGES (BufferSize
));
78 The user Entry Point for module ScsiDisk.
80 The user code starts with this function.
82 @param ImageHandle The firmware allocated handle for the EFI image.
83 @param SystemTable A pointer to the EFI System Table.
85 @retval EFI_SUCCESS The entry point is executed successfully.
86 @retval other Some error occurs when executing this entry point.
92 IN EFI_HANDLE ImageHandle
,
93 IN EFI_SYSTEM_TABLE
*SystemTable
99 // Install driver model protocol(s).
101 Status
= EfiLibInstallDriverBindingComponentName2 (
104 &gScsiDiskDriverBinding
,
106 &gScsiDiskComponentName
,
107 &gScsiDiskComponentName2
109 ASSERT_EFI_ERROR (Status
);
116 Test to see if this driver supports ControllerHandle.
118 This service is called by the EFI boot service ConnectController(). In order
119 to make drivers as small as possible, there are a few calling restrictions for
120 this service. ConnectController() must follow these calling restrictions.
121 If any other agent wishes to call Supported() it must also follow these
122 calling restrictions.
124 @param This Protocol instance pointer.
125 @param ControllerHandle Handle of device to test
126 @param RemainingDevicePath Optional parameter use to pick a specific child
129 @retval EFI_SUCCESS This driver supports this device
130 @retval EFI_ALREADY_STARTED This driver is already running on this device
131 @retval other This driver does not support this device
136 ScsiDiskDriverBindingSupported (
137 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
138 IN EFI_HANDLE Controller
,
139 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
143 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
146 Status
= gBS
->OpenProtocol (
148 &gEfiScsiIoProtocolGuid
,
150 This
->DriverBindingHandle
,
152 EFI_OPEN_PROTOCOL_BY_DRIVER
154 if (EFI_ERROR (Status
)) {
158 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
159 if (!EFI_ERROR (Status
)) {
160 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) || (DeviceType
== EFI_SCSI_TYPE_CDROM
)) {
161 Status
= EFI_SUCCESS
;
163 Status
= EFI_UNSUPPORTED
;
169 &gEfiScsiIoProtocolGuid
,
170 This
->DriverBindingHandle
,
178 Start this driver on ControllerHandle.
180 This service is called by the EFI boot service ConnectController(). In order
181 to make drivers as small as possible, there are a few calling restrictions for
182 this service. ConnectController() must follow these calling restrictions. If
183 any other agent wishes to call Start() it must also follow these calling
186 @param This Protocol instance pointer.
187 @param ControllerHandle Handle of device to bind driver to
188 @param RemainingDevicePath Optional parameter use to pick a specific child
191 @retval EFI_SUCCESS This driver is added to ControllerHandle
192 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
193 @retval other This driver does not support this device
198 ScsiDiskDriverBindingStart (
199 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
200 IN EFI_HANDLE Controller
,
201 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
205 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
206 SCSI_DISK_DEV
*ScsiDiskDevice
;
211 BOOLEAN MustReadCapacity
;
213 MustReadCapacity
= TRUE
;
215 ScsiDiskDevice
= (SCSI_DISK_DEV
*) AllocateZeroPool (sizeof (SCSI_DISK_DEV
));
216 if (ScsiDiskDevice
== NULL
) {
217 return EFI_OUT_OF_RESOURCES
;
220 Status
= gBS
->OpenProtocol (
222 &gEfiScsiIoProtocolGuid
,
224 This
->DriverBindingHandle
,
226 EFI_OPEN_PROTOCOL_BY_DRIVER
228 if (EFI_ERROR (Status
)) {
229 FreePool (ScsiDiskDevice
);
233 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
234 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
235 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION3
;
236 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
237 ScsiDiskDevice
->BlkIo
.Media
->IoAlign
= ScsiIo
->IoAlign
;
238 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
239 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
240 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
241 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
242 ScsiDiskDevice
->BlkIo2
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
243 ScsiDiskDevice
->BlkIo2
.Reset
= ScsiDiskResetEx
;
244 ScsiDiskDevice
->BlkIo2
.ReadBlocksEx
= ScsiDiskReadBlocksEx
;
245 ScsiDiskDevice
->BlkIo2
.WriteBlocksEx
= ScsiDiskWriteBlocksEx
;
246 ScsiDiskDevice
->BlkIo2
.FlushBlocksEx
= ScsiDiskFlushBlocksEx
;
247 ScsiDiskDevice
->EraseBlock
.Revision
= EFI_ERASE_BLOCK_PROTOCOL_REVISION
;
248 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
= 1;
249 ScsiDiskDevice
->EraseBlock
.EraseBlocks
= ScsiDiskEraseBlocks
;
250 ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
= 1;
251 ScsiDiskDevice
->BlockLimitsVpdSupported
= FALSE
;
252 ScsiDiskDevice
->Handle
= Controller
;
253 InitializeListHead (&ScsiDiskDevice
->AsyncTaskQueue
);
255 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
256 switch (ScsiDiskDevice
->DeviceType
) {
257 case EFI_SCSI_TYPE_DISK
:
258 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
259 MustReadCapacity
= TRUE
;
262 case EFI_SCSI_TYPE_CDROM
:
263 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
264 ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
= TRUE
;
265 MustReadCapacity
= FALSE
;
269 // The Sense Data Array's initial size is 6
271 ScsiDiskDevice
->SenseDataNumber
= 6;
272 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
273 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
275 if (ScsiDiskDevice
->SenseData
== NULL
) {
278 &gEfiScsiIoProtocolGuid
,
279 This
->DriverBindingHandle
,
282 FreePool (ScsiDiskDevice
);
283 return EFI_OUT_OF_RESOURCES
;
287 // Retrieve device information
290 for (Index
= 0; Index
< MaxRetry
; Index
++) {
291 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
292 if (!EFI_ERROR (Status
)) {
297 FreePool (ScsiDiskDevice
->SenseData
);
300 &gEfiScsiIoProtocolGuid
,
301 This
->DriverBindingHandle
,
304 FreePool (ScsiDiskDevice
);
305 return EFI_DEVICE_ERROR
;
309 // The second parameter "TRUE" means must
310 // retrieve media capacity
312 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, MustReadCapacity
, &Temp
);
313 if (!EFI_ERROR (Status
)) {
315 // Determine if Block IO & Block IO2 should be produced on this controller
318 if (DetermineInstallBlockIo(Controller
)) {
319 InitializeInstallDiskInfo(ScsiDiskDevice
, Controller
);
320 Status
= gBS
->InstallMultipleProtocolInterfaces (
322 &gEfiBlockIoProtocolGuid
,
323 &ScsiDiskDevice
->BlkIo
,
324 &gEfiBlockIo2ProtocolGuid
,
325 &ScsiDiskDevice
->BlkIo2
,
326 &gEfiDiskInfoProtocolGuid
,
327 &ScsiDiskDevice
->DiskInfo
,
330 if (!EFI_ERROR(Status
)) {
331 if (DetermineInstallEraseBlock(ScsiDiskDevice
, Controller
)) {
332 Status
= gBS
->InstallProtocolInterface (
334 &gEfiEraseBlockProtocolGuid
,
335 EFI_NATIVE_INTERFACE
,
336 &ScsiDiskDevice
->EraseBlock
338 if (EFI_ERROR(Status
)) {
339 DEBUG ((EFI_D_ERROR
, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", Status
));
342 ScsiDiskDevice
->ControllerNameTable
= NULL
;
345 gScsiDiskComponentName
.SupportedLanguages
,
346 &ScsiDiskDevice
->ControllerNameTable
,
352 gScsiDiskComponentName2
.SupportedLanguages
,
353 &ScsiDiskDevice
->ControllerNameTable
,
362 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
363 gBS
->FreePool (ScsiDiskDevice
);
366 &gEfiScsiIoProtocolGuid
,
367 This
->DriverBindingHandle
,
376 Stop this driver on ControllerHandle.
378 This service is called by the EFI boot service DisconnectController().
379 In order to make drivers as small as possible, there are a few calling
380 restrictions for this service. DisconnectController() must follow these
381 calling restrictions. If any other agent wishes to call Stop() it must
382 also follow these calling restrictions.
384 @param This Protocol instance pointer.
385 @param ControllerHandle Handle of device to stop driver on
386 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
387 children is zero stop the entire bus driver.
388 @param ChildHandleBuffer List of Child Handles to Stop.
390 @retval EFI_SUCCESS This driver is removed ControllerHandle
391 @retval other This driver was not removed from this device
396 ScsiDiskDriverBindingStop (
397 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
398 IN EFI_HANDLE Controller
,
399 IN UINTN NumberOfChildren
,
400 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
403 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
404 EFI_ERASE_BLOCK_PROTOCOL
*EraseBlock
;
405 SCSI_DISK_DEV
*ScsiDiskDevice
;
408 Status
= gBS
->OpenProtocol (
410 &gEfiBlockIoProtocolGuid
,
412 This
->DriverBindingHandle
,
414 EFI_OPEN_PROTOCOL_GET_PROTOCOL
416 if (EFI_ERROR (Status
)) {
420 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (BlkIo
);
423 // Wait for the BlockIo2 requests queue to become empty
425 while (!IsListEmpty (&ScsiDiskDevice
->AsyncTaskQueue
));
428 // If Erase Block Protocol is installed, then uninstall this protocol.
430 Status
= gBS
->OpenProtocol (
432 &gEfiEraseBlockProtocolGuid
,
433 (VOID
**) &EraseBlock
,
434 This
->DriverBindingHandle
,
436 EFI_OPEN_PROTOCOL_GET_PROTOCOL
439 if (!EFI_ERROR (Status
)) {
440 Status
= gBS
->UninstallProtocolInterface (
442 &gEfiEraseBlockProtocolGuid
,
443 &ScsiDiskDevice
->EraseBlock
445 if (EFI_ERROR (Status
)) {
450 Status
= gBS
->UninstallMultipleProtocolInterfaces (
452 &gEfiBlockIoProtocolGuid
,
453 &ScsiDiskDevice
->BlkIo
,
454 &gEfiBlockIo2ProtocolGuid
,
455 &ScsiDiskDevice
->BlkIo2
,
456 &gEfiDiskInfoProtocolGuid
,
457 &ScsiDiskDevice
->DiskInfo
,
460 if (!EFI_ERROR (Status
)) {
463 &gEfiScsiIoProtocolGuid
,
464 This
->DriverBindingHandle
,
468 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
482 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
483 @param ExtendedVerification The flag about if extend verificate
485 @retval EFI_SUCCESS The device was reset.
486 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
488 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
494 IN EFI_BLOCK_IO_PROTOCOL
*This
,
495 IN BOOLEAN ExtendedVerification
499 SCSI_DISK_DEV
*ScsiDiskDevice
;
502 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
504 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
506 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
508 if (EFI_ERROR (Status
)) {
509 if (Status
== EFI_UNSUPPORTED
) {
510 Status
= EFI_SUCCESS
;
512 Status
= EFI_DEVICE_ERROR
;
517 if (!ExtendedVerification
) {
521 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
523 if (EFI_ERROR (Status
)) {
524 Status
= EFI_DEVICE_ERROR
;
529 gBS
->RestoreTPL (OldTpl
);
534 The function is to Read Block from SCSI Disk.
536 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
537 @param MediaId The Id of Media detected
538 @param Lba The logic block address
539 @param BufferSize The size of Buffer
540 @param Buffer The buffer to fill the read out data
542 @retval EFI_SUCCESS Successfully to read out block.
543 @retval EFI_DEVICE_ERROR Fail to detect media.
544 @retval EFI_NO_MEDIA Media is not present.
545 @retval EFI_MEDIA_CHANGED Media has changed.
546 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
547 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
553 IN EFI_BLOCK_IO_PROTOCOL
*This
,
560 SCSI_DISK_DEV
*ScsiDiskDevice
;
561 EFI_BLOCK_IO_MEDIA
*Media
;
564 UINTN NumberOfBlocks
;
569 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
570 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
572 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
574 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
575 if (EFI_ERROR (Status
)) {
576 Status
= EFI_DEVICE_ERROR
;
581 gBS
->ReinstallProtocolInterface (
582 ScsiDiskDevice
->Handle
,
583 &gEfiBlockIoProtocolGuid
,
584 &ScsiDiskDevice
->BlkIo
,
585 &ScsiDiskDevice
->BlkIo
587 gBS
->ReinstallProtocolInterface (
588 ScsiDiskDevice
->Handle
,
589 &gEfiBlockIo2ProtocolGuid
,
590 &ScsiDiskDevice
->BlkIo2
,
591 &ScsiDiskDevice
->BlkIo2
593 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
594 gBS
->ReinstallProtocolInterface (
595 ScsiDiskDevice
->Handle
,
596 &gEfiEraseBlockProtocolGuid
,
597 &ScsiDiskDevice
->EraseBlock
,
598 &ScsiDiskDevice
->EraseBlock
601 Status
= EFI_MEDIA_CHANGED
;
606 // Get the intrinsic block size
608 Media
= ScsiDiskDevice
->BlkIo
.Media
;
609 BlockSize
= Media
->BlockSize
;
611 NumberOfBlocks
= BufferSize
/ BlockSize
;
613 if (!(Media
->MediaPresent
)) {
614 Status
= EFI_NO_MEDIA
;
618 if (MediaId
!= Media
->MediaId
) {
619 Status
= EFI_MEDIA_CHANGED
;
623 if (Buffer
== NULL
) {
624 Status
= EFI_INVALID_PARAMETER
;
628 if (BufferSize
== 0) {
629 Status
= EFI_SUCCESS
;
633 if (BufferSize
% BlockSize
!= 0) {
634 Status
= EFI_BAD_BUFFER_SIZE
;
638 if (Lba
> Media
->LastBlock
) {
639 Status
= EFI_INVALID_PARAMETER
;
643 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
644 Status
= EFI_INVALID_PARAMETER
;
648 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
649 Status
= EFI_INVALID_PARAMETER
;
654 // If all the parameters are valid, then perform read sectors command
655 // to transfer data from device to host.
657 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
660 gBS
->RestoreTPL (OldTpl
);
665 The function is to Write Block to SCSI Disk.
667 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
668 @param MediaId The Id of Media detected
669 @param Lba The logic block address
670 @param BufferSize The size of Buffer
671 @param Buffer The buffer to fill the read out data
673 @retval EFI_SUCCESS Successfully to read out block.
674 @retval EFI_WRITE_PROTECTED The device can not be written to.
675 @retval EFI_DEVICE_ERROR Fail to detect media.
676 @retval EFI_NO_MEDIA Media is not present.
677 @retval EFI_MEDIA_CHNAGED Media has changed.
678 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
679 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
684 ScsiDiskWriteBlocks (
685 IN EFI_BLOCK_IO_PROTOCOL
*This
,
692 SCSI_DISK_DEV
*ScsiDiskDevice
;
693 EFI_BLOCK_IO_MEDIA
*Media
;
696 UINTN NumberOfBlocks
;
701 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
702 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
704 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
706 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
707 if (EFI_ERROR (Status
)) {
708 Status
= EFI_DEVICE_ERROR
;
713 gBS
->ReinstallProtocolInterface (
714 ScsiDiskDevice
->Handle
,
715 &gEfiBlockIoProtocolGuid
,
716 &ScsiDiskDevice
->BlkIo
,
717 &ScsiDiskDevice
->BlkIo
719 gBS
->ReinstallProtocolInterface (
720 ScsiDiskDevice
->Handle
,
721 &gEfiBlockIo2ProtocolGuid
,
722 &ScsiDiskDevice
->BlkIo2
,
723 &ScsiDiskDevice
->BlkIo2
725 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
726 gBS
->ReinstallProtocolInterface (
727 ScsiDiskDevice
->Handle
,
728 &gEfiEraseBlockProtocolGuid
,
729 &ScsiDiskDevice
->EraseBlock
,
730 &ScsiDiskDevice
->EraseBlock
733 Status
= EFI_MEDIA_CHANGED
;
738 // Get the intrinsic block size
740 Media
= ScsiDiskDevice
->BlkIo
.Media
;
741 BlockSize
= Media
->BlockSize
;
743 NumberOfBlocks
= BufferSize
/ BlockSize
;
745 if (!(Media
->MediaPresent
)) {
746 Status
= EFI_NO_MEDIA
;
750 if (MediaId
!= Media
->MediaId
) {
751 Status
= EFI_MEDIA_CHANGED
;
755 if (Media
->ReadOnly
) {
756 Status
= EFI_WRITE_PROTECTED
;
760 if (BufferSize
== 0) {
761 Status
= EFI_SUCCESS
;
765 if (Buffer
== NULL
) {
766 Status
= EFI_INVALID_PARAMETER
;
770 if (BufferSize
% BlockSize
!= 0) {
771 Status
= EFI_BAD_BUFFER_SIZE
;
775 if (Lba
> Media
->LastBlock
) {
776 Status
= EFI_INVALID_PARAMETER
;
780 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
781 Status
= EFI_INVALID_PARAMETER
;
785 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
786 Status
= EFI_INVALID_PARAMETER
;
790 // if all the parameters are valid, then perform read sectors command
791 // to transfer data from device to host.
793 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
796 gBS
->RestoreTPL (OldTpl
);
803 EFI_SUCCESS is returned directly.
805 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
807 @retval EFI_SUCCESS All outstanding data was written to the device
812 ScsiDiskFlushBlocks (
813 IN EFI_BLOCK_IO_PROTOCOL
*This
826 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
827 @param ExtendedVerification The flag about if extend verificate.
829 @retval EFI_SUCCESS The device was reset.
830 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
832 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
838 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
839 IN BOOLEAN ExtendedVerification
843 SCSI_DISK_DEV
*ScsiDiskDevice
;
846 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
848 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
850 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
852 if (EFI_ERROR (Status
)) {
853 if (Status
== EFI_UNSUPPORTED
) {
854 Status
= EFI_SUCCESS
;
856 Status
= EFI_DEVICE_ERROR
;
861 if (!ExtendedVerification
) {
865 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
867 if (EFI_ERROR (Status
)) {
868 Status
= EFI_DEVICE_ERROR
;
873 gBS
->RestoreTPL (OldTpl
);
878 The function is to Read Block from SCSI Disk.
880 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
881 @param MediaId The Id of Media detected.
882 @param Lba The logic block address.
883 @param Token A pointer to the token associated with the transaction.
884 @param BufferSize The size of Buffer.
885 @param Buffer The buffer to fill the read out data.
887 @retval EFI_SUCCESS The read request was queued if Token-> Event is
888 not NULL. The data was read correctly from the
889 device if theToken-> Event is NULL.
890 @retval EFI_DEVICE_ERROR The device reported an error while attempting
891 to perform the read operation.
892 @retval EFI_NO_MEDIA There is no media in the device.
893 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
894 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
895 the intrinsic block size of the device.
896 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
897 valid, or the buffer is not on proper
899 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
905 ScsiDiskReadBlocksEx (
906 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
909 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
914 SCSI_DISK_DEV
*ScsiDiskDevice
;
915 EFI_BLOCK_IO_MEDIA
*Media
;
918 UINTN NumberOfBlocks
;
923 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
924 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
926 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
928 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
929 if (EFI_ERROR (Status
)) {
930 Status
= EFI_DEVICE_ERROR
;
935 gBS
->ReinstallProtocolInterface (
936 ScsiDiskDevice
->Handle
,
937 &gEfiBlockIoProtocolGuid
,
938 &ScsiDiskDevice
->BlkIo
,
939 &ScsiDiskDevice
->BlkIo
941 gBS
->ReinstallProtocolInterface (
942 ScsiDiskDevice
->Handle
,
943 &gEfiBlockIo2ProtocolGuid
,
944 &ScsiDiskDevice
->BlkIo2
,
945 &ScsiDiskDevice
->BlkIo2
947 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
948 gBS
->ReinstallProtocolInterface (
949 ScsiDiskDevice
->Handle
,
950 &gEfiEraseBlockProtocolGuid
,
951 &ScsiDiskDevice
->EraseBlock
,
952 &ScsiDiskDevice
->EraseBlock
955 Status
= EFI_MEDIA_CHANGED
;
960 // Get the intrinsic block size
962 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
963 BlockSize
= Media
->BlockSize
;
965 NumberOfBlocks
= BufferSize
/ BlockSize
;
967 if (!(Media
->MediaPresent
)) {
968 Status
= EFI_NO_MEDIA
;
972 if (MediaId
!= Media
->MediaId
) {
973 Status
= EFI_MEDIA_CHANGED
;
977 if (Buffer
== NULL
) {
978 Status
= EFI_INVALID_PARAMETER
;
982 if (BufferSize
== 0) {
983 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
984 Token
->TransactionStatus
= EFI_SUCCESS
;
985 gBS
->SignalEvent (Token
->Event
);
988 Status
= EFI_SUCCESS
;
992 if (BufferSize
% BlockSize
!= 0) {
993 Status
= EFI_BAD_BUFFER_SIZE
;
997 if (Lba
> Media
->LastBlock
) {
998 Status
= EFI_INVALID_PARAMETER
;
1002 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1003 Status
= EFI_INVALID_PARAMETER
;
1007 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1008 Status
= EFI_INVALID_PARAMETER
;
1013 // If all the parameters are valid, then perform read sectors command
1014 // to transfer data from device to host.
1016 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1017 Token
->TransactionStatus
= EFI_SUCCESS
;
1018 Status
= ScsiDiskAsyncReadSectors (
1026 Status
= ScsiDiskReadSectors (
1035 gBS
->RestoreTPL (OldTpl
);
1040 The function is to Write Block to SCSI Disk.
1042 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
1043 @param MediaId The Id of Media detected.
1044 @param Lba The logic block address.
1045 @param Token A pointer to the token associated with the transaction.
1046 @param BufferSize The size of Buffer.
1047 @param Buffer The buffer to fill the read out data.
1049 @retval EFI_SUCCESS The data were written correctly to the device.
1050 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1051 @retval EFI_NO_MEDIA There is no media in the device.
1052 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1053 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1054 to perform the write operation.
1055 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
1056 the intrinsic block size of the device.
1057 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
1058 valid, or the buffer is not on proper
1064 ScsiDiskWriteBlocksEx (
1065 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1068 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1069 IN UINTN BufferSize
,
1073 SCSI_DISK_DEV
*ScsiDiskDevice
;
1074 EFI_BLOCK_IO_MEDIA
*Media
;
1077 UINTN NumberOfBlocks
;
1078 BOOLEAN MediaChange
;
1081 MediaChange
= FALSE
;
1082 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1083 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1085 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1087 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1088 if (EFI_ERROR (Status
)) {
1089 Status
= EFI_DEVICE_ERROR
;
1094 gBS
->ReinstallProtocolInterface (
1095 ScsiDiskDevice
->Handle
,
1096 &gEfiBlockIoProtocolGuid
,
1097 &ScsiDiskDevice
->BlkIo
,
1098 &ScsiDiskDevice
->BlkIo
1100 gBS
->ReinstallProtocolInterface (
1101 ScsiDiskDevice
->Handle
,
1102 &gEfiBlockIo2ProtocolGuid
,
1103 &ScsiDiskDevice
->BlkIo2
,
1104 &ScsiDiskDevice
->BlkIo2
1106 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1107 gBS
->ReinstallProtocolInterface (
1108 ScsiDiskDevice
->Handle
,
1109 &gEfiEraseBlockProtocolGuid
,
1110 &ScsiDiskDevice
->EraseBlock
,
1111 &ScsiDiskDevice
->EraseBlock
1114 Status
= EFI_MEDIA_CHANGED
;
1119 // Get the intrinsic block size
1121 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
1122 BlockSize
= Media
->BlockSize
;
1124 NumberOfBlocks
= BufferSize
/ BlockSize
;
1126 if (!(Media
->MediaPresent
)) {
1127 Status
= EFI_NO_MEDIA
;
1131 if (MediaId
!= Media
->MediaId
) {
1132 Status
= EFI_MEDIA_CHANGED
;
1136 if (Media
->ReadOnly
) {
1137 Status
= EFI_WRITE_PROTECTED
;
1141 if (BufferSize
== 0) {
1142 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1143 Token
->TransactionStatus
= EFI_SUCCESS
;
1144 gBS
->SignalEvent (Token
->Event
);
1147 Status
= EFI_SUCCESS
;
1151 if (Buffer
== NULL
) {
1152 Status
= EFI_INVALID_PARAMETER
;
1156 if (BufferSize
% BlockSize
!= 0) {
1157 Status
= EFI_BAD_BUFFER_SIZE
;
1161 if (Lba
> Media
->LastBlock
) {
1162 Status
= EFI_INVALID_PARAMETER
;
1166 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1167 Status
= EFI_INVALID_PARAMETER
;
1171 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1172 Status
= EFI_INVALID_PARAMETER
;
1177 // if all the parameters are valid, then perform write sectors command
1178 // to transfer data from device to host.
1180 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1181 Token
->TransactionStatus
= EFI_SUCCESS
;
1182 Status
= ScsiDiskAsyncWriteSectors (
1190 Status
= ScsiDiskWriteSectors (
1199 gBS
->RestoreTPL (OldTpl
);
1204 Flush the Block Device.
1206 @param This Indicates a pointer to the calling context.
1207 @param Token A pointer to the token associated with the transaction.
1209 @retval EFI_SUCCESS All outstanding data was written to the device.
1210 @retval EFI_DEVICE_ERROR The device reported an error while attempting to
1212 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1213 @retval EFI_NO_MEDIA There is no media in the device.
1214 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1219 ScsiDiskFlushBlocksEx (
1220 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1221 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1224 SCSI_DISK_DEV
*ScsiDiskDevice
;
1225 EFI_BLOCK_IO_MEDIA
*Media
;
1227 BOOLEAN MediaChange
;
1230 MediaChange
= FALSE
;
1231 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1232 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1234 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1236 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1237 if (EFI_ERROR (Status
)) {
1238 Status
= EFI_DEVICE_ERROR
;
1243 gBS
->ReinstallProtocolInterface (
1244 ScsiDiskDevice
->Handle
,
1245 &gEfiBlockIoProtocolGuid
,
1246 &ScsiDiskDevice
->BlkIo
,
1247 &ScsiDiskDevice
->BlkIo
1249 gBS
->ReinstallProtocolInterface (
1250 ScsiDiskDevice
->Handle
,
1251 &gEfiBlockIo2ProtocolGuid
,
1252 &ScsiDiskDevice
->BlkIo2
,
1253 &ScsiDiskDevice
->BlkIo2
1255 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1256 gBS
->ReinstallProtocolInterface (
1257 ScsiDiskDevice
->Handle
,
1258 &gEfiEraseBlockProtocolGuid
,
1259 &ScsiDiskDevice
->EraseBlock
,
1260 &ScsiDiskDevice
->EraseBlock
1263 Status
= EFI_MEDIA_CHANGED
;
1268 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
1270 if (!(Media
->MediaPresent
)) {
1271 Status
= EFI_NO_MEDIA
;
1275 if (Media
->ReadOnly
) {
1276 Status
= EFI_WRITE_PROTECTED
;
1281 // Wait for the BlockIo2 requests queue to become empty
1283 while (!IsListEmpty (&ScsiDiskDevice
->AsyncTaskQueue
));
1285 Status
= EFI_SUCCESS
;
1288 // Signal caller event
1290 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1291 Token
->TransactionStatus
= EFI_SUCCESS
;
1292 gBS
->SignalEvent (Token
->Event
);
1296 gBS
->RestoreTPL (OldTpl
);
1302 Internal helper notify function which process the result of an asynchronous
1303 SCSI UNMAP Command and signal the event passed from EraseBlocks.
1305 @param Event The instance of EFI_EVENT.
1306 @param Context The parameter passed in.
1311 ScsiDiskAsyncUnmapNotify (
1316 SCSI_ERASEBLK_REQUEST
*EraseBlkReq
;
1317 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*CommandPacket
;
1318 EFI_ERASE_BLOCK_TOKEN
*Token
;
1321 gBS
->CloseEvent (Event
);
1323 EraseBlkReq
= (SCSI_ERASEBLK_REQUEST
*) Context
;
1324 CommandPacket
= &EraseBlkReq
->CommandPacket
;
1325 Token
= EraseBlkReq
->Token
;
1326 Token
->TransactionStatus
= EFI_SUCCESS
;
1328 Status
= CheckHostAdapterStatus (CommandPacket
->HostAdapterStatus
);
1329 if (EFI_ERROR(Status
)) {
1332 "ScsiDiskAsyncUnmapNotify: Host adapter indicating error status 0x%x.\n",
1333 CommandPacket
->HostAdapterStatus
1336 Token
->TransactionStatus
= Status
;
1340 Status
= CheckTargetStatus (CommandPacket
->TargetStatus
);
1341 if (EFI_ERROR(Status
)) {
1344 "ScsiDiskAsyncUnmapNotify: Target indicating error status 0x%x.\n",
1345 CommandPacket
->HostAdapterStatus
1348 Token
->TransactionStatus
= Status
;
1353 RemoveEntryList (&EraseBlkReq
->Link
);
1354 FreePool (CommandPacket
->OutDataBuffer
);
1355 FreePool (EraseBlkReq
->CommandPacket
.Cdb
);
1356 FreePool (EraseBlkReq
);
1358 gBS
->SignalEvent (Token
->Event
);
1362 Require the device server to cause one or more LBAs to be unmapped.
1364 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
1365 @param Lba The start block number.
1366 @param Blocks Total block number to be unmapped.
1367 @param Token The pointer to the token associated with the
1368 non-blocking erase block request.
1370 @retval EFI_SUCCESS Target blocks have been successfully unmapped.
1371 @retval EFI_DEVICE_ERROR Fail to unmap the target blocks.
1376 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1379 IN EFI_ERASE_BLOCK_TOKEN
*Token OPTIONAL
1382 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
1383 SCSI_ERASEBLK_REQUEST
*EraseBlkReq
;
1384 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*CommandPacket
;
1385 EFI_SCSI_DISK_UNMAP_BLOCK_DESP
*BlkDespPtr
;
1387 EFI_STATUS ReturnStatus
;
1390 UINT32 MaxBlkDespCnt
;
1392 UINT16 UnmapParamListLen
;
1393 VOID
*UnmapParamList
;
1394 EFI_EVENT AsyncUnmapEvent
;
1397 ScsiIo
= ScsiDiskDevice
->ScsiIo
;
1398 MaxLbaCnt
= ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
;
1399 MaxBlkDespCnt
= ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
;
1401 UnmapParamList
= NULL
;
1402 AsyncUnmapEvent
= NULL
;
1403 ReturnStatus
= EFI_SUCCESS
;
1405 if (Blocks
/ (UINTN
) MaxLbaCnt
> MaxBlkDespCnt
) {
1406 ReturnStatus
= EFI_DEVICE_ERROR
;
1410 EraseBlkReq
= AllocateZeroPool (sizeof (SCSI_ERASEBLK_REQUEST
));
1411 if (EraseBlkReq
== NULL
) {
1412 ReturnStatus
= EFI_DEVICE_ERROR
;
1416 EraseBlkReq
->CommandPacket
.Cdb
= AllocateZeroPool (0xA);
1417 if (EraseBlkReq
->CommandPacket
.Cdb
== NULL
) {
1418 ReturnStatus
= EFI_DEVICE_ERROR
;
1422 BlkDespCnt
= (UINT32
) ((Blocks
- 1) / MaxLbaCnt
+ 1);
1423 UnmapParamListLen
= (UINT16
) (sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
)
1424 + BlkDespCnt
* sizeof (EFI_SCSI_DISK_UNMAP_BLOCK_DESP
));
1425 UnmapParamList
= AllocateZeroPool (UnmapParamListLen
);
1426 if (UnmapParamList
== NULL
) {
1427 ReturnStatus
= EFI_DEVICE_ERROR
;
1431 *((UINT16
*)UnmapParamList
) = SwapBytes16 (UnmapParamListLen
- 2);
1432 *((UINT16
*)UnmapParamList
+ 1) = SwapBytes16 (UnmapParamListLen
- sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
));
1434 BlkDespPtr
= (EFI_SCSI_DISK_UNMAP_BLOCK_DESP
*)((UINT8
*)UnmapParamList
+ sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
));
1435 while (Blocks
> 0) {
1436 if (Blocks
> MaxLbaCnt
) {
1437 *(UINT64
*)(&BlkDespPtr
->Lba
) = SwapBytes64 (Lba
);
1438 *(UINT32
*)(&BlkDespPtr
->BlockNum
) = SwapBytes32 (MaxLbaCnt
);
1439 Blocks
-= MaxLbaCnt
;
1442 *(UINT64
*)(&BlkDespPtr
->Lba
) = SwapBytes64 (Lba
);
1443 *(UINT32
*)(&BlkDespPtr
->BlockNum
) = SwapBytes32 ((UINT32
) Blocks
);
1450 CommandPacket
= &EraseBlkReq
->CommandPacket
;
1451 CommandPacket
->Timeout
= SCSI_DISK_TIMEOUT
;
1452 CommandPacket
->OutDataBuffer
= UnmapParamList
;
1453 CommandPacket
->OutTransferLength
= UnmapParamListLen
;
1454 CommandPacket
->CdbLength
= 0xA;
1455 CommandPacket
->DataDirection
= EFI_SCSI_DATA_OUT
;
1457 // Fill Cdb for UNMAP Command
1459 Cdb
= CommandPacket
->Cdb
;
1460 Cdb
[0] = EFI_SCSI_OP_UNMAP
;
1461 WriteUnaligned16 ((UINT16
*)&Cdb
[7], SwapBytes16 (UnmapParamListLen
));
1463 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1465 // Non-blocking UNMAP request
1467 Status
= gBS
->CreateEvent (
1470 ScsiDiskAsyncUnmapNotify
,
1474 if (EFI_ERROR(Status
)) {
1475 ReturnStatus
= EFI_DEVICE_ERROR
;
1479 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1480 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &EraseBlkReq
->Link
);
1481 gBS
->RestoreTPL (OldTpl
);
1483 EraseBlkReq
->Token
= Token
;
1485 Status
= ScsiIo
->ExecuteScsiCommand (
1490 if (EFI_ERROR(Status
)) {
1491 ReturnStatus
= EFI_DEVICE_ERROR
;
1493 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1494 RemoveEntryList (&EraseBlkReq
->Link
);
1495 gBS
->RestoreTPL (OldTpl
);
1500 // Directly return if the non-blocking UNMAP request is queued.
1506 // Blocking UNMAP request
1508 Status
= ScsiIo
->ExecuteScsiCommand (
1513 if (EFI_ERROR(Status
)) {
1514 ReturnStatus
= EFI_DEVICE_ERROR
;
1520 // Only blocking UNMAP request will reach here.
1522 Status
= CheckHostAdapterStatus (CommandPacket
->HostAdapterStatus
);
1523 if (EFI_ERROR(Status
)) {
1526 "ScsiDiskUnmap: Host adapter indicating error status 0x%x.\n",
1527 CommandPacket
->HostAdapterStatus
1530 ReturnStatus
= EFI_DEVICE_ERROR
;
1534 Status
= CheckTargetStatus (CommandPacket
->TargetStatus
);
1535 if (EFI_ERROR(Status
)) {
1538 "ScsiDiskUnmap: Target indicating error status 0x%x.\n",
1539 CommandPacket
->HostAdapterStatus
1542 ReturnStatus
= EFI_DEVICE_ERROR
;
1547 if (EraseBlkReq
!= NULL
) {
1548 if (EraseBlkReq
->CommandPacket
.Cdb
!= NULL
) {
1549 FreePool (EraseBlkReq
->CommandPacket
.Cdb
);
1551 FreePool (EraseBlkReq
);
1554 if (UnmapParamList
!= NULL
) {
1555 FreePool (UnmapParamList
);
1558 if (AsyncUnmapEvent
!= NULL
) {
1559 gBS
->CloseEvent (AsyncUnmapEvent
);
1562 return ReturnStatus
;
1566 Erase a specified number of device blocks.
1568 @param[in] This Indicates a pointer to the calling context.
1569 @param[in] MediaId The media ID that the erase request is for.
1570 @param[in] Lba The starting logical block address to be
1571 erased. The caller is responsible for erasing
1572 only legitimate locations.
1573 @param[in, out] Token A pointer to the token associated with the
1575 @param[in] Size The size in bytes to be erased. This must be
1576 a multiple of the physical block size of the
1579 @retval EFI_SUCCESS The erase request was queued if Event is not
1580 NULL. The data was erased correctly to the
1581 device if the Event is NULL.to the device.
1582 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
1584 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1585 to perform the erase operation.
1586 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
1588 @retval EFI_NO_MEDIA There is no media in the device.
1589 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1594 ScsiDiskEraseBlocks (
1595 IN EFI_ERASE_BLOCK_PROTOCOL
*This
,
1598 IN OUT EFI_ERASE_BLOCK_TOKEN
*Token
,
1602 SCSI_DISK_DEV
*ScsiDiskDevice
;
1603 EFI_BLOCK_IO_MEDIA
*Media
;
1606 UINTN NumberOfBlocks
;
1607 BOOLEAN MediaChange
;
1610 MediaChange
= FALSE
;
1611 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1612 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_ERASEBLK (This
);
1614 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1615 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1616 if (EFI_ERROR (Status
)) {
1617 Status
= EFI_DEVICE_ERROR
;
1622 gBS
->ReinstallProtocolInterface (
1623 ScsiDiskDevice
->Handle
,
1624 &gEfiBlockIoProtocolGuid
,
1625 &ScsiDiskDevice
->BlkIo
,
1626 &ScsiDiskDevice
->BlkIo
1628 gBS
->ReinstallProtocolInterface (
1629 ScsiDiskDevice
->Handle
,
1630 &gEfiBlockIo2ProtocolGuid
,
1631 &ScsiDiskDevice
->BlkIo2
,
1632 &ScsiDiskDevice
->BlkIo2
1634 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1635 gBS
->ReinstallProtocolInterface (
1636 ScsiDiskDevice
->Handle
,
1637 &gEfiEraseBlockProtocolGuid
,
1638 &ScsiDiskDevice
->EraseBlock
,
1639 &ScsiDiskDevice
->EraseBlock
1642 Status
= EFI_MEDIA_CHANGED
;
1647 // Get the intrinsic block size
1649 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1651 if (!(Media
->MediaPresent
)) {
1652 Status
= EFI_NO_MEDIA
;
1656 if (MediaId
!= Media
->MediaId
) {
1657 Status
= EFI_MEDIA_CHANGED
;
1661 if (Media
->ReadOnly
) {
1662 Status
= EFI_WRITE_PROTECTED
;
1667 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1668 Token
->TransactionStatus
= EFI_SUCCESS
;
1669 gBS
->SignalEvent (Token
->Event
);
1671 Status
= EFI_SUCCESS
;
1675 BlockSize
= Media
->BlockSize
;
1676 if ((Size
% BlockSize
) != 0) {
1677 Status
= EFI_INVALID_PARAMETER
;
1681 NumberOfBlocks
= Size
/ BlockSize
;
1682 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1683 Status
= EFI_INVALID_PARAMETER
;
1687 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1688 Status
= ScsiDiskUnmap (ScsiDiskDevice
, Lba
, NumberOfBlocks
, Token
);
1690 Status
= ScsiDiskUnmap (ScsiDiskDevice
, Lba
, NumberOfBlocks
, NULL
);
1694 gBS
->RestoreTPL (OldTpl
);
1700 Detect Device and read out capacity ,if error occurs, parse the sense key.
1702 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1703 @param MustReadCapacity The flag about reading device capacity
1704 @param MediaChange The pointer of flag indicates if media has changed
1706 @retval EFI_DEVICE_ERROR Indicates that error occurs
1707 @retval EFI_SUCCESS Successfully to detect media
1711 ScsiDiskDetectMedia (
1712 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1713 IN BOOLEAN MustReadCapacity
,
1714 OUT BOOLEAN
*MediaChange
1718 EFI_SCSI_SENSE_DATA
*SenseData
;
1719 UINTN NumberOfSenseKeys
;
1721 BOOLEAN NeedReadCapacity
;
1724 EFI_BLOCK_IO_MEDIA OldMedia
;
1726 EFI_EVENT TimeoutEvt
;
1728 Status
= EFI_SUCCESS
;
1730 NumberOfSenseKeys
= 0;
1733 Action
= ACTION_NO_ACTION
;
1734 NeedReadCapacity
= FALSE
;
1735 *MediaChange
= FALSE
;
1738 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
1740 Status
= gBS
->CreateEvent (
1747 if (EFI_ERROR (Status
)) {
1751 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
1752 if (EFI_ERROR (Status
)) {
1757 // Sending Test_Unit cmd to poll device status.
1758 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
1759 // We limit the upper boundary to 120 seconds.
1761 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
1762 Status
= ScsiDiskTestUnitReady (
1768 if (!EFI_ERROR (Status
)) {
1769 Status
= DetectMediaParsingSenseKeys (
1775 if (EFI_ERROR (Status
)) {
1777 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1784 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1790 if (EFI_ERROR (Status
)) {
1795 // ACTION_NO_ACTION: need not read capacity
1796 // other action code: need read capacity
1798 if (Action
== ACTION_READ_CAPACITY
) {
1799 NeedReadCapacity
= TRUE
;
1803 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
1804 // retrieve capacity via Read Capacity command
1806 if (NeedReadCapacity
|| MustReadCapacity
) {
1808 // retrieve media information
1810 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
1811 Status
= ScsiDiskReadCapacity (
1817 if (!EFI_ERROR (Status
)) {
1819 // analyze sense key to action
1821 Status
= DetectMediaParsingSenseKeys (
1827 if (EFI_ERROR (Status
)) {
1829 // if Status is error, it may indicate crisis error,
1830 // so return without retry.
1833 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1841 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1847 if (EFI_ERROR (Status
)) {
1852 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
1854 // Media change information got from the device
1856 *MediaChange
= TRUE
;
1859 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
1860 *MediaChange
= TRUE
;
1861 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1864 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
1865 *MediaChange
= TRUE
;
1866 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1869 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
1870 *MediaChange
= TRUE
;
1871 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1874 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
1875 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
1877 // when change from no media to media present, reset the MediaId to 1.
1879 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
1882 // when no media, reset the MediaId to zero.
1884 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
1887 *MediaChange
= TRUE
;
1891 if (TimeoutEvt
!= NULL
) {
1892 gBS
->CloseEvent (TimeoutEvt
);
1899 Send out Inquiry command to Device.
1901 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1902 @param NeedRetry Indicates if needs try again when error happens
1904 @retval EFI_DEVICE_ERROR Indicates that error occurs
1905 @retval EFI_SUCCESS Successfully to detect media
1909 ScsiDiskInquiryDevice (
1910 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1911 OUT BOOLEAN
*NeedRetry
1914 UINT32 InquiryDataLength
;
1915 UINT8 SenseDataLength
;
1916 UINT8 HostAdapterStatus
;
1918 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
1919 UINTN NumberOfSenseKeys
;
1923 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
1924 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
1927 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1928 SenseDataLength
= 0;
1930 Status
= ScsiInquiryCommand (
1931 ScsiDiskDevice
->ScsiIo
,
1937 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
1942 // no need to check HostAdapterStatus and TargetStatus
1944 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1945 ParseInquiryData (ScsiDiskDevice
);
1947 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1949 // Check whether the device supports Block Limits VPD page (0xB0)
1951 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1952 if (SupportedVpdPages
== NULL
) {
1954 return EFI_DEVICE_ERROR
;
1956 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1957 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
1958 SenseDataLength
= 0;
1959 Status
= ScsiInquiryCommandEx (
1960 ScsiDiskDevice
->ScsiIo
,
1966 (VOID
*) SupportedVpdPages
,
1969 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
1971 if (!EFI_ERROR (Status
)) {
1972 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
1973 | SupportedVpdPages
->PageLength1
;
1976 // Sanity checks for coping with broken devices
1978 if (PageLength
> sizeof SupportedVpdPages
->SupportedVpdPageList
) {
1980 "%a: invalid PageLength (%u) in Supported VPD Pages page\n",
1981 __FUNCTION__
, (UINT32
)PageLength
));
1985 if ((PageLength
> 0) &&
1986 (SupportedVpdPages
->SupportedVpdPageList
[0] !=
1987 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
)) {
1989 "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",
1990 __FUNCTION__
, EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
));
1995 // Locate the code for the Block Limits VPD page
1997 for (Index
= 0; Index
< PageLength
; Index
++) {
2002 (SupportedVpdPages
->SupportedVpdPageList
[Index
] <=
2003 SupportedVpdPages
->SupportedVpdPageList
[Index
- 1])) {
2005 "%a: non-ascending code in Supported VPD Pages page @ %u\n",
2006 __FUNCTION__
, Index
));
2012 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
2018 // Query the Block Limits VPD page
2020 if (Index
< PageLength
) {
2021 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2022 if (BlockLimits
== NULL
) {
2023 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2025 return EFI_DEVICE_ERROR
;
2027 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2028 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
2029 SenseDataLength
= 0;
2030 Status
= ScsiInquiryCommandEx (
2031 ScsiDiskDevice
->ScsiIo
,
2037 (VOID
*) BlockLimits
,
2040 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
2042 if (!EFI_ERROR (Status
)) {
2043 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
2044 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
2045 BlockLimits
->OptimalTransferLengthGranularity1
;
2047 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
=
2048 (BlockLimits
->MaximumUnmapLbaCount4
<< 24) |
2049 (BlockLimits
->MaximumUnmapLbaCount3
<< 16) |
2050 (BlockLimits
->MaximumUnmapLbaCount2
<< 8) |
2051 BlockLimits
->MaximumUnmapLbaCount1
;
2052 ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
=
2053 (BlockLimits
->MaximumUnmapBlockDescriptorCount4
<< 24) |
2054 (BlockLimits
->MaximumUnmapBlockDescriptorCount3
<< 16) |
2055 (BlockLimits
->MaximumUnmapBlockDescriptorCount2
<< 8) |
2056 BlockLimits
->MaximumUnmapBlockDescriptorCount1
;
2057 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
=
2058 (BlockLimits
->OptimalUnmapGranularity4
<< 24) |
2059 (BlockLimits
->OptimalUnmapGranularity3
<< 16) |
2060 (BlockLimits
->OptimalUnmapGranularity2
<< 8) |
2061 BlockLimits
->OptimalUnmapGranularity1
;
2062 if (BlockLimits
->UnmapGranularityAlignmentValid
!= 0) {
2063 ScsiDiskDevice
->UnmapInfo
.GranularityAlignment
=
2064 (BlockLimits
->UnmapGranularityAlignment4
<< 24) |
2065 (BlockLimits
->UnmapGranularityAlignment3
<< 16) |
2066 (BlockLimits
->UnmapGranularityAlignment2
<< 8) |
2067 BlockLimits
->UnmapGranularityAlignment1
;
2070 if (ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
== 0) {
2072 // A value of 0 indicates that the optimal unmap granularity is
2075 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
= 1;
2078 ScsiDiskDevice
->BlockLimitsVpdSupported
= TRUE
;
2081 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2085 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2089 if (!EFI_ERROR (Status
)) {
2092 } else if (Status
== EFI_NOT_READY
) {
2094 return EFI_DEVICE_ERROR
;
2096 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2098 return EFI_DEVICE_ERROR
;
2101 // go ahead to check HostAdapterStatus and TargetStatus
2102 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
2105 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2106 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2108 return EFI_DEVICE_ERROR
;
2109 } else if (Status
== EFI_DEVICE_ERROR
) {
2111 // reset the scsi channel
2113 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2115 return EFI_DEVICE_ERROR
;
2118 Status
= CheckTargetStatus (TargetStatus
);
2119 if (Status
== EFI_NOT_READY
) {
2121 // reset the scsi device
2123 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2125 return EFI_DEVICE_ERROR
;
2127 } else if (Status
== EFI_DEVICE_ERROR
) {
2129 return EFI_DEVICE_ERROR
;
2133 // if goes here, meant ScsiInquiryCommand() failed.
2134 // if ScsiDiskRequestSenseKeys() succeeds at last,
2135 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
2138 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2139 Status
= ScsiDiskRequestSenseKeys (
2146 if (!EFI_ERROR (Status
)) {
2148 return EFI_DEVICE_ERROR
;
2152 return EFI_DEVICE_ERROR
;
2156 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2157 // set *NeedRetry = FALSE to avoid the outside caller try again.
2160 return EFI_DEVICE_ERROR
;
2166 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
2167 When Test Unit Ready command encounters any error caused by host adapter or
2168 target, return error without retrieving Sense Keys.
2170 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2171 @param NeedRetry The pointer of flag indicates try again
2172 @param SenseDataArray The pointer of an array of sense data
2173 @param NumberOfSenseKeys The pointer of the number of sense data array
2175 @retval EFI_DEVICE_ERROR Indicates that error occurs
2176 @retval EFI_SUCCESS Successfully to test unit
2180 ScsiDiskTestUnitReady (
2181 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2182 OUT BOOLEAN
*NeedRetry
,
2183 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2184 OUT UINTN
*NumberOfSenseKeys
2188 UINT8 SenseDataLength
;
2189 UINT8 HostAdapterStatus
;
2194 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2195 *NumberOfSenseKeys
= 0;
2198 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
2200 Status
= ScsiTestUnitReadyCommand (
2201 ScsiDiskDevice
->ScsiIo
,
2203 ScsiDiskDevice
->SenseData
,
2209 // no need to check HostAdapterStatus and TargetStatus
2211 if (Status
== EFI_NOT_READY
) {
2213 return EFI_DEVICE_ERROR
;
2215 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2217 return EFI_DEVICE_ERROR
;
2220 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
2223 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2224 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2226 return EFI_DEVICE_ERROR
;
2228 } else if (Status
== EFI_DEVICE_ERROR
) {
2230 // reset the scsi channel
2232 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2234 return EFI_DEVICE_ERROR
;
2237 Status
= CheckTargetStatus (TargetStatus
);
2238 if (Status
== EFI_NOT_READY
) {
2240 // reset the scsi device
2242 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2244 return EFI_DEVICE_ERROR
;
2246 } else if (Status
== EFI_DEVICE_ERROR
) {
2248 return EFI_DEVICE_ERROR
;
2251 if (SenseDataLength
!= 0) {
2252 *NumberOfSenseKeys
= SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
);
2253 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2258 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2259 Status
= ScsiDiskRequestSenseKeys (
2266 if (!EFI_ERROR (Status
)) {
2271 return EFI_DEVICE_ERROR
;
2275 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2276 // set *NeedRetry = FALSE to avoid the outside caller try again.
2279 return EFI_DEVICE_ERROR
;
2283 Parsing Sense Keys which got from request sense command.
2285 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2286 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2287 @param NumberOfSenseKeys The number of sense key
2288 @param Action The pointer of action which indicates what is need to do next
2290 @retval EFI_DEVICE_ERROR Indicates that error occurs
2291 @retval EFI_SUCCESS Successfully to complete the parsing
2295 DetectMediaParsingSenseKeys (
2296 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2297 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2298 IN UINTN NumberOfSenseKeys
,
2305 // Default is to read capacity, unless..
2307 *Action
= ACTION_READ_CAPACITY
;
2309 if (NumberOfSenseKeys
== 0) {
2310 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
2311 *Action
= ACTION_NO_ACTION
;
2316 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
2318 // No Sense Key returned from last submitted command
2320 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
2321 *Action
= ACTION_NO_ACTION
;
2326 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
2327 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
2328 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
2329 *Action
= ACTION_NO_ACTION
;
2330 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
2334 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
2335 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
2336 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
2340 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
2341 *Action
= ACTION_RETRY_COMMAND_LATER
;
2342 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
2346 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
2347 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
2348 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2349 return EFI_DEVICE_ERROR
;
2352 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
2353 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
2354 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2355 return EFI_DEVICE_ERROR
;
2358 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
2360 *Action
= ACTION_RETRY_COMMAND_LATER
;
2361 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
2364 *Action
= ACTION_NO_ACTION
;
2365 return EFI_DEVICE_ERROR
;
2368 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2369 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
2375 Send read capacity command to device and get the device parameter.
2377 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2378 @param NeedRetry The pointer of flag indicates if need a retry
2379 @param SenseDataArray The pointer of an array of sense data
2380 @param NumberOfSenseKeys The number of sense key
2382 @retval EFI_DEVICE_ERROR Indicates that error occurs
2383 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
2387 ScsiDiskReadCapacity (
2388 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2389 OUT BOOLEAN
*NeedRetry
,
2390 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2391 OUT UINTN
*NumberOfSenseKeys
2394 UINT8 HostAdapterStatus
;
2396 EFI_STATUS CommandStatus
;
2400 UINT8 SenseDataLength
;
2401 UINT32 DataLength10
;
2402 UINT32 DataLength16
;
2403 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
2404 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
2406 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2407 if (CapacityData10
== NULL
) {
2409 return EFI_DEVICE_ERROR
;
2411 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2412 if (CapacityData16
== NULL
) {
2413 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2415 return EFI_DEVICE_ERROR
;
2418 SenseDataLength
= 0;
2419 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
2420 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
2421 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2422 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2424 *NumberOfSenseKeys
= 0;
2428 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
2429 // 16 byte command should be used to access large hard disk >2TB
2431 CommandStatus
= ScsiReadCapacityCommand (
2432 ScsiDiskDevice
->ScsiIo
,
2438 (VOID
*) CapacityData10
,
2443 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
2444 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
2445 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff)) {
2447 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
2449 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
2451 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
2452 // and LowestAlignedLba
2454 CommandStatus
= ScsiReadCapacity16Command (
2455 ScsiDiskDevice
->ScsiIo
,
2461 (VOID
*) CapacityData16
,
2468 // no need to check HostAdapterStatus and TargetStatus
2470 if (CommandStatus
== EFI_SUCCESS
) {
2471 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
2472 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2473 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2477 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2478 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2480 if (CommandStatus
== EFI_NOT_READY
) {
2482 return EFI_DEVICE_ERROR
;
2483 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
2485 return EFI_DEVICE_ERROR
;
2489 // go ahead to check HostAdapterStatus and TargetStatus
2490 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2493 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2494 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2496 return EFI_DEVICE_ERROR
;
2498 } else if (Status
== EFI_DEVICE_ERROR
) {
2500 // reset the scsi channel
2502 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2504 return EFI_DEVICE_ERROR
;
2507 Status
= CheckTargetStatus (TargetStatus
);
2508 if (Status
== EFI_NOT_READY
) {
2510 // reset the scsi device
2512 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2514 return EFI_DEVICE_ERROR
;
2516 } else if (Status
== EFI_DEVICE_ERROR
) {
2518 return EFI_DEVICE_ERROR
;
2522 // if goes here, meant ScsiReadCapacityCommand() failed.
2523 // if ScsiDiskRequestSenseKeys() succeeds at last,
2524 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
2527 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2529 Status
= ScsiDiskRequestSenseKeys (
2536 if (!EFI_ERROR (Status
)) {
2541 return EFI_DEVICE_ERROR
;
2545 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2546 // set *NeedRetry = FALSE to avoid the outside caller try again.
2549 return EFI_DEVICE_ERROR
;
2553 Check the HostAdapter status and re-interpret it in EFI_STATUS.
2555 @param HostAdapterStatus Host Adapter status
2557 @retval EFI_SUCCESS Host adapter is OK.
2558 @retval EFI_TIMEOUT Timeout.
2559 @retval EFI_NOT_READY Adapter NOT ready.
2560 @retval EFI_DEVICE_ERROR Adapter device error.
2564 CheckHostAdapterStatus (
2565 IN UINT8 HostAdapterStatus
2568 switch (HostAdapterStatus
) {
2569 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
2572 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
2573 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
2574 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
2577 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
2578 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
2579 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
2580 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
2581 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
2582 return EFI_NOT_READY
;
2584 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
2585 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
2586 return EFI_DEVICE_ERROR
;
2595 Check the target status and re-interpret it in EFI_STATUS.
2597 @param TargetStatus Target status
2599 @retval EFI_NOT_READY Device is NOT ready.
2600 @retval EFI_DEVICE_ERROR
2606 IN UINT8 TargetStatus
2609 switch (TargetStatus
) {
2610 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
2611 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
2612 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
2615 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
2616 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
2617 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
2618 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
2619 return EFI_NOT_READY
;
2621 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
2622 return EFI_DEVICE_ERROR
;
2631 Retrieve all sense keys from the device.
2633 When encountering error during the process, if retrieve sense keys before
2634 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
2635 and NeedRetry set to FALSE; otherwize, return the proper return status.
2637 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2638 @param NeedRetry The pointer of flag indicates if need a retry
2639 @param SenseDataArray The pointer of an array of sense data
2640 @param NumberOfSenseKeys The number of sense key
2641 @param AskResetIfError The flag indicates if need reset when error occurs
2643 @retval EFI_DEVICE_ERROR Indicates that error occurs
2644 @retval EFI_SUCCESS Successfully to request sense key
2648 ScsiDiskRequestSenseKeys (
2649 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2650 OUT BOOLEAN
*NeedRetry
,
2651 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2652 OUT UINTN
*NumberOfSenseKeys
,
2653 IN BOOLEAN AskResetIfError
2656 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
2657 UINT8 SenseDataLength
;
2660 EFI_STATUS FallStatus
;
2661 UINT8 HostAdapterStatus
;
2664 FallStatus
= EFI_SUCCESS
;
2665 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
2668 ScsiDiskDevice
->SenseData
,
2669 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
2672 *NumberOfSenseKeys
= 0;
2673 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2674 Status
= EFI_SUCCESS
;
2675 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
2676 if (PtrSenseData
== NULL
) {
2677 return EFI_DEVICE_ERROR
;
2680 for (SenseReq
= TRUE
; SenseReq
;) {
2681 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2682 Status
= ScsiRequestSenseCommand (
2683 ScsiDiskDevice
->ScsiIo
,
2690 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
2691 FallStatus
= EFI_SUCCESS
;
2693 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2695 FallStatus
= EFI_DEVICE_ERROR
;
2697 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2699 FallStatus
= EFI_DEVICE_ERROR
;
2701 } else if (Status
== EFI_DEVICE_ERROR
) {
2702 if (AskResetIfError
) {
2703 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2706 FallStatus
= EFI_DEVICE_ERROR
;
2709 if (EFI_ERROR (FallStatus
)) {
2710 if (*NumberOfSenseKeys
!= 0) {
2712 Status
= EFI_SUCCESS
;
2715 Status
= EFI_DEVICE_ERROR
;
2720 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
2721 (*NumberOfSenseKeys
) += 1;
2724 // no more sense key or number of sense keys exceeds predefined,
2727 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
2728 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
2734 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2740 Get information from media read capacity command.
2742 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2743 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
2744 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
2749 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2750 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
2751 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
2756 if (!ScsiDiskDevice
->Cdb16Byte
) {
2757 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= ((UINT32
) Capacity10
->LastLba3
<< 24) |
2758 (Capacity10
->LastLba2
<< 16) |
2759 (Capacity10
->LastLba1
<< 8) |
2760 Capacity10
->LastLba0
;
2762 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
2763 (Capacity10
->BlockSize2
<< 16) |
2764 (Capacity10
->BlockSize1
<< 8) |
2765 Capacity10
->BlockSize0
;
2766 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
2767 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
2768 if (!ScsiDiskDevice
->BlockLimitsVpdSupported
) {
2769 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
) ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2772 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2773 *Ptr
++ = Capacity16
->LastLba0
;
2774 *Ptr
++ = Capacity16
->LastLba1
;
2775 *Ptr
++ = Capacity16
->LastLba2
;
2776 *Ptr
++ = Capacity16
->LastLba3
;
2777 *Ptr
++ = Capacity16
->LastLba4
;
2778 *Ptr
++ = Capacity16
->LastLba5
;
2779 *Ptr
++ = Capacity16
->LastLba6
;
2780 *Ptr
= Capacity16
->LastLba7
;
2782 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
2783 (Capacity16
->BlockSize2
<< 16) |
2784 (Capacity16
->BlockSize1
<< 8) |
2785 Capacity16
->BlockSize0
;
2787 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
2788 Capacity16
->LowestAlignLogic1
;
2789 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
2790 if (!ScsiDiskDevice
->BlockLimitsVpdSupported
) {
2791 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
> (UINT32
) -1) {
2792 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
) -1;
2794 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
) ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2799 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
2805 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2810 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2813 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
2814 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
2818 Read sector from SCSI Disk.
2820 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2821 @param Buffer The buffer to fill in the read out data
2822 @param Lba Logic block address
2823 @param NumberOfBlocks The number of blocks to read
2825 @retval EFI_DEVICE_ERROR Indicates a device error.
2826 @retval EFI_SUCCESS Operation is successful.
2830 ScsiDiskReadSectors (
2831 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2834 IN UINTN NumberOfBlocks
2837 UINTN BlocksRemaining
;
2843 UINT32 NextSectorCount
;
2850 Status
= EFI_SUCCESS
;
2852 BlocksRemaining
= NumberOfBlocks
;
2853 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2856 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2858 if (!ScsiDiskDevice
->Cdb16Byte
) {
2861 MaxBlock
= 0xFFFFFFFF;
2866 while (BlocksRemaining
> 0) {
2868 if (BlocksRemaining
<= MaxBlock
) {
2869 if (!ScsiDiskDevice
->Cdb16Byte
) {
2870 SectorCount
= (UINT16
) BlocksRemaining
;
2872 SectorCount
= (UINT32
) BlocksRemaining
;
2875 SectorCount
= MaxBlock
;
2878 ByteCount
= SectorCount
* BlockSize
;
2880 // |------------------------|-----------------|------------------|-----------------|
2881 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2882 // |------------------------|-----------------|------------------|-----------------|
2883 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2884 // |------------------------|-----------------|------------------|-----------------|
2885 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2886 // |------------------------|-----------------|------------------|-----------------|
2887 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2888 // |------------------------|-----------------|------------------|-----------------|
2889 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2890 // |------------------------|-----------------|------------------|-----------------|
2891 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2892 // |------------------------|-----------------|------------------|-----------------|
2893 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2894 // |------------------------|-----------------|------------------|-----------------|
2895 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2896 // |------------------------|-----------------|------------------|-----------------|
2897 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2898 // |------------------------|-----------------|------------------|-----------------|
2899 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2900 // |------------------------|-----------------|------------------|-----------------|
2901 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2902 // |------------------------|-----------------|------------------|-----------------|
2904 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2905 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2906 // From the above table, we could know 2.1Mbytes per second is lowest one.
2907 // The timout value is rounded up to nearest integar and here an additional 30s is added
2908 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2909 // commands in the Standby/Idle mode.
2911 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2914 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2915 if (!ScsiDiskDevice
->Cdb16Byte
) {
2916 Status
= ScsiDiskRead10 (
2926 Status
= ScsiDiskRead16 (
2936 if (!EFI_ERROR (Status
)) {
2941 return EFI_DEVICE_ERROR
;
2945 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
2946 // lowered ByteCount on output, we must make sure that we lower
2947 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2948 // it is invalid to request more sectors in the CDB than the entire
2949 // transfer (ie. ByteCount) can carry.
2951 // In addition, ByteCount is only expected to go down, or stay unchaged.
2952 // Therefore we don't need to update Timeout: the original timeout should
2953 // accommodate shorter transfers too.
2955 NextSectorCount
= ByteCount
/ BlockSize
;
2956 if (NextSectorCount
< SectorCount
) {
2957 SectorCount
= NextSectorCount
;
2959 // Account for any rounding down.
2961 ByteCount
= SectorCount
* BlockSize
;
2965 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2966 return EFI_DEVICE_ERROR
;
2970 // actual transferred sectors
2972 SectorCount
= ByteCount
/ BlockSize
;
2975 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2976 BlocksRemaining
-= SectorCount
;
2983 Write sector to SCSI Disk.
2985 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2986 @param Buffer The buffer of data to be written into SCSI Disk
2987 @param Lba Logic block address
2988 @param NumberOfBlocks The number of blocks to read
2990 @retval EFI_DEVICE_ERROR Indicates a device error.
2991 @retval EFI_SUCCESS Operation is successful.
2995 ScsiDiskWriteSectors (
2996 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2999 IN UINTN NumberOfBlocks
3002 UINTN BlocksRemaining
;
3008 UINT32 NextSectorCount
;
3015 Status
= EFI_SUCCESS
;
3017 BlocksRemaining
= NumberOfBlocks
;
3018 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3021 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3023 if (!ScsiDiskDevice
->Cdb16Byte
) {
3026 MaxBlock
= 0xFFFFFFFF;
3031 while (BlocksRemaining
> 0) {
3033 if (BlocksRemaining
<= MaxBlock
) {
3034 if (!ScsiDiskDevice
->Cdb16Byte
) {
3035 SectorCount
= (UINT16
) BlocksRemaining
;
3037 SectorCount
= (UINT32
) BlocksRemaining
;
3040 SectorCount
= MaxBlock
;
3043 ByteCount
= SectorCount
* BlockSize
;
3045 // |------------------------|-----------------|------------------|-----------------|
3046 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3047 // |------------------------|-----------------|------------------|-----------------|
3048 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3049 // |------------------------|-----------------|------------------|-----------------|
3050 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3051 // |------------------------|-----------------|------------------|-----------------|
3052 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3053 // |------------------------|-----------------|------------------|-----------------|
3054 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3055 // |------------------------|-----------------|------------------|-----------------|
3056 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3057 // |------------------------|-----------------|------------------|-----------------|
3058 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3059 // |------------------------|-----------------|------------------|-----------------|
3060 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3061 // |------------------------|-----------------|------------------|-----------------|
3062 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3063 // |------------------------|-----------------|------------------|-----------------|
3064 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3065 // |------------------------|-----------------|------------------|-----------------|
3066 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3067 // |------------------------|-----------------|------------------|-----------------|
3069 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3070 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3071 // From the above table, we could know 2.1Mbytes per second is lowest one.
3072 // The timout value is rounded up to nearest integar and here an additional 30s is added
3073 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3074 // commands in the Standby/Idle mode.
3076 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3078 for (Index
= 0; Index
< MaxRetry
; Index
++) {
3079 if (!ScsiDiskDevice
->Cdb16Byte
) {
3080 Status
= ScsiDiskWrite10 (
3090 Status
= ScsiDiskWrite16 (
3100 if (!EFI_ERROR (Status
)) {
3105 return EFI_DEVICE_ERROR
;
3109 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
3110 // has lowered ByteCount on output, we must make sure that we lower
3111 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3112 // it is invalid to request more sectors in the CDB than the entire
3113 // transfer (ie. ByteCount) can carry.
3115 // In addition, ByteCount is only expected to go down, or stay unchaged.
3116 // Therefore we don't need to update Timeout: the original timeout should
3117 // accommodate shorter transfers too.
3119 NextSectorCount
= ByteCount
/ BlockSize
;
3120 if (NextSectorCount
< SectorCount
) {
3121 SectorCount
= NextSectorCount
;
3123 // Account for any rounding down.
3125 ByteCount
= SectorCount
* BlockSize
;
3129 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
3130 return EFI_DEVICE_ERROR
;
3133 // actual transferred sectors
3135 SectorCount
= ByteCount
/ BlockSize
;
3138 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3139 BlocksRemaining
-= SectorCount
;
3146 Asynchronously read sector from SCSI Disk.
3148 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3149 @param Buffer The buffer to fill in the read out data.
3150 @param Lba Logic block address.
3151 @param NumberOfBlocks The number of blocks to read.
3152 @param Token A pointer to the token associated with the
3153 non-blocking read request.
3155 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
3156 @retval EFI_DEVICE_ERROR Indicates a device error.
3157 @retval EFI_SUCCESS Operation is successful.
3161 ScsiDiskAsyncReadSectors (
3162 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3165 IN UINTN NumberOfBlocks
,
3166 IN EFI_BLOCK_IO2_TOKEN
*Token
3169 UINTN BlocksRemaining
;
3176 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
3180 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
3181 return EFI_INVALID_PARAMETER
;
3184 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
3185 if (BlkIo2Req
== NULL
) {
3186 return EFI_OUT_OF_RESOURCES
;
3189 BlkIo2Req
->Token
= Token
;
3191 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3192 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &BlkIo2Req
->Link
);
3193 gBS
->RestoreTPL (OldTpl
);
3195 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
3197 Status
= EFI_SUCCESS
;
3199 BlocksRemaining
= NumberOfBlocks
;
3200 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3203 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3206 if (!ScsiDiskDevice
->Cdb16Byte
) {
3209 MaxBlock
= 0xFFFFFFFF;
3214 while (BlocksRemaining
> 0) {
3216 if (BlocksRemaining
<= MaxBlock
) {
3217 if (!ScsiDiskDevice
->Cdb16Byte
) {
3218 SectorCount
= (UINT16
) BlocksRemaining
;
3220 SectorCount
= (UINT32
) BlocksRemaining
;
3223 SectorCount
= MaxBlock
;
3226 ByteCount
= SectorCount
* BlockSize
;
3228 // |------------------------|-----------------|------------------|-----------------|
3229 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3230 // |------------------------|-----------------|------------------|-----------------|
3231 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3232 // |------------------------|-----------------|------------------|-----------------|
3233 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3234 // |------------------------|-----------------|------------------|-----------------|
3235 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3236 // |------------------------|-----------------|------------------|-----------------|
3237 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3238 // |------------------------|-----------------|------------------|-----------------|
3239 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3240 // |------------------------|-----------------|------------------|-----------------|
3241 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3242 // |------------------------|-----------------|------------------|-----------------|
3243 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3244 // |------------------------|-----------------|------------------|-----------------|
3245 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3246 // |------------------------|-----------------|------------------|-----------------|
3247 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3248 // |------------------------|-----------------|------------------|-----------------|
3249 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3250 // |------------------------|-----------------|------------------|-----------------|
3252 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3253 // we have to use the lowest transfer rate to calculate the possible
3254 // maximum timeout value for each operation.
3255 // From the above table, we could know 2.1Mbytes per second is lowest one.
3256 // The timout value is rounded up to nearest integar and here an additional
3257 // 30s is added to follow ATA spec in which it mentioned that the device
3258 // may take up to 30s to respond commands in the Standby/Idle mode.
3260 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3262 if (!ScsiDiskDevice
->Cdb16Byte
) {
3263 Status
= ScsiDiskAsyncRead10 (
3275 Status
= ScsiDiskAsyncRead16 (
3287 if (EFI_ERROR (Status
)) {
3289 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3290 // length of a SCSI I/O command is too large.
3291 // In this case, we retry sending the SCSI command with a data length
3292 // half of its previous value.
3294 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
3295 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
3296 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
3301 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3302 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3304 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3305 // SCSI sub-task running. Otherwise, it will be freed in the callback
3306 // function ScsiDiskNotify().
3308 RemoveEntryList (&BlkIo2Req
->Link
);
3309 FreePool (BlkIo2Req
);
3311 gBS
->RestoreTPL (OldTpl
);
3314 // It is safe to return error status to the caller, since there is no
3315 // previous SCSI sub-task executing.
3317 Status
= EFI_DEVICE_ERROR
;
3320 gBS
->RestoreTPL (OldTpl
);
3323 // There are previous SCSI commands still running, EFI_SUCCESS should
3324 // be returned to make sure that the caller does not free resources
3325 // still using by these SCSI commands.
3327 Status
= EFI_SUCCESS
;
3333 // Sectors submitted for transfer
3335 SectorCount
= ByteCount
/ BlockSize
;
3338 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3339 BlocksRemaining
-= SectorCount
;
3342 Status
= EFI_SUCCESS
;
3345 if (BlkIo2Req
!= NULL
) {
3346 BlkIo2Req
->LastScsiRW
= TRUE
;
3348 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3349 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3350 RemoveEntryList (&BlkIo2Req
->Link
);
3351 FreePool (BlkIo2Req
);
3354 gBS
->SignalEvent (Token
->Event
);
3356 gBS
->RestoreTPL (OldTpl
);
3363 Asynchronously write sector to SCSI Disk.
3365 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3366 @param Buffer The buffer of data to be written into SCSI Disk.
3367 @param Lba Logic block address.
3368 @param NumberOfBlocks The number of blocks to read.
3369 @param Token A pointer to the token associated with the
3370 non-blocking read request.
3372 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
3373 @retval EFI_DEVICE_ERROR Indicates a device error.
3374 @retval EFI_SUCCESS Operation is successful.
3378 ScsiDiskAsyncWriteSectors (
3379 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3382 IN UINTN NumberOfBlocks
,
3383 IN EFI_BLOCK_IO2_TOKEN
*Token
3386 UINTN BlocksRemaining
;
3393 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
3397 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
3398 return EFI_INVALID_PARAMETER
;
3401 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
3402 if (BlkIo2Req
== NULL
) {
3403 return EFI_OUT_OF_RESOURCES
;
3406 BlkIo2Req
->Token
= Token
;
3408 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3409 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &BlkIo2Req
->Link
);
3410 gBS
->RestoreTPL (OldTpl
);
3412 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
3414 Status
= EFI_SUCCESS
;
3416 BlocksRemaining
= NumberOfBlocks
;
3417 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3420 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3423 if (!ScsiDiskDevice
->Cdb16Byte
) {
3426 MaxBlock
= 0xFFFFFFFF;
3431 while (BlocksRemaining
> 0) {
3433 if (BlocksRemaining
<= MaxBlock
) {
3434 if (!ScsiDiskDevice
->Cdb16Byte
) {
3435 SectorCount
= (UINT16
) BlocksRemaining
;
3437 SectorCount
= (UINT32
) BlocksRemaining
;
3440 SectorCount
= MaxBlock
;
3443 ByteCount
= SectorCount
* BlockSize
;
3445 // |------------------------|-----------------|------------------|-----------------|
3446 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3447 // |------------------------|-----------------|------------------|-----------------|
3448 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3449 // |------------------------|-----------------|------------------|-----------------|
3450 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3451 // |------------------------|-----------------|------------------|-----------------|
3452 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3453 // |------------------------|-----------------|------------------|-----------------|
3454 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3455 // |------------------------|-----------------|------------------|-----------------|
3456 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3457 // |------------------------|-----------------|------------------|-----------------|
3458 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3459 // |------------------------|-----------------|------------------|-----------------|
3460 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3461 // |------------------------|-----------------|------------------|-----------------|
3462 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3463 // |------------------------|-----------------|------------------|-----------------|
3464 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3465 // |------------------------|-----------------|------------------|-----------------|
3466 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3467 // |------------------------|-----------------|------------------|-----------------|
3469 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3470 // we have to use the lowest transfer rate to calculate the possible
3471 // maximum timeout value for each operation.
3472 // From the above table, we could know 2.1Mbytes per second is lowest one.
3473 // The timout value is rounded up to nearest integar and here an additional
3474 // 30s is added to follow ATA spec in which it mentioned that the device
3475 // may take up to 30s to respond commands in the Standby/Idle mode.
3477 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3479 if (!ScsiDiskDevice
->Cdb16Byte
) {
3480 Status
= ScsiDiskAsyncWrite10 (
3492 Status
= ScsiDiskAsyncWrite16 (
3504 if (EFI_ERROR (Status
)) {
3506 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3507 // length of a SCSI I/O command is too large.
3508 // In this case, we retry sending the SCSI command with a data length
3509 // half of its previous value.
3511 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
3512 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
3513 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
3518 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3519 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3521 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3522 // SCSI sub-task running. Otherwise, it will be freed in the callback
3523 // function ScsiDiskNotify().
3525 RemoveEntryList (&BlkIo2Req
->Link
);
3526 FreePool (BlkIo2Req
);
3528 gBS
->RestoreTPL (OldTpl
);
3531 // It is safe to return error status to the caller, since there is no
3532 // previous SCSI sub-task executing.
3534 Status
= EFI_DEVICE_ERROR
;
3537 gBS
->RestoreTPL (OldTpl
);
3540 // There are previous SCSI commands still running, EFI_SUCCESS should
3541 // be returned to make sure that the caller does not free resources
3542 // still using by these SCSI commands.
3544 Status
= EFI_SUCCESS
;
3550 // Sectors submitted for transfer
3552 SectorCount
= ByteCount
/ BlockSize
;
3555 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3556 BlocksRemaining
-= SectorCount
;
3559 Status
= EFI_SUCCESS
;
3562 if (BlkIo2Req
!= NULL
) {
3563 BlkIo2Req
->LastScsiRW
= TRUE
;
3565 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3566 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3567 RemoveEntryList (&BlkIo2Req
->Link
);
3568 FreePool (BlkIo2Req
);
3571 gBS
->SignalEvent (Token
->Event
);
3573 gBS
->RestoreTPL (OldTpl
);
3581 Submit Read(10) command.
3583 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3584 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3585 @param Timeout The time to complete the command
3586 @param DataBuffer The buffer to fill with the read out data
3587 @param DataLength The length of buffer
3588 @param StartLba The start logic block address
3589 @param SectorCount The number of blocks to read
3591 @return EFI_STATUS is returned by calling ScsiRead10Command().
3595 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3596 OUT BOOLEAN
*NeedRetry
,
3598 OUT UINT8
*DataBuffer
,
3599 IN OUT UINT32
*DataLength
,
3601 IN UINT32 SectorCount
3604 UINT8 SenseDataLength
;
3606 EFI_STATUS ReturnStatus
;
3607 UINT8 HostAdapterStatus
;
3612 // Implement a backoff algorithem to resolve some compatibility issues that
3613 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3614 // big data in a single operation.
3615 // This algorithem will at first try to execute original request. If the request fails
3616 // with media error sense data or else, it will reduce the transfer length to half and
3617 // try again till the operation succeeds or fails with one sector transfer length.
3621 Action
= ACTION_NO_ACTION
;
3622 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3623 ReturnStatus
= ScsiRead10Command (
3624 ScsiDiskDevice
->ScsiIo
,
3626 ScsiDiskDevice
->SenseData
,
3636 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3638 return EFI_DEVICE_ERROR
;
3639 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3641 return ReturnStatus
;
3645 // go ahead to check HostAdapterStatus and TargetStatus
3646 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3648 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3649 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3651 return EFI_DEVICE_ERROR
;
3652 } else if (Status
== EFI_DEVICE_ERROR
) {
3654 // reset the scsi channel
3656 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3658 return EFI_DEVICE_ERROR
;
3661 Status
= CheckTargetStatus (TargetStatus
);
3662 if (Status
== EFI_NOT_READY
) {
3664 // reset the scsi device
3666 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3668 return EFI_DEVICE_ERROR
;
3669 } else if (Status
== EFI_DEVICE_ERROR
) {
3671 return EFI_DEVICE_ERROR
;
3674 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3675 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
3676 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3677 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3679 return EFI_DEVICE_ERROR
;
3680 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3681 if (SectorCount
<= 1) {
3683 // Jump out if the operation still fails with one sector transfer length.
3686 return EFI_DEVICE_ERROR
;
3689 // Try again with half length if the sense data shows we need to retry.
3692 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3696 return EFI_DEVICE_ERROR
;
3700 return ReturnStatus
;
3705 Submit Write(10) Command.
3707 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3708 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3709 @param Timeout The time to complete the command
3710 @param DataBuffer The buffer to fill with the read out data
3711 @param DataLength The length of buffer
3712 @param StartLba The start logic block address
3713 @param SectorCount The number of blocks to write
3715 @return EFI_STATUS is returned by calling ScsiWrite10Command().
3720 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3721 OUT BOOLEAN
*NeedRetry
,
3723 IN UINT8
*DataBuffer
,
3724 IN OUT UINT32
*DataLength
,
3726 IN UINT32 SectorCount
3730 EFI_STATUS ReturnStatus
;
3731 UINT8 SenseDataLength
;
3732 UINT8 HostAdapterStatus
;
3737 // Implement a backoff algorithem to resolve some compatibility issues that
3738 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3739 // big data in a single operation.
3740 // This algorithem will at first try to execute original request. If the request fails
3741 // with media error sense data or else, it will reduce the transfer length to half and
3742 // try again till the operation succeeds or fails with one sector transfer length.
3746 Action
= ACTION_NO_ACTION
;
3747 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3748 ReturnStatus
= ScsiWrite10Command (
3749 ScsiDiskDevice
->ScsiIo
,
3751 ScsiDiskDevice
->SenseData
,
3760 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3762 return EFI_DEVICE_ERROR
;
3763 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3765 return ReturnStatus
;
3769 // go ahead to check HostAdapterStatus and TargetStatus
3770 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3772 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3773 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3775 return EFI_DEVICE_ERROR
;
3776 } else if (Status
== EFI_DEVICE_ERROR
) {
3778 // reset the scsi channel
3780 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3782 return EFI_DEVICE_ERROR
;
3785 Status
= CheckTargetStatus (TargetStatus
);
3786 if (Status
== EFI_NOT_READY
) {
3788 // reset the scsi device
3790 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3792 return EFI_DEVICE_ERROR
;
3793 } else if (Status
== EFI_DEVICE_ERROR
) {
3795 return EFI_DEVICE_ERROR
;
3798 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3799 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
3800 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3801 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3803 return EFI_DEVICE_ERROR
;
3804 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3805 if (SectorCount
<= 1) {
3807 // Jump out if the operation still fails with one sector transfer length.
3810 return EFI_DEVICE_ERROR
;
3813 // Try again with half length if the sense data shows we need to retry.
3816 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3820 return EFI_DEVICE_ERROR
;
3824 return ReturnStatus
;
3829 Submit Read(16) command.
3831 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3832 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3833 @param Timeout The time to complete the command
3834 @param DataBuffer The buffer to fill with the read out data
3835 @param DataLength The length of buffer
3836 @param StartLba The start logic block address
3837 @param SectorCount The number of blocks to read
3839 @return EFI_STATUS is returned by calling ScsiRead16Command().
3843 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3844 OUT BOOLEAN
*NeedRetry
,
3846 OUT UINT8
*DataBuffer
,
3847 IN OUT UINT32
*DataLength
,
3849 IN UINT32 SectorCount
3852 UINT8 SenseDataLength
;
3854 EFI_STATUS ReturnStatus
;
3855 UINT8 HostAdapterStatus
;
3860 // Implement a backoff algorithem to resolve some compatibility issues that
3861 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3862 // big data in a single operation.
3863 // This algorithem will at first try to execute original request. If the request fails
3864 // with media error sense data or else, it will reduce the transfer length to half and
3865 // try again till the operation succeeds or fails with one sector transfer length.
3869 Action
= ACTION_NO_ACTION
;
3870 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3871 ReturnStatus
= ScsiRead16Command (
3872 ScsiDiskDevice
->ScsiIo
,
3874 ScsiDiskDevice
->SenseData
,
3883 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3885 return EFI_DEVICE_ERROR
;
3886 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3888 return ReturnStatus
;
3892 // go ahead to check HostAdapterStatus and TargetStatus
3893 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3895 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3896 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3898 return EFI_DEVICE_ERROR
;
3899 } else if (Status
== EFI_DEVICE_ERROR
) {
3901 // reset the scsi channel
3903 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3905 return EFI_DEVICE_ERROR
;
3908 Status
= CheckTargetStatus (TargetStatus
);
3909 if (Status
== EFI_NOT_READY
) {
3911 // reset the scsi device
3913 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3915 return EFI_DEVICE_ERROR
;
3916 } else if (Status
== EFI_DEVICE_ERROR
) {
3918 return EFI_DEVICE_ERROR
;
3921 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3922 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
3923 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3924 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3926 return EFI_DEVICE_ERROR
;
3927 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3928 if (SectorCount
<= 1) {
3930 // Jump out if the operation still fails with one sector transfer length.
3933 return EFI_DEVICE_ERROR
;
3936 // Try again with half length if the sense data shows we need to retry.
3939 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3943 return EFI_DEVICE_ERROR
;
3947 return ReturnStatus
;
3952 Submit Write(16) Command.
3954 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3955 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3956 @param Timeout The time to complete the command
3957 @param DataBuffer The buffer to fill with the read out data
3958 @param DataLength The length of buffer
3959 @param StartLba The start logic block address
3960 @param SectorCount The number of blocks to write
3962 @return EFI_STATUS is returned by calling ScsiWrite16Command().
3967 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3968 OUT BOOLEAN
*NeedRetry
,
3970 IN UINT8
*DataBuffer
,
3971 IN OUT UINT32
*DataLength
,
3973 IN UINT32 SectorCount
3977 EFI_STATUS ReturnStatus
;
3978 UINT8 SenseDataLength
;
3979 UINT8 HostAdapterStatus
;
3984 // Implement a backoff algorithem to resolve some compatibility issues that
3985 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3986 // big data in a single operation.
3987 // This algorithem will at first try to execute original request. If the request fails
3988 // with media error sense data or else, it will reduce the transfer length to half and
3989 // try again till the operation succeeds or fails with one sector transfer length.
3993 Action
= ACTION_NO_ACTION
;
3994 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3995 ReturnStatus
= ScsiWrite16Command (
3996 ScsiDiskDevice
->ScsiIo
,
3998 ScsiDiskDevice
->SenseData
,
4007 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
4009 return EFI_DEVICE_ERROR
;
4010 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
4012 return ReturnStatus
;
4016 // go ahead to check HostAdapterStatus and TargetStatus
4017 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4019 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
4020 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4022 return EFI_DEVICE_ERROR
;
4023 } else if (Status
== EFI_DEVICE_ERROR
) {
4025 // reset the scsi channel
4027 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4029 return EFI_DEVICE_ERROR
;
4032 Status
= CheckTargetStatus (TargetStatus
);
4033 if (Status
== EFI_NOT_READY
) {
4035 // reset the scsi device
4037 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4039 return EFI_DEVICE_ERROR
;
4040 } else if (Status
== EFI_DEVICE_ERROR
) {
4042 return EFI_DEVICE_ERROR
;
4045 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
4046 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
4047 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
4048 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4050 return EFI_DEVICE_ERROR
;
4051 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4052 if (SectorCount
<= 1) {
4054 // Jump out if the operation still fails with one sector transfer length.
4057 return EFI_DEVICE_ERROR
;
4060 // Try again with half length if the sense data shows we need to retry.
4063 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4067 return EFI_DEVICE_ERROR
;
4071 return ReturnStatus
;
4076 Internal helper notify function in which determine whether retry of a SCSI
4077 Read/Write command is needed and signal the event passed from Block I/O(2) if
4078 the SCSI I/O operation completes.
4080 @param Event The instance of EFI_EVENT.
4081 @param Context The parameter passed in.
4092 SCSI_ASYNC_RW_REQUEST
*Request
;
4093 SCSI_DISK_DEV
*ScsiDiskDevice
;
4094 EFI_BLOCK_IO2_TOKEN
*Token
;
4096 UINT32 OldDataLength
;
4097 UINT32 OldSectorCount
;
4100 gBS
->CloseEvent (Event
);
4102 Request
= (SCSI_ASYNC_RW_REQUEST
*) Context
;
4103 ScsiDiskDevice
= Request
->ScsiDiskDevice
;
4104 Token
= Request
->BlkIo2Req
->Token
;
4105 OldDataLength
= Request
->DataLength
;
4106 OldSectorCount
= Request
->SectorCount
;
4110 // If previous sub-tasks already fails, no need to process this sub-task.
4112 if (Token
->TransactionStatus
!= EFI_SUCCESS
) {
4117 // Check HostAdapterStatus and TargetStatus
4118 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4120 Status
= CheckHostAdapterStatus (Request
->HostAdapterStatus
);
4121 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4122 if (++Request
->TimesRetry
> MaxRetry
) {
4123 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4128 } else if (Status
== EFI_DEVICE_ERROR
) {
4130 // reset the scsi channel
4132 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4133 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4137 Status
= CheckTargetStatus (Request
->TargetStatus
);
4138 if (Status
== EFI_NOT_READY
) {
4140 // reset the scsi device
4142 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4143 if (++Request
->TimesRetry
> MaxRetry
) {
4144 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4149 } else if (Status
== EFI_DEVICE_ERROR
) {
4150 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4154 if (Request
->TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) {
4155 DEBUG ((EFI_D_ERROR
, "ScsiDiskNotify: Check Condition happened!\n"));
4157 Status
= DetectMediaParsingSenseKeys (
4160 Request
->SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
),
4163 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4164 if (++Request
->TimesRetry
> MaxRetry
) {
4165 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4170 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4171 if (Request
->SectorCount
<= 1) {
4173 // Jump out if the operation still fails with one sector transfer
4176 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4180 // Try again with two half length request if the sense data shows we need
4183 Request
->SectorCount
>>= 1;
4184 Request
->DataLength
= Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4185 Request
->TimesRetry
= 0;
4189 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4195 // This sub-task succeeds, no need to retry.
4200 if (Request
->InBuffer
!= NULL
) {
4202 // SCSI read command
4204 if (!ScsiDiskDevice
->Cdb16Byte
) {
4205 Status
= ScsiDiskAsyncRead10 (
4208 Request
->TimesRetry
,
4210 Request
->DataLength
,
4211 (UINT32
) Request
->StartLba
,
4212 Request
->SectorCount
,
4217 Status
= ScsiDiskAsyncRead16 (
4220 Request
->TimesRetry
,
4222 Request
->DataLength
,
4224 Request
->SectorCount
,
4230 if (EFI_ERROR (Status
)) {
4231 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4233 } else if (OldSectorCount
!= Request
->SectorCount
) {
4235 // Original sub-task will be split into two new sub-tasks with smaller
4238 if (!ScsiDiskDevice
->Cdb16Byte
) {
4239 Status
= ScsiDiskAsyncRead10 (
4243 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4244 OldDataLength
- Request
->DataLength
,
4245 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
4246 OldSectorCount
- Request
->SectorCount
,
4251 Status
= ScsiDiskAsyncRead16 (
4255 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4256 OldDataLength
- Request
->DataLength
,
4257 Request
->StartLba
+ Request
->SectorCount
,
4258 OldSectorCount
- Request
->SectorCount
,
4263 if (EFI_ERROR (Status
)) {
4264 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4270 // SCSI write command
4272 if (!ScsiDiskDevice
->Cdb16Byte
) {
4273 Status
= ScsiDiskAsyncWrite10 (
4276 Request
->TimesRetry
,
4278 Request
->DataLength
,
4279 (UINT32
) Request
->StartLba
,
4280 Request
->SectorCount
,
4285 Status
= ScsiDiskAsyncWrite16 (
4288 Request
->TimesRetry
,
4290 Request
->DataLength
,
4292 Request
->SectorCount
,
4298 if (EFI_ERROR (Status
)) {
4299 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4301 } else if (OldSectorCount
!= Request
->SectorCount
) {
4303 // Original sub-task will be split into two new sub-tasks with smaller
4306 if (!ScsiDiskDevice
->Cdb16Byte
) {
4307 Status
= ScsiDiskAsyncWrite10 (
4311 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4312 OldDataLength
- Request
->DataLength
,
4313 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
4314 OldSectorCount
- Request
->SectorCount
,
4319 Status
= ScsiDiskAsyncWrite16 (
4323 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4324 OldDataLength
- Request
->DataLength
,
4325 Request
->StartLba
+ Request
->SectorCount
,
4326 OldSectorCount
- Request
->SectorCount
,
4331 if (EFI_ERROR (Status
)) {
4332 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4339 RemoveEntryList (&Request
->Link
);
4340 if ((IsListEmpty (&Request
->BlkIo2Req
->ScsiRWQueue
)) &&
4341 (Request
->BlkIo2Req
->LastScsiRW
)) {
4343 // The last SCSI R/W command of a BlockIo2 request completes
4345 RemoveEntryList (&Request
->BlkIo2Req
->Link
);
4346 FreePool (Request
->BlkIo2Req
); // Should be freed only once
4347 gBS
->SignalEvent (Token
->Event
);
4350 FreePool (Request
->SenseData
);
4356 Submit Async Read(10) command.
4358 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4359 @param Timeout The time to complete the command.
4360 @param TimesRetry The number of times the command has been retried.
4361 @param DataBuffer The buffer to fill with the read out data.
4362 @param DataLength The length of buffer.
4363 @param StartLba The start logic block address.
4364 @param SectorCount The number of blocks to read.
4365 @param BlkIo2Req The upstream BlockIo2 request.
4366 @param Token The pointer to the token associated with the
4367 non-blocking read request.
4369 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4371 @return others Status returned by calling
4372 ScsiRead10CommandEx().
4376 ScsiDiskAsyncRead10 (
4377 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4379 IN UINT8 TimesRetry
,
4380 OUT UINT8
*DataBuffer
,
4381 IN UINT32 DataLength
,
4383 IN UINT32 SectorCount
,
4384 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4385 IN EFI_BLOCK_IO2_TOKEN
*Token
4389 SCSI_ASYNC_RW_REQUEST
*Request
;
4390 EFI_EVENT AsyncIoEvent
;
4393 AsyncIoEvent
= NULL
;
4395 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4396 if (Request
== NULL
) {
4397 return EFI_OUT_OF_RESOURCES
;
4400 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4401 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4402 gBS
->RestoreTPL (OldTpl
);
4404 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4405 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4406 if (Request
->SenseData
== NULL
) {
4407 Status
= EFI_OUT_OF_RESOURCES
;
4411 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4412 Request
->Timeout
= Timeout
;
4413 Request
->TimesRetry
= TimesRetry
;
4414 Request
->InBuffer
= DataBuffer
;
4415 Request
->DataLength
= DataLength
;
4416 Request
->StartLba
= StartLba
;
4417 Request
->SectorCount
= SectorCount
;
4418 Request
->BlkIo2Req
= BlkIo2Req
;
4423 Status
= gBS
->CreateEvent (
4430 if (EFI_ERROR(Status
)) {
4434 Status
= ScsiRead10CommandEx (
4435 ScsiDiskDevice
->ScsiIo
,
4438 &Request
->SenseDataLength
,
4439 &Request
->HostAdapterStatus
,
4440 &Request
->TargetStatus
,
4442 &Request
->DataLength
,
4443 (UINT32
) Request
->StartLba
,
4444 Request
->SectorCount
,
4447 if (EFI_ERROR(Status
)) {
4454 if (AsyncIoEvent
!= NULL
) {
4455 gBS
->CloseEvent (AsyncIoEvent
);
4458 if (Request
!= NULL
) {
4459 if (Request
->SenseData
!= NULL
) {
4460 FreePool (Request
->SenseData
);
4463 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4464 RemoveEntryList (&Request
->Link
);
4465 gBS
->RestoreTPL (OldTpl
);
4475 Submit Async Write(10) command.
4477 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4478 @param Timeout The time to complete the command.
4479 @param TimesRetry The number of times the command has been retried.
4480 @param DataBuffer The buffer contains the data to write.
4481 @param DataLength The length of buffer.
4482 @param StartLba The start logic block address.
4483 @param SectorCount The number of blocks to write.
4484 @param BlkIo2Req The upstream BlockIo2 request.
4485 @param Token The pointer to the token associated with the
4486 non-blocking read request.
4488 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4490 @return others Status returned by calling
4491 ScsiWrite10CommandEx().
4495 ScsiDiskAsyncWrite10 (
4496 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4498 IN UINT8 TimesRetry
,
4499 IN UINT8
*DataBuffer
,
4500 IN UINT32 DataLength
,
4502 IN UINT32 SectorCount
,
4503 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4504 IN EFI_BLOCK_IO2_TOKEN
*Token
4508 SCSI_ASYNC_RW_REQUEST
*Request
;
4509 EFI_EVENT AsyncIoEvent
;
4512 AsyncIoEvent
= NULL
;
4514 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4515 if (Request
== NULL
) {
4516 return EFI_OUT_OF_RESOURCES
;
4519 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4520 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4521 gBS
->RestoreTPL (OldTpl
);
4523 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4524 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4525 if (Request
->SenseData
== NULL
) {
4526 Status
= EFI_OUT_OF_RESOURCES
;
4530 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4531 Request
->Timeout
= Timeout
;
4532 Request
->TimesRetry
= TimesRetry
;
4533 Request
->OutBuffer
= DataBuffer
;
4534 Request
->DataLength
= DataLength
;
4535 Request
->StartLba
= StartLba
;
4536 Request
->SectorCount
= SectorCount
;
4537 Request
->BlkIo2Req
= BlkIo2Req
;
4542 Status
= gBS
->CreateEvent (
4549 if (EFI_ERROR(Status
)) {
4553 Status
= ScsiWrite10CommandEx (
4554 ScsiDiskDevice
->ScsiIo
,
4557 &Request
->SenseDataLength
,
4558 &Request
->HostAdapterStatus
,
4559 &Request
->TargetStatus
,
4561 &Request
->DataLength
,
4562 (UINT32
) Request
->StartLba
,
4563 Request
->SectorCount
,
4566 if (EFI_ERROR(Status
)) {
4573 if (AsyncIoEvent
!= NULL
) {
4574 gBS
->CloseEvent (AsyncIoEvent
);
4577 if (Request
!= NULL
) {
4578 if (Request
->SenseData
!= NULL
) {
4579 FreePool (Request
->SenseData
);
4582 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4583 RemoveEntryList (&Request
->Link
);
4584 gBS
->RestoreTPL (OldTpl
);
4594 Submit Async Read(16) command.
4596 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4597 @param Timeout The time to complete the command.
4598 @param TimesRetry The number of times the command has been retried.
4599 @param DataBuffer The buffer to fill with the read out data.
4600 @param DataLength The length of buffer.
4601 @param StartLba The start logic block address.
4602 @param SectorCount The number of blocks to read.
4603 @param BlkIo2Req The upstream BlockIo2 request.
4604 @param Token The pointer to the token associated with the
4605 non-blocking read request.
4607 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4609 @return others Status returned by calling
4610 ScsiRead16CommandEx().
4614 ScsiDiskAsyncRead16 (
4615 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4617 IN UINT8 TimesRetry
,
4618 OUT UINT8
*DataBuffer
,
4619 IN UINT32 DataLength
,
4621 IN UINT32 SectorCount
,
4622 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4623 IN EFI_BLOCK_IO2_TOKEN
*Token
4627 SCSI_ASYNC_RW_REQUEST
*Request
;
4628 EFI_EVENT AsyncIoEvent
;
4631 AsyncIoEvent
= NULL
;
4633 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4634 if (Request
== NULL
) {
4635 return EFI_OUT_OF_RESOURCES
;
4638 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4639 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4640 gBS
->RestoreTPL (OldTpl
);
4642 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4643 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4644 if (Request
->SenseData
== NULL
) {
4645 Status
= EFI_OUT_OF_RESOURCES
;
4649 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4650 Request
->Timeout
= Timeout
;
4651 Request
->TimesRetry
= TimesRetry
;
4652 Request
->InBuffer
= DataBuffer
;
4653 Request
->DataLength
= DataLength
;
4654 Request
->StartLba
= StartLba
;
4655 Request
->SectorCount
= SectorCount
;
4656 Request
->BlkIo2Req
= BlkIo2Req
;
4661 Status
= gBS
->CreateEvent (
4668 if (EFI_ERROR(Status
)) {
4672 Status
= ScsiRead16CommandEx (
4673 ScsiDiskDevice
->ScsiIo
,
4676 &Request
->SenseDataLength
,
4677 &Request
->HostAdapterStatus
,
4678 &Request
->TargetStatus
,
4680 &Request
->DataLength
,
4682 Request
->SectorCount
,
4685 if (EFI_ERROR(Status
)) {
4692 if (AsyncIoEvent
!= NULL
) {
4693 gBS
->CloseEvent (AsyncIoEvent
);
4696 if (Request
!= NULL
) {
4697 if (Request
->SenseData
!= NULL
) {
4698 FreePool (Request
->SenseData
);
4701 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4702 RemoveEntryList (&Request
->Link
);
4703 gBS
->RestoreTPL (OldTpl
);
4713 Submit Async Write(16) command.
4715 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4716 @param Timeout The time to complete the command.
4717 @param TimesRetry The number of times the command has been retried.
4718 @param DataBuffer The buffer contains the data to write.
4719 @param DataLength The length of buffer.
4720 @param StartLba The start logic block address.
4721 @param SectorCount The number of blocks to write.
4722 @param BlkIo2Req The upstream BlockIo2 request.
4723 @param Token The pointer to the token associated with the
4724 non-blocking read request.
4726 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4728 @return others Status returned by calling
4729 ScsiWrite16CommandEx().
4733 ScsiDiskAsyncWrite16 (
4734 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4736 IN UINT8 TimesRetry
,
4737 IN UINT8
*DataBuffer
,
4738 IN UINT32 DataLength
,
4740 IN UINT32 SectorCount
,
4741 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4742 IN EFI_BLOCK_IO2_TOKEN
*Token
4746 SCSI_ASYNC_RW_REQUEST
*Request
;
4747 EFI_EVENT AsyncIoEvent
;
4750 AsyncIoEvent
= NULL
;
4752 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4753 if (Request
== NULL
) {
4754 return EFI_OUT_OF_RESOURCES
;
4757 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4758 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4759 gBS
->RestoreTPL (OldTpl
);
4761 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4762 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4763 if (Request
->SenseData
== NULL
) {
4764 Status
= EFI_OUT_OF_RESOURCES
;
4768 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4769 Request
->Timeout
= Timeout
;
4770 Request
->TimesRetry
= TimesRetry
;
4771 Request
->OutBuffer
= DataBuffer
;
4772 Request
->DataLength
= DataLength
;
4773 Request
->StartLba
= StartLba
;
4774 Request
->SectorCount
= SectorCount
;
4775 Request
->BlkIo2Req
= BlkIo2Req
;
4780 Status
= gBS
->CreateEvent (
4787 if (EFI_ERROR(Status
)) {
4791 Status
= ScsiWrite16CommandEx (
4792 ScsiDiskDevice
->ScsiIo
,
4795 &Request
->SenseDataLength
,
4796 &Request
->HostAdapterStatus
,
4797 &Request
->TargetStatus
,
4799 &Request
->DataLength
,
4801 Request
->SectorCount
,
4804 if (EFI_ERROR(Status
)) {
4811 if (AsyncIoEvent
!= NULL
) {
4812 gBS
->CloseEvent (AsyncIoEvent
);
4815 if (Request
!= NULL
) {
4816 if (Request
->SenseData
!= NULL
) {
4817 FreePool (Request
->SenseData
);
4820 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4821 RemoveEntryList (&Request
->Link
);
4822 gBS
->RestoreTPL (OldTpl
);
4832 Check sense key to find if media presents.
4834 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4835 @param SenseCounts The number of sense key
4837 @retval TRUE NOT any media
4838 @retval FALSE Media presents
4842 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4843 IN UINTN SenseCounts
4846 EFI_SCSI_SENSE_DATA
*SensePtr
;
4851 SensePtr
= SenseData
;
4853 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4855 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
4856 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
4858 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
4859 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
4872 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4873 @param SenseCounts The number of sense key
4876 @retval FALSE NOT error
4880 ScsiDiskIsMediaError (
4881 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4882 IN UINTN SenseCounts
4885 EFI_SCSI_SENSE_DATA
*SensePtr
;
4890 SensePtr
= SenseData
;
4892 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4894 switch (SensePtr
->Sense_Key
) {
4896 case EFI_SCSI_SK_MEDIUM_ERROR
:
4898 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
4900 switch (SensePtr
->Addnl_Sense_Code
) {
4905 case EFI_SCSI_ASC_MEDIA_ERR1
:
4910 case EFI_SCSI_ASC_MEDIA_ERR2
:
4915 case EFI_SCSI_ASC_MEDIA_ERR3
:
4916 case EFI_SCSI_ASC_MEDIA_ERR4
:
4926 case EFI_SCSI_SK_NOT_READY
:
4928 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4930 switch (SensePtr
->Addnl_Sense_Code
) {
4932 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
4934 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
4955 Check sense key to find if hardware error happens.
4957 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4958 @param SenseCounts The number of sense key
4960 @retval TRUE Hardware error exits.
4961 @retval FALSE NO error.
4965 ScsiDiskIsHardwareError (
4966 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4967 IN UINTN SenseCounts
4970 EFI_SCSI_SENSE_DATA
*SensePtr
;
4975 SensePtr
= SenseData
;
4977 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4980 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
4982 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
4994 Check sense key to find if media has changed.
4996 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4997 @param SenseCounts The number of sense key
4999 @retval TRUE Media is changed.
5000 @retval FALSE Media is NOT changed.
5003 ScsiDiskIsMediaChange (
5004 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5005 IN UINTN SenseCounts
5008 EFI_SCSI_SENSE_DATA
*SensePtr
;
5010 BOOLEAN IsMediaChanged
;
5012 IsMediaChanged
= FALSE
;
5013 SensePtr
= SenseData
;
5015 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5017 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
5018 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
5020 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
5021 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
5022 IsMediaChanged
= TRUE
;
5028 return IsMediaChanged
;
5032 Check sense key to find if reset happens.
5034 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5035 @param SenseCounts The number of sense key
5037 @retval TRUE It is reset before.
5038 @retval FALSE It is NOT reset before.
5042 ScsiDiskIsResetBefore (
5043 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5044 IN UINTN SenseCounts
5047 EFI_SCSI_SENSE_DATA
*SensePtr
;
5049 BOOLEAN IsResetBefore
;
5051 IsResetBefore
= FALSE
;
5052 SensePtr
= SenseData
;
5054 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5057 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
5058 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
5060 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
5061 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
5062 IsResetBefore
= TRUE
;
5068 return IsResetBefore
;
5072 Check sense key to find if the drive is ready.
5074 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5075 @param SenseCounts The number of sense key
5076 @param RetryLater The flag means if need a retry
5078 @retval TRUE Drive is ready.
5079 @retval FALSE Drive is NOT ready.
5083 ScsiDiskIsDriveReady (
5084 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5085 IN UINTN SenseCounts
,
5086 OUT BOOLEAN
*RetryLater
5089 EFI_SCSI_SENSE_DATA
*SensePtr
;
5094 *RetryLater
= FALSE
;
5095 SensePtr
= SenseData
;
5097 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5099 switch (SensePtr
->Sense_Key
) {
5101 case EFI_SCSI_SK_NOT_READY
:
5103 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5105 switch (SensePtr
->Addnl_Sense_Code
) {
5106 case EFI_SCSI_ASC_NOT_READY
:
5108 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
5110 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
5111 case EFI_SCSI_ASCQ_IN_PROGRESS
:
5113 // Additional Sense Code Qualifier is
5114 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
5122 *RetryLater
= FALSE
;
5143 Check sense key to find if it has sense key.
5145 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
5146 @param SenseCounts - The number of sense key
5148 @retval TRUE It has sense key.
5149 @retval FALSE It has NOT any sense key.
5153 ScsiDiskHaveSenseKey (
5154 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5155 IN UINTN SenseCounts
5158 EFI_SCSI_SENSE_DATA
*SensePtr
;
5160 BOOLEAN HaveSenseKey
;
5162 if (SenseCounts
== 0) {
5163 HaveSenseKey
= FALSE
;
5165 HaveSenseKey
= TRUE
;
5168 SensePtr
= SenseData
;
5170 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5173 // Sense Key is SK_NO_SENSE (0x0)
5175 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
5177 HaveSenseKey
= FALSE
;
5183 return HaveSenseKey
;
5187 Release resource about disk device.
5189 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
5193 ReleaseScsiDiskDeviceResources (
5194 IN SCSI_DISK_DEV
*ScsiDiskDevice
5197 if (ScsiDiskDevice
== NULL
) {
5201 if (ScsiDiskDevice
->SenseData
!= NULL
) {
5202 FreePool (ScsiDiskDevice
->SenseData
);
5203 ScsiDiskDevice
->SenseData
= NULL
;
5206 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
5207 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
5208 ScsiDiskDevice
->ControllerNameTable
= NULL
;
5211 FreePool (ScsiDiskDevice
);
5213 ScsiDiskDevice
= NULL
;
5217 Determine if Block Io & Block Io2 should be produced.
5220 @param ChildHandle Child Handle to retrieve Parent information.
5222 @retval TRUE Should produce Block Io & Block Io2.
5223 @retval FALSE Should not produce Block Io & Block Io2.
5227 DetermineInstallBlockIo (
5228 IN EFI_HANDLE ChildHandle
5231 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
5232 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
5235 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
5236 // check its attribute, logic or physical.
5238 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
5239 if (ExtScsiPassThru
!= NULL
) {
5240 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
5246 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
5247 // check its attribute, logic or physical.
5249 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
5250 if (ScsiPassThru
!= NULL
) {
5251 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
5260 Search protocol database and check to see if the protocol
5261 specified by ProtocolGuid is present on a ControllerHandle and opened by
5262 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
5263 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
5264 will be opened on it.
5267 @param ProtocolGuid ProtocolGuid pointer.
5268 @param ChildHandle Child Handle to retrieve Parent information.
5274 IN EFI_GUID
*ProtocolGuid
,
5275 IN EFI_HANDLE ChildHandle
5282 EFI_HANDLE
*HandleBuffer
;
5285 // Retrieve the list of all handles from the handle database
5287 Status
= gBS
->LocateHandleBuffer (
5295 if (EFI_ERROR (Status
)) {
5300 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
5302 for (Index
= 0; Index
< HandleCount
; Index
++) {
5303 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
5304 if (!EFI_ERROR (Status
)) {
5305 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
5306 if (!EFI_ERROR (Status
)) {
5307 gBS
->FreePool (HandleBuffer
);
5313 gBS
->FreePool (HandleBuffer
);
5318 Determine if EFI Erase Block Protocol should be produced.
5320 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
5321 @param ChildHandle Handle of device.
5323 @retval TRUE Should produce EFI Erase Block Protocol.
5324 @retval FALSE Should not produce EFI Erase Block Protocol.
5328 DetermineInstallEraseBlock (
5329 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5330 IN EFI_HANDLE ChildHandle
5333 UINT8 HostAdapterStatus
;
5335 EFI_STATUS CommandStatus
;
5339 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
5340 UINT8 SenseDataLength
;
5341 UINT32 DataLength16
;
5342 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
5346 CapacityData16
= NULL
;
5348 Status
= gBS
->HandleProtocol (
5350 &gEfiDevicePathProtocolGuid
,
5351 (VOID
**) &DevicePathNode
5354 // Device Path protocol must be installed on the device handle.
5356 ASSERT_EFI_ERROR (Status
);
5358 while (!IsDevicePathEndType (DevicePathNode
)) {
5360 // For now, only support Erase Block Protocol on UFS devices.
5362 if ((DevicePathNode
->Type
== MESSAGING_DEVICE_PATH
) &&
5363 (DevicePathNode
->SubType
== MSG_UFS_DP
)) {
5368 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
5376 // Check whether the erase functionality is enabled on the UFS device.
5378 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
5379 if (CapacityData16
== NULL
) {
5384 SenseDataLength
= 0;
5385 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
5386 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
5388 CommandStatus
= ScsiReadCapacity16Command (
5389 ScsiDiskDevice
->ScsiIo
,
5395 (VOID
*) CapacityData16
,
5400 if (CommandStatus
== EFI_SUCCESS
) {
5402 // Universal Flash Storage (UFS) Version 2.0
5404 // Bits TPE and TPRZ should both be set to enable the erase feature on UFS.
5406 if (((CapacityData16
->LowestAlignLogic2
& BIT7
) == 0) ||
5407 ((CapacityData16
->LowestAlignLogic2
& BIT6
) == 0)) {
5410 "ScsiDisk EraseBlock: Either TPE or TPRZ is not set: 0x%x.\n",
5411 CapacityData16
->LowestAlignLogic2
5420 "ScsiDisk EraseBlock: ReadCapacity16 failed with status %r.\n",
5429 // Check whether the UFS device server implements the UNMAP command.
5431 if ((ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
== 0) ||
5432 (ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
== 0)) {
5435 "ScsiDisk EraseBlock: The device server does not implement the UNMAP command.\n"
5443 if (CapacityData16
!= NULL
) {
5444 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
5451 Provides inquiry information for the controller type.
5453 This function is used by the IDE bus driver to get inquiry data. Data format
5454 of Identify data is defined by the Interface GUID.
5456 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
5457 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
5458 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
5460 @retval EFI_SUCCESS The command was accepted without any errors.
5461 @retval EFI_NOT_FOUND Device does not support this data class
5462 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
5463 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
5468 ScsiDiskInfoInquiry (
5469 IN EFI_DISK_INFO_PROTOCOL
*This
,
5470 IN OUT VOID
*InquiryData
,
5471 IN OUT UINT32
*InquiryDataSize
5475 SCSI_DISK_DEV
*ScsiDiskDevice
;
5477 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
5479 Status
= EFI_BUFFER_TOO_SMALL
;
5480 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
5481 Status
= EFI_SUCCESS
;
5482 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
5484 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
5490 Provides identify information for the controller type.
5492 This function is used by the IDE bus driver to get identify data. Data format
5493 of Identify data is defined by the Interface GUID.
5495 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
5497 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
5498 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
5501 @retval EFI_SUCCESS The command was accepted without any errors.
5502 @retval EFI_NOT_FOUND Device does not support this data class
5503 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
5504 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
5509 ScsiDiskInfoIdentify (
5510 IN EFI_DISK_INFO_PROTOCOL
*This
,
5511 IN OUT VOID
*IdentifyData
,
5512 IN OUT UINT32
*IdentifyDataSize
5516 SCSI_DISK_DEV
*ScsiDiskDevice
;
5518 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
5520 // Physical SCSI bus does not support this data class.
5522 return EFI_NOT_FOUND
;
5525 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
5527 Status
= EFI_BUFFER_TOO_SMALL
;
5528 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
5529 Status
= EFI_SUCCESS
;
5530 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
5532 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
5537 Provides sense data information for the controller type.
5539 This function is used by the IDE bus driver to get sense data.
5540 Data format of Sense data is defined by the Interface GUID.
5542 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
5543 @param[in, out] SenseData Pointer to the SenseData.
5544 @param[in, out] SenseDataSize Size of SenseData in bytes.
5545 @param[out] SenseDataNumber Pointer to the value for the sense data size.
5547 @retval EFI_SUCCESS The command was accepted without any errors.
5548 @retval EFI_NOT_FOUND Device does not support this data class.
5549 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
5550 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
5555 ScsiDiskInfoSenseData (
5556 IN EFI_DISK_INFO_PROTOCOL
*This
,
5557 IN OUT VOID
*SenseData
,
5558 IN OUT UINT32
*SenseDataSize
,
5559 OUT UINT8
*SenseDataNumber
5562 return EFI_NOT_FOUND
;
5567 This function is used by the IDE bus driver to get controller information.
5569 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
5570 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
5571 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
5573 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
5574 @retval EFI_UNSUPPORTED This is not an IDE device.
5579 ScsiDiskInfoWhichIde (
5580 IN EFI_DISK_INFO_PROTOCOL
*This
,
5581 OUT UINT32
*IdeChannel
,
5582 OUT UINT32
*IdeDevice
5585 SCSI_DISK_DEV
*ScsiDiskDevice
;
5587 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
5589 // This is not an IDE physical device.
5591 return EFI_UNSUPPORTED
;
5594 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
5595 *IdeChannel
= ScsiDiskDevice
->Channel
;
5596 *IdeDevice
= ScsiDiskDevice
->Device
;
5603 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
5605 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
5606 implement Identify() interface for DiskInfo protocol. The ATA command is sent
5607 via SCSI Request Packet.
5609 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
5611 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
5612 @retval others Some error occurred during the identification that ATAPI device.
5616 AtapiIdentifyDevice (
5617 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
5620 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
5624 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
5626 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
5627 ZeroMem (Cdb
, sizeof (Cdb
));
5629 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
5630 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
5631 CommandPacket
.Cdb
= Cdb
;
5632 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
5633 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
5634 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
5636 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
5641 Initialize the installation of DiskInfo protocol.
5643 This function prepares for the installation of DiskInfo protocol on the child handle.
5644 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
5645 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
5646 to be IDE/AHCI interface GUID.
5648 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
5649 @param ChildHandle Child handle to install DiskInfo protocol.
5653 InitializeInstallDiskInfo (
5654 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5655 IN EFI_HANDLE ChildHandle
5659 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
5660 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
5661 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
5662 SATA_DEVICE_PATH
*SataDevicePath
;
5663 UINTN IdentifyRetry
;
5665 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
5667 // Device Path protocol must be installed on the device handle.
5669 ASSERT_EFI_ERROR (Status
);
5671 // Copy the DiskInfo protocol template.
5673 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
5675 while (!IsDevicePathEnd (DevicePathNode
)) {
5676 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
5677 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
5678 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
5679 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
5680 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
5681 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
5686 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
5687 // with IDE/AHCI interface GUID.
5689 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
5690 if (!EFI_ERROR (Status
)) {
5691 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
5693 // We find the valid ATAPI device path
5695 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
5696 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
5697 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
5699 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
5701 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
5704 // We find the valid SATA device path
5706 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
5707 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
5708 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
5710 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
5712 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
5716 } while (--IdentifyRetry
> 0);
5717 } else if ((DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
5718 (DevicePathSubType (ChildDevicePathNode
) == MSG_UFS_DP
)) {
5719 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoUfsInterfaceGuid
);
5722 DevicePathNode
= ChildDevicePathNode
;