2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 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
);
571 Media
= ScsiDiskDevice
->BlkIo
.Media
;
573 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
575 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
576 if (EFI_ERROR (Status
)) {
577 Status
= EFI_DEVICE_ERROR
;
582 gBS
->ReinstallProtocolInterface (
583 ScsiDiskDevice
->Handle
,
584 &gEfiBlockIoProtocolGuid
,
585 &ScsiDiskDevice
->BlkIo
,
586 &ScsiDiskDevice
->BlkIo
588 gBS
->ReinstallProtocolInterface (
589 ScsiDiskDevice
->Handle
,
590 &gEfiBlockIo2ProtocolGuid
,
591 &ScsiDiskDevice
->BlkIo2
,
592 &ScsiDiskDevice
->BlkIo2
594 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
595 gBS
->ReinstallProtocolInterface (
596 ScsiDiskDevice
->Handle
,
597 &gEfiEraseBlockProtocolGuid
,
598 &ScsiDiskDevice
->EraseBlock
,
599 &ScsiDiskDevice
->EraseBlock
602 if (Media
->MediaPresent
) {
603 Status
= EFI_MEDIA_CHANGED
;
605 Status
= EFI_NO_MEDIA
;
611 // Get the intrinsic block size
613 BlockSize
= Media
->BlockSize
;
615 NumberOfBlocks
= BufferSize
/ BlockSize
;
617 if (!(Media
->MediaPresent
)) {
618 Status
= EFI_NO_MEDIA
;
622 if (MediaId
!= Media
->MediaId
) {
623 Status
= EFI_MEDIA_CHANGED
;
627 if (Buffer
== NULL
) {
628 Status
= EFI_INVALID_PARAMETER
;
632 if (BufferSize
== 0) {
633 Status
= EFI_SUCCESS
;
637 if (BufferSize
% BlockSize
!= 0) {
638 Status
= EFI_BAD_BUFFER_SIZE
;
642 if (Lba
> Media
->LastBlock
) {
643 Status
= EFI_INVALID_PARAMETER
;
647 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
648 Status
= EFI_INVALID_PARAMETER
;
652 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
653 Status
= EFI_INVALID_PARAMETER
;
658 // If all the parameters are valid, then perform read sectors command
659 // to transfer data from device to host.
661 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
664 gBS
->RestoreTPL (OldTpl
);
669 The function is to Write Block to SCSI Disk.
671 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
672 @param MediaId The Id of Media detected
673 @param Lba The logic block address
674 @param BufferSize The size of Buffer
675 @param Buffer The buffer to fill the read out data
677 @retval EFI_SUCCESS Successfully to read out block.
678 @retval EFI_WRITE_PROTECTED The device can not be written to.
679 @retval EFI_DEVICE_ERROR Fail to detect media.
680 @retval EFI_NO_MEDIA Media is not present.
681 @retval EFI_MEDIA_CHNAGED Media has changed.
682 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
683 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
688 ScsiDiskWriteBlocks (
689 IN EFI_BLOCK_IO_PROTOCOL
*This
,
696 SCSI_DISK_DEV
*ScsiDiskDevice
;
697 EFI_BLOCK_IO_MEDIA
*Media
;
700 UINTN NumberOfBlocks
;
705 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
706 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
707 Media
= ScsiDiskDevice
->BlkIo
.Media
;
709 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
711 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
712 if (EFI_ERROR (Status
)) {
713 Status
= EFI_DEVICE_ERROR
;
718 gBS
->ReinstallProtocolInterface (
719 ScsiDiskDevice
->Handle
,
720 &gEfiBlockIoProtocolGuid
,
721 &ScsiDiskDevice
->BlkIo
,
722 &ScsiDiskDevice
->BlkIo
724 gBS
->ReinstallProtocolInterface (
725 ScsiDiskDevice
->Handle
,
726 &gEfiBlockIo2ProtocolGuid
,
727 &ScsiDiskDevice
->BlkIo2
,
728 &ScsiDiskDevice
->BlkIo2
730 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
731 gBS
->ReinstallProtocolInterface (
732 ScsiDiskDevice
->Handle
,
733 &gEfiEraseBlockProtocolGuid
,
734 &ScsiDiskDevice
->EraseBlock
,
735 &ScsiDiskDevice
->EraseBlock
738 if (Media
->MediaPresent
) {
739 Status
= EFI_MEDIA_CHANGED
;
741 Status
= EFI_NO_MEDIA
;
747 // Get the intrinsic block size
749 BlockSize
= Media
->BlockSize
;
751 NumberOfBlocks
= BufferSize
/ BlockSize
;
753 if (!(Media
->MediaPresent
)) {
754 Status
= EFI_NO_MEDIA
;
758 if (MediaId
!= Media
->MediaId
) {
759 Status
= EFI_MEDIA_CHANGED
;
763 if (Media
->ReadOnly
) {
764 Status
= EFI_WRITE_PROTECTED
;
768 if (BufferSize
== 0) {
769 Status
= EFI_SUCCESS
;
773 if (Buffer
== NULL
) {
774 Status
= EFI_INVALID_PARAMETER
;
778 if (BufferSize
% BlockSize
!= 0) {
779 Status
= EFI_BAD_BUFFER_SIZE
;
783 if (Lba
> Media
->LastBlock
) {
784 Status
= EFI_INVALID_PARAMETER
;
788 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
789 Status
= EFI_INVALID_PARAMETER
;
793 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
794 Status
= EFI_INVALID_PARAMETER
;
798 // if all the parameters are valid, then perform read sectors command
799 // to transfer data from device to host.
801 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
804 gBS
->RestoreTPL (OldTpl
);
811 EFI_SUCCESS is returned directly.
813 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
815 @retval EFI_SUCCESS All outstanding data was written to the device
820 ScsiDiskFlushBlocks (
821 IN EFI_BLOCK_IO_PROTOCOL
*This
834 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
835 @param ExtendedVerification The flag about if extend verificate.
837 @retval EFI_SUCCESS The device was reset.
838 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
840 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
846 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
847 IN BOOLEAN ExtendedVerification
851 SCSI_DISK_DEV
*ScsiDiskDevice
;
854 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
856 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
858 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
860 if (EFI_ERROR (Status
)) {
861 if (Status
== EFI_UNSUPPORTED
) {
862 Status
= EFI_SUCCESS
;
864 Status
= EFI_DEVICE_ERROR
;
869 if (!ExtendedVerification
) {
873 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
875 if (EFI_ERROR (Status
)) {
876 Status
= EFI_DEVICE_ERROR
;
881 gBS
->RestoreTPL (OldTpl
);
886 The function is to Read Block from SCSI Disk.
888 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
889 @param MediaId The Id of Media detected.
890 @param Lba The logic block address.
891 @param Token A pointer to the token associated with the transaction.
892 @param BufferSize The size of Buffer.
893 @param Buffer The buffer to fill the read out data.
895 @retval EFI_SUCCESS The read request was queued if Token-> Event is
896 not NULL. The data was read correctly from the
897 device if theToken-> Event is NULL.
898 @retval EFI_DEVICE_ERROR The device reported an error while attempting
899 to perform the read operation.
900 @retval EFI_NO_MEDIA There is no media in the device.
901 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
902 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
903 the intrinsic block size of the device.
904 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
905 valid, or the buffer is not on proper
907 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
913 ScsiDiskReadBlocksEx (
914 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
917 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
922 SCSI_DISK_DEV
*ScsiDiskDevice
;
923 EFI_BLOCK_IO_MEDIA
*Media
;
926 UINTN NumberOfBlocks
;
931 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
932 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
933 Media
= ScsiDiskDevice
->BlkIo
.Media
;
935 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
937 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
938 if (EFI_ERROR (Status
)) {
939 Status
= EFI_DEVICE_ERROR
;
944 gBS
->ReinstallProtocolInterface (
945 ScsiDiskDevice
->Handle
,
946 &gEfiBlockIoProtocolGuid
,
947 &ScsiDiskDevice
->BlkIo
,
948 &ScsiDiskDevice
->BlkIo
950 gBS
->ReinstallProtocolInterface (
951 ScsiDiskDevice
->Handle
,
952 &gEfiBlockIo2ProtocolGuid
,
953 &ScsiDiskDevice
->BlkIo2
,
954 &ScsiDiskDevice
->BlkIo2
956 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
957 gBS
->ReinstallProtocolInterface (
958 ScsiDiskDevice
->Handle
,
959 &gEfiEraseBlockProtocolGuid
,
960 &ScsiDiskDevice
->EraseBlock
,
961 &ScsiDiskDevice
->EraseBlock
964 if (Media
->MediaPresent
) {
965 Status
= EFI_MEDIA_CHANGED
;
967 Status
= EFI_NO_MEDIA
;
973 // Get the intrinsic block size
975 BlockSize
= Media
->BlockSize
;
977 NumberOfBlocks
= BufferSize
/ BlockSize
;
979 if (!(Media
->MediaPresent
)) {
980 Status
= EFI_NO_MEDIA
;
984 if (MediaId
!= Media
->MediaId
) {
985 Status
= EFI_MEDIA_CHANGED
;
989 if (Buffer
== NULL
) {
990 Status
= EFI_INVALID_PARAMETER
;
994 if (BufferSize
== 0) {
995 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
996 Token
->TransactionStatus
= EFI_SUCCESS
;
997 gBS
->SignalEvent (Token
->Event
);
1000 Status
= EFI_SUCCESS
;
1004 if (BufferSize
% BlockSize
!= 0) {
1005 Status
= EFI_BAD_BUFFER_SIZE
;
1009 if (Lba
> Media
->LastBlock
) {
1010 Status
= EFI_INVALID_PARAMETER
;
1014 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1015 Status
= EFI_INVALID_PARAMETER
;
1019 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1020 Status
= EFI_INVALID_PARAMETER
;
1025 // If all the parameters are valid, then perform read sectors command
1026 // to transfer data from device to host.
1028 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1029 Token
->TransactionStatus
= EFI_SUCCESS
;
1030 Status
= ScsiDiskAsyncReadSectors (
1038 Status
= ScsiDiskReadSectors (
1047 gBS
->RestoreTPL (OldTpl
);
1052 The function is to Write Block to SCSI Disk.
1054 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
1055 @param MediaId The Id of Media detected.
1056 @param Lba The logic block address.
1057 @param Token A pointer to the token associated with the transaction.
1058 @param BufferSize The size of Buffer.
1059 @param Buffer The buffer to fill the read out data.
1061 @retval EFI_SUCCESS The data were written correctly to the device.
1062 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1063 @retval EFI_NO_MEDIA There is no media in the device.
1064 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1065 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1066 to perform the write operation.
1067 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
1068 the intrinsic block size of the device.
1069 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
1070 valid, or the buffer is not on proper
1076 ScsiDiskWriteBlocksEx (
1077 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1080 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1081 IN UINTN BufferSize
,
1085 SCSI_DISK_DEV
*ScsiDiskDevice
;
1086 EFI_BLOCK_IO_MEDIA
*Media
;
1089 UINTN NumberOfBlocks
;
1090 BOOLEAN MediaChange
;
1093 MediaChange
= FALSE
;
1094 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1095 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1096 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1098 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1100 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1101 if (EFI_ERROR (Status
)) {
1102 Status
= EFI_DEVICE_ERROR
;
1107 gBS
->ReinstallProtocolInterface (
1108 ScsiDiskDevice
->Handle
,
1109 &gEfiBlockIoProtocolGuid
,
1110 &ScsiDiskDevice
->BlkIo
,
1111 &ScsiDiskDevice
->BlkIo
1113 gBS
->ReinstallProtocolInterface (
1114 ScsiDiskDevice
->Handle
,
1115 &gEfiBlockIo2ProtocolGuid
,
1116 &ScsiDiskDevice
->BlkIo2
,
1117 &ScsiDiskDevice
->BlkIo2
1119 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1120 gBS
->ReinstallProtocolInterface (
1121 ScsiDiskDevice
->Handle
,
1122 &gEfiEraseBlockProtocolGuid
,
1123 &ScsiDiskDevice
->EraseBlock
,
1124 &ScsiDiskDevice
->EraseBlock
1127 if (Media
->MediaPresent
) {
1128 Status
= EFI_MEDIA_CHANGED
;
1130 Status
= EFI_NO_MEDIA
;
1136 // Get the intrinsic block size
1138 BlockSize
= Media
->BlockSize
;
1140 NumberOfBlocks
= BufferSize
/ BlockSize
;
1142 if (!(Media
->MediaPresent
)) {
1143 Status
= EFI_NO_MEDIA
;
1147 if (MediaId
!= Media
->MediaId
) {
1148 Status
= EFI_MEDIA_CHANGED
;
1152 if (Media
->ReadOnly
) {
1153 Status
= EFI_WRITE_PROTECTED
;
1157 if (BufferSize
== 0) {
1158 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1159 Token
->TransactionStatus
= EFI_SUCCESS
;
1160 gBS
->SignalEvent (Token
->Event
);
1163 Status
= EFI_SUCCESS
;
1167 if (Buffer
== NULL
) {
1168 Status
= EFI_INVALID_PARAMETER
;
1172 if (BufferSize
% BlockSize
!= 0) {
1173 Status
= EFI_BAD_BUFFER_SIZE
;
1177 if (Lba
> Media
->LastBlock
) {
1178 Status
= EFI_INVALID_PARAMETER
;
1182 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1183 Status
= EFI_INVALID_PARAMETER
;
1187 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1188 Status
= EFI_INVALID_PARAMETER
;
1193 // if all the parameters are valid, then perform write sectors command
1194 // to transfer data from device to host.
1196 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1197 Token
->TransactionStatus
= EFI_SUCCESS
;
1198 Status
= ScsiDiskAsyncWriteSectors (
1206 Status
= ScsiDiskWriteSectors (
1215 gBS
->RestoreTPL (OldTpl
);
1220 Flush the Block Device.
1222 @param This Indicates a pointer to the calling context.
1223 @param Token A pointer to the token associated with the transaction.
1225 @retval EFI_SUCCESS All outstanding data was written to the device.
1226 @retval EFI_DEVICE_ERROR The device reported an error while attempting to
1228 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1229 @retval EFI_NO_MEDIA There is no media in the device.
1230 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1235 ScsiDiskFlushBlocksEx (
1236 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1237 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1240 SCSI_DISK_DEV
*ScsiDiskDevice
;
1241 EFI_BLOCK_IO_MEDIA
*Media
;
1243 BOOLEAN MediaChange
;
1246 MediaChange
= FALSE
;
1247 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1248 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1249 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1251 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1253 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1254 if (EFI_ERROR (Status
)) {
1255 Status
= EFI_DEVICE_ERROR
;
1260 gBS
->ReinstallProtocolInterface (
1261 ScsiDiskDevice
->Handle
,
1262 &gEfiBlockIoProtocolGuid
,
1263 &ScsiDiskDevice
->BlkIo
,
1264 &ScsiDiskDevice
->BlkIo
1266 gBS
->ReinstallProtocolInterface (
1267 ScsiDiskDevice
->Handle
,
1268 &gEfiBlockIo2ProtocolGuid
,
1269 &ScsiDiskDevice
->BlkIo2
,
1270 &ScsiDiskDevice
->BlkIo2
1272 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1273 gBS
->ReinstallProtocolInterface (
1274 ScsiDiskDevice
->Handle
,
1275 &gEfiEraseBlockProtocolGuid
,
1276 &ScsiDiskDevice
->EraseBlock
,
1277 &ScsiDiskDevice
->EraseBlock
1280 if (Media
->MediaPresent
) {
1281 Status
= EFI_MEDIA_CHANGED
;
1283 Status
= EFI_NO_MEDIA
;
1289 if (!(Media
->MediaPresent
)) {
1290 Status
= EFI_NO_MEDIA
;
1294 if (Media
->ReadOnly
) {
1295 Status
= EFI_WRITE_PROTECTED
;
1300 // Wait for the BlockIo2 requests queue to become empty
1302 while (!IsListEmpty (&ScsiDiskDevice
->AsyncTaskQueue
));
1304 Status
= EFI_SUCCESS
;
1307 // Signal caller event
1309 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1310 Token
->TransactionStatus
= EFI_SUCCESS
;
1311 gBS
->SignalEvent (Token
->Event
);
1315 gBS
->RestoreTPL (OldTpl
);
1321 Internal helper notify function which process the result of an asynchronous
1322 SCSI UNMAP Command and signal the event passed from EraseBlocks.
1324 @param Event The instance of EFI_EVENT.
1325 @param Context The parameter passed in.
1330 ScsiDiskAsyncUnmapNotify (
1335 SCSI_ERASEBLK_REQUEST
*EraseBlkReq
;
1336 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*CommandPacket
;
1337 EFI_ERASE_BLOCK_TOKEN
*Token
;
1340 gBS
->CloseEvent (Event
);
1342 EraseBlkReq
= (SCSI_ERASEBLK_REQUEST
*) Context
;
1343 CommandPacket
= &EraseBlkReq
->CommandPacket
;
1344 Token
= EraseBlkReq
->Token
;
1345 Token
->TransactionStatus
= EFI_SUCCESS
;
1347 Status
= CheckHostAdapterStatus (CommandPacket
->HostAdapterStatus
);
1348 if (EFI_ERROR(Status
)) {
1351 "ScsiDiskAsyncUnmapNotify: Host adapter indicating error status 0x%x.\n",
1352 CommandPacket
->HostAdapterStatus
1355 Token
->TransactionStatus
= Status
;
1359 Status
= CheckTargetStatus (CommandPacket
->TargetStatus
);
1360 if (EFI_ERROR(Status
)) {
1363 "ScsiDiskAsyncUnmapNotify: Target indicating error status 0x%x.\n",
1364 CommandPacket
->HostAdapterStatus
1367 Token
->TransactionStatus
= Status
;
1372 RemoveEntryList (&EraseBlkReq
->Link
);
1373 FreePool (CommandPacket
->OutDataBuffer
);
1374 FreePool (EraseBlkReq
->CommandPacket
.Cdb
);
1375 FreePool (EraseBlkReq
);
1377 gBS
->SignalEvent (Token
->Event
);
1381 Require the device server to cause one or more LBAs to be unmapped.
1383 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
1384 @param Lba The start block number.
1385 @param Blocks Total block number to be unmapped.
1386 @param Token The pointer to the token associated with the
1387 non-blocking erase block request.
1389 @retval EFI_SUCCESS Target blocks have been successfully unmapped.
1390 @retval EFI_DEVICE_ERROR Fail to unmap the target blocks.
1395 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1398 IN EFI_ERASE_BLOCK_TOKEN
*Token OPTIONAL
1401 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
1402 SCSI_ERASEBLK_REQUEST
*EraseBlkReq
;
1403 EFI_SCSI_IO_SCSI_REQUEST_PACKET
*CommandPacket
;
1404 EFI_SCSI_DISK_UNMAP_BLOCK_DESP
*BlkDespPtr
;
1406 EFI_STATUS ReturnStatus
;
1409 UINT32 MaxBlkDespCnt
;
1411 UINT16 UnmapParamListLen
;
1412 VOID
*UnmapParamList
;
1413 EFI_EVENT AsyncUnmapEvent
;
1416 ScsiIo
= ScsiDiskDevice
->ScsiIo
;
1417 MaxLbaCnt
= ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
;
1418 MaxBlkDespCnt
= ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
;
1420 UnmapParamList
= NULL
;
1421 AsyncUnmapEvent
= NULL
;
1422 ReturnStatus
= EFI_SUCCESS
;
1424 if (Blocks
/ (UINTN
) MaxLbaCnt
> MaxBlkDespCnt
) {
1425 ReturnStatus
= EFI_DEVICE_ERROR
;
1429 EraseBlkReq
= AllocateZeroPool (sizeof (SCSI_ERASEBLK_REQUEST
));
1430 if (EraseBlkReq
== NULL
) {
1431 ReturnStatus
= EFI_DEVICE_ERROR
;
1435 EraseBlkReq
->CommandPacket
.Cdb
= AllocateZeroPool (0xA);
1436 if (EraseBlkReq
->CommandPacket
.Cdb
== NULL
) {
1437 ReturnStatus
= EFI_DEVICE_ERROR
;
1441 BlkDespCnt
= (UINT32
) ((Blocks
- 1) / MaxLbaCnt
+ 1);
1442 UnmapParamListLen
= (UINT16
) (sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
)
1443 + BlkDespCnt
* sizeof (EFI_SCSI_DISK_UNMAP_BLOCK_DESP
));
1444 UnmapParamList
= AllocateZeroPool (UnmapParamListLen
);
1445 if (UnmapParamList
== NULL
) {
1446 ReturnStatus
= EFI_DEVICE_ERROR
;
1450 *((UINT16
*)UnmapParamList
) = SwapBytes16 (UnmapParamListLen
- 2);
1451 *((UINT16
*)UnmapParamList
+ 1) = SwapBytes16 (UnmapParamListLen
- sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
));
1453 BlkDespPtr
= (EFI_SCSI_DISK_UNMAP_BLOCK_DESP
*)((UINT8
*)UnmapParamList
+ sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER
));
1454 while (Blocks
> 0) {
1455 if (Blocks
> MaxLbaCnt
) {
1456 *(UINT64
*)(&BlkDespPtr
->Lba
) = SwapBytes64 (Lba
);
1457 *(UINT32
*)(&BlkDespPtr
->BlockNum
) = SwapBytes32 (MaxLbaCnt
);
1458 Blocks
-= MaxLbaCnt
;
1461 *(UINT64
*)(&BlkDespPtr
->Lba
) = SwapBytes64 (Lba
);
1462 *(UINT32
*)(&BlkDespPtr
->BlockNum
) = SwapBytes32 ((UINT32
) Blocks
);
1469 CommandPacket
= &EraseBlkReq
->CommandPacket
;
1470 CommandPacket
->Timeout
= SCSI_DISK_TIMEOUT
;
1471 CommandPacket
->OutDataBuffer
= UnmapParamList
;
1472 CommandPacket
->OutTransferLength
= UnmapParamListLen
;
1473 CommandPacket
->CdbLength
= 0xA;
1474 CommandPacket
->DataDirection
= EFI_SCSI_DATA_OUT
;
1476 // Fill Cdb for UNMAP Command
1478 Cdb
= CommandPacket
->Cdb
;
1479 Cdb
[0] = EFI_SCSI_OP_UNMAP
;
1480 WriteUnaligned16 ((UINT16
*)&Cdb
[7], SwapBytes16 (UnmapParamListLen
));
1482 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1484 // Non-blocking UNMAP request
1486 Status
= gBS
->CreateEvent (
1489 ScsiDiskAsyncUnmapNotify
,
1493 if (EFI_ERROR(Status
)) {
1494 ReturnStatus
= EFI_DEVICE_ERROR
;
1498 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1499 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &EraseBlkReq
->Link
);
1500 gBS
->RestoreTPL (OldTpl
);
1502 EraseBlkReq
->Token
= Token
;
1504 Status
= ScsiIo
->ExecuteScsiCommand (
1509 if (EFI_ERROR(Status
)) {
1510 ReturnStatus
= EFI_DEVICE_ERROR
;
1512 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1513 RemoveEntryList (&EraseBlkReq
->Link
);
1514 gBS
->RestoreTPL (OldTpl
);
1519 // Directly return if the non-blocking UNMAP request is queued.
1525 // Blocking UNMAP request
1527 Status
= ScsiIo
->ExecuteScsiCommand (
1532 if (EFI_ERROR(Status
)) {
1533 ReturnStatus
= EFI_DEVICE_ERROR
;
1539 // Only blocking UNMAP request will reach here.
1541 Status
= CheckHostAdapterStatus (CommandPacket
->HostAdapterStatus
);
1542 if (EFI_ERROR(Status
)) {
1545 "ScsiDiskUnmap: Host adapter indicating error status 0x%x.\n",
1546 CommandPacket
->HostAdapterStatus
1549 ReturnStatus
= EFI_DEVICE_ERROR
;
1553 Status
= CheckTargetStatus (CommandPacket
->TargetStatus
);
1554 if (EFI_ERROR(Status
)) {
1557 "ScsiDiskUnmap: Target indicating error status 0x%x.\n",
1558 CommandPacket
->HostAdapterStatus
1561 ReturnStatus
= EFI_DEVICE_ERROR
;
1566 if (EraseBlkReq
!= NULL
) {
1567 if (EraseBlkReq
->CommandPacket
.Cdb
!= NULL
) {
1568 FreePool (EraseBlkReq
->CommandPacket
.Cdb
);
1570 FreePool (EraseBlkReq
);
1573 if (UnmapParamList
!= NULL
) {
1574 FreePool (UnmapParamList
);
1577 if (AsyncUnmapEvent
!= NULL
) {
1578 gBS
->CloseEvent (AsyncUnmapEvent
);
1581 return ReturnStatus
;
1585 Erase a specified number of device blocks.
1587 @param[in] This Indicates a pointer to the calling context.
1588 @param[in] MediaId The media ID that the erase request is for.
1589 @param[in] Lba The starting logical block address to be
1590 erased. The caller is responsible for erasing
1591 only legitimate locations.
1592 @param[in, out] Token A pointer to the token associated with the
1594 @param[in] Size The size in bytes to be erased. This must be
1595 a multiple of the physical block size of the
1598 @retval EFI_SUCCESS The erase request was queued if Event is not
1599 NULL. The data was erased correctly to the
1600 device if the Event is NULL.to the device.
1601 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
1603 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1604 to perform the erase operation.
1605 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
1607 @retval EFI_NO_MEDIA There is no media in the device.
1608 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1613 ScsiDiskEraseBlocks (
1614 IN EFI_ERASE_BLOCK_PROTOCOL
*This
,
1617 IN OUT EFI_ERASE_BLOCK_TOKEN
*Token
,
1621 SCSI_DISK_DEV
*ScsiDiskDevice
;
1622 EFI_BLOCK_IO_MEDIA
*Media
;
1625 UINTN NumberOfBlocks
;
1626 BOOLEAN MediaChange
;
1629 MediaChange
= FALSE
;
1630 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1631 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_ERASEBLK (This
);
1633 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1634 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1635 if (EFI_ERROR (Status
)) {
1636 Status
= EFI_DEVICE_ERROR
;
1641 gBS
->ReinstallProtocolInterface (
1642 ScsiDiskDevice
->Handle
,
1643 &gEfiBlockIoProtocolGuid
,
1644 &ScsiDiskDevice
->BlkIo
,
1645 &ScsiDiskDevice
->BlkIo
1647 gBS
->ReinstallProtocolInterface (
1648 ScsiDiskDevice
->Handle
,
1649 &gEfiBlockIo2ProtocolGuid
,
1650 &ScsiDiskDevice
->BlkIo2
,
1651 &ScsiDiskDevice
->BlkIo2
1653 if (DetermineInstallEraseBlock(ScsiDiskDevice
, ScsiDiskDevice
->Handle
)) {
1654 gBS
->ReinstallProtocolInterface (
1655 ScsiDiskDevice
->Handle
,
1656 &gEfiEraseBlockProtocolGuid
,
1657 &ScsiDiskDevice
->EraseBlock
,
1658 &ScsiDiskDevice
->EraseBlock
1661 Status
= EFI_MEDIA_CHANGED
;
1666 // Get the intrinsic block size
1668 Media
= ScsiDiskDevice
->BlkIo
.Media
;
1670 if (!(Media
->MediaPresent
)) {
1671 Status
= EFI_NO_MEDIA
;
1675 if (MediaId
!= Media
->MediaId
) {
1676 Status
= EFI_MEDIA_CHANGED
;
1680 if (Media
->ReadOnly
) {
1681 Status
= EFI_WRITE_PROTECTED
;
1686 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1687 Token
->TransactionStatus
= EFI_SUCCESS
;
1688 gBS
->SignalEvent (Token
->Event
);
1690 Status
= EFI_SUCCESS
;
1694 BlockSize
= Media
->BlockSize
;
1695 if ((Size
% BlockSize
) != 0) {
1696 Status
= EFI_INVALID_PARAMETER
;
1700 NumberOfBlocks
= Size
/ BlockSize
;
1701 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1702 Status
= EFI_INVALID_PARAMETER
;
1706 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1707 Status
= ScsiDiskUnmap (ScsiDiskDevice
, Lba
, NumberOfBlocks
, Token
);
1709 Status
= ScsiDiskUnmap (ScsiDiskDevice
, Lba
, NumberOfBlocks
, NULL
);
1713 gBS
->RestoreTPL (OldTpl
);
1719 Detect Device and read out capacity ,if error occurs, parse the sense key.
1721 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1722 @param MustReadCapacity The flag about reading device capacity
1723 @param MediaChange The pointer of flag indicates if media has changed
1725 @retval EFI_DEVICE_ERROR Indicates that error occurs
1726 @retval EFI_SUCCESS Successfully to detect media
1730 ScsiDiskDetectMedia (
1731 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1732 IN BOOLEAN MustReadCapacity
,
1733 OUT BOOLEAN
*MediaChange
1737 EFI_SCSI_SENSE_DATA
*SenseData
;
1738 UINTN NumberOfSenseKeys
;
1740 BOOLEAN NeedReadCapacity
;
1743 EFI_BLOCK_IO_MEDIA OldMedia
;
1745 EFI_EVENT TimeoutEvt
;
1747 Status
= EFI_SUCCESS
;
1749 NumberOfSenseKeys
= 0;
1752 Action
= ACTION_NO_ACTION
;
1753 NeedReadCapacity
= FALSE
;
1754 *MediaChange
= FALSE
;
1757 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
1759 Status
= gBS
->CreateEvent (
1766 if (EFI_ERROR (Status
)) {
1770 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
1771 if (EFI_ERROR (Status
)) {
1776 // Sending Test_Unit cmd to poll device status.
1777 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
1778 // We limit the upper boundary to 120 seconds.
1780 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
1781 Status
= ScsiDiskTestUnitReady (
1787 if (!EFI_ERROR (Status
)) {
1788 Status
= DetectMediaParsingSenseKeys (
1794 if (EFI_ERROR (Status
)) {
1796 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1803 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1809 if (EFI_ERROR (Status
)) {
1814 // ACTION_NO_ACTION: need not read capacity
1815 // other action code: need read capacity
1817 if (Action
== ACTION_READ_CAPACITY
) {
1818 NeedReadCapacity
= TRUE
;
1822 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
1823 // retrieve capacity via Read Capacity command
1825 if (NeedReadCapacity
|| MustReadCapacity
) {
1827 // retrieve media information
1829 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
1830 Status
= ScsiDiskReadCapacity (
1836 if (!EFI_ERROR (Status
)) {
1838 // analyze sense key to action
1840 Status
= DetectMediaParsingSenseKeys (
1846 if (EFI_ERROR (Status
)) {
1848 // if Status is error, it may indicate crisis error,
1849 // so return without retry.
1852 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1860 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1866 if (EFI_ERROR (Status
)) {
1871 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
1873 // Media change information got from the device
1875 *MediaChange
= TRUE
;
1878 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
1879 *MediaChange
= TRUE
;
1880 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1883 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
1884 *MediaChange
= TRUE
;
1885 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1888 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
1889 *MediaChange
= TRUE
;
1890 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1893 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
1894 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
1896 // when change from no media to media present, reset the MediaId to 1.
1898 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
1901 // when no media, reset the MediaId to zero.
1903 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
1906 *MediaChange
= TRUE
;
1910 if (TimeoutEvt
!= NULL
) {
1911 gBS
->CloseEvent (TimeoutEvt
);
1918 Send out Inquiry command to Device.
1920 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1921 @param NeedRetry Indicates if needs try again when error happens
1923 @retval EFI_DEVICE_ERROR Indicates that error occurs
1924 @retval EFI_SUCCESS Successfully to detect media
1928 ScsiDiskInquiryDevice (
1929 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1930 OUT BOOLEAN
*NeedRetry
1933 UINT32 InquiryDataLength
;
1934 UINT8 SenseDataLength
;
1935 UINT8 HostAdapterStatus
;
1937 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
1938 UINTN NumberOfSenseKeys
;
1942 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
1943 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
1946 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1947 SenseDataLength
= 0;
1949 Status
= ScsiInquiryCommand (
1950 ScsiDiskDevice
->ScsiIo
,
1956 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
1961 // no need to check HostAdapterStatus and TargetStatus
1963 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1964 ParseInquiryData (ScsiDiskDevice
);
1966 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1968 // Check whether the device supports Block Limits VPD page (0xB0)
1970 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1971 if (SupportedVpdPages
== NULL
) {
1973 return EFI_DEVICE_ERROR
;
1975 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1976 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
1977 SenseDataLength
= 0;
1978 Status
= ScsiInquiryCommandEx (
1979 ScsiDiskDevice
->ScsiIo
,
1985 (VOID
*) SupportedVpdPages
,
1988 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
1990 if (!EFI_ERROR (Status
)) {
1991 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
1992 | SupportedVpdPages
->PageLength1
;
1995 // Sanity checks for coping with broken devices
1997 if (PageLength
> sizeof SupportedVpdPages
->SupportedVpdPageList
) {
1999 "%a: invalid PageLength (%u) in Supported VPD Pages page\n",
2000 __FUNCTION__
, (UINT32
)PageLength
));
2004 if ((PageLength
> 0) &&
2005 (SupportedVpdPages
->SupportedVpdPageList
[0] !=
2006 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
)) {
2008 "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",
2009 __FUNCTION__
, EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
));
2014 // Locate the code for the Block Limits VPD page
2016 for (Index
= 0; Index
< PageLength
; Index
++) {
2021 (SupportedVpdPages
->SupportedVpdPageList
[Index
] <=
2022 SupportedVpdPages
->SupportedVpdPageList
[Index
- 1])) {
2024 "%a: non-ascending code in Supported VPD Pages page @ %u\n",
2025 __FUNCTION__
, Index
));
2031 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
2037 // Query the Block Limits VPD page
2039 if (Index
< PageLength
) {
2040 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2041 if (BlockLimits
== NULL
) {
2042 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2044 return EFI_DEVICE_ERROR
;
2046 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2047 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
2048 SenseDataLength
= 0;
2049 Status
= ScsiInquiryCommandEx (
2050 ScsiDiskDevice
->ScsiIo
,
2056 (VOID
*) BlockLimits
,
2059 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
2061 if (!EFI_ERROR (Status
)) {
2062 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
2063 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
2064 BlockLimits
->OptimalTransferLengthGranularity1
;
2066 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
=
2067 (BlockLimits
->MaximumUnmapLbaCount4
<< 24) |
2068 (BlockLimits
->MaximumUnmapLbaCount3
<< 16) |
2069 (BlockLimits
->MaximumUnmapLbaCount2
<< 8) |
2070 BlockLimits
->MaximumUnmapLbaCount1
;
2071 ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
=
2072 (BlockLimits
->MaximumUnmapBlockDescriptorCount4
<< 24) |
2073 (BlockLimits
->MaximumUnmapBlockDescriptorCount3
<< 16) |
2074 (BlockLimits
->MaximumUnmapBlockDescriptorCount2
<< 8) |
2075 BlockLimits
->MaximumUnmapBlockDescriptorCount1
;
2076 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
=
2077 (BlockLimits
->OptimalUnmapGranularity4
<< 24) |
2078 (BlockLimits
->OptimalUnmapGranularity3
<< 16) |
2079 (BlockLimits
->OptimalUnmapGranularity2
<< 8) |
2080 BlockLimits
->OptimalUnmapGranularity1
;
2081 if (BlockLimits
->UnmapGranularityAlignmentValid
!= 0) {
2082 ScsiDiskDevice
->UnmapInfo
.GranularityAlignment
=
2083 (BlockLimits
->UnmapGranularityAlignment4
<< 24) |
2084 (BlockLimits
->UnmapGranularityAlignment3
<< 16) |
2085 (BlockLimits
->UnmapGranularityAlignment2
<< 8) |
2086 BlockLimits
->UnmapGranularityAlignment1
;
2089 if (ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
== 0) {
2091 // A value of 0 indicates that the optimal unmap granularity is
2094 ScsiDiskDevice
->EraseBlock
.EraseLengthGranularity
= 1;
2097 ScsiDiskDevice
->BlockLimitsVpdSupported
= TRUE
;
2100 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
2104 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
2108 if (!EFI_ERROR (Status
)) {
2111 } else if (Status
== EFI_NOT_READY
) {
2113 return EFI_DEVICE_ERROR
;
2115 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2117 return EFI_DEVICE_ERROR
;
2120 // go ahead to check HostAdapterStatus and TargetStatus
2121 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
2124 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2125 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2127 return EFI_DEVICE_ERROR
;
2128 } else if (Status
== EFI_DEVICE_ERROR
) {
2130 // reset the scsi channel
2132 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2134 return EFI_DEVICE_ERROR
;
2137 Status
= CheckTargetStatus (TargetStatus
);
2138 if (Status
== EFI_NOT_READY
) {
2140 // reset the scsi device
2142 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2144 return EFI_DEVICE_ERROR
;
2146 } else if (Status
== EFI_DEVICE_ERROR
) {
2148 return EFI_DEVICE_ERROR
;
2152 // if goes here, meant ScsiInquiryCommand() failed.
2153 // if ScsiDiskRequestSenseKeys() succeeds at last,
2154 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
2157 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2158 Status
= ScsiDiskRequestSenseKeys (
2165 if (!EFI_ERROR (Status
)) {
2167 return EFI_DEVICE_ERROR
;
2171 return EFI_DEVICE_ERROR
;
2175 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2176 // set *NeedRetry = FALSE to avoid the outside caller try again.
2179 return EFI_DEVICE_ERROR
;
2185 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
2186 When Test Unit Ready command encounters any error caused by host adapter or
2187 target, return error without retrieving Sense Keys.
2189 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2190 @param NeedRetry The pointer of flag indicates try again
2191 @param SenseDataArray The pointer of an array of sense data
2192 @param NumberOfSenseKeys The pointer of the number of sense data array
2194 @retval EFI_DEVICE_ERROR Indicates that error occurs
2195 @retval EFI_SUCCESS Successfully to test unit
2199 ScsiDiskTestUnitReady (
2200 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2201 OUT BOOLEAN
*NeedRetry
,
2202 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2203 OUT UINTN
*NumberOfSenseKeys
2207 UINT8 SenseDataLength
;
2208 UINT8 HostAdapterStatus
;
2213 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2214 *NumberOfSenseKeys
= 0;
2217 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
2219 Status
= ScsiTestUnitReadyCommand (
2220 ScsiDiskDevice
->ScsiIo
,
2222 ScsiDiskDevice
->SenseData
,
2228 // no need to check HostAdapterStatus and TargetStatus
2230 if (Status
== EFI_NOT_READY
) {
2232 return EFI_DEVICE_ERROR
;
2234 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2236 return EFI_DEVICE_ERROR
;
2239 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
2242 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2243 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2245 return EFI_DEVICE_ERROR
;
2247 } else if (Status
== EFI_DEVICE_ERROR
) {
2249 // reset the scsi channel
2251 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2253 return EFI_DEVICE_ERROR
;
2256 Status
= CheckTargetStatus (TargetStatus
);
2257 if (Status
== EFI_NOT_READY
) {
2259 // reset the scsi device
2261 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2263 return EFI_DEVICE_ERROR
;
2265 } else if (Status
== EFI_DEVICE_ERROR
) {
2267 return EFI_DEVICE_ERROR
;
2270 if (SenseDataLength
!= 0) {
2271 *NumberOfSenseKeys
= SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
);
2272 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2277 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2278 Status
= ScsiDiskRequestSenseKeys (
2285 if (!EFI_ERROR (Status
)) {
2290 return EFI_DEVICE_ERROR
;
2294 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2295 // set *NeedRetry = FALSE to avoid the outside caller try again.
2298 return EFI_DEVICE_ERROR
;
2302 Parsing Sense Keys which got from request sense command.
2304 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2305 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
2306 @param NumberOfSenseKeys The number of sense key
2307 @param Action The pointer of action which indicates what is need to do next
2309 @retval EFI_DEVICE_ERROR Indicates that error occurs
2310 @retval EFI_SUCCESS Successfully to complete the parsing
2314 DetectMediaParsingSenseKeys (
2315 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2316 IN EFI_SCSI_SENSE_DATA
*SenseData
,
2317 IN UINTN NumberOfSenseKeys
,
2324 // Default is to read capacity, unless..
2326 *Action
= ACTION_READ_CAPACITY
;
2328 if (NumberOfSenseKeys
== 0) {
2329 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
2330 *Action
= ACTION_NO_ACTION
;
2335 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
2337 // No Sense Key returned from last submitted command
2339 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
2340 *Action
= ACTION_NO_ACTION
;
2345 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
2346 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
2347 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
2348 *Action
= ACTION_NO_ACTION
;
2349 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
2353 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
2354 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
2355 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
2359 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
2360 *Action
= ACTION_RETRY_COMMAND_LATER
;
2361 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
2365 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
2366 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
2367 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2368 return EFI_DEVICE_ERROR
;
2371 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
2372 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
2373 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2374 return EFI_DEVICE_ERROR
;
2377 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
2379 *Action
= ACTION_RETRY_COMMAND_LATER
;
2380 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
2383 *Action
= ACTION_NO_ACTION
;
2384 return EFI_DEVICE_ERROR
;
2387 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
2388 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
2394 Send read capacity command to device and get the device parameter.
2396 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2397 @param NeedRetry The pointer of flag indicates if need a retry
2398 @param SenseDataArray The pointer of an array of sense data
2399 @param NumberOfSenseKeys The number of sense key
2401 @retval EFI_DEVICE_ERROR Indicates that error occurs
2402 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
2406 ScsiDiskReadCapacity (
2407 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2408 OUT BOOLEAN
*NeedRetry
,
2409 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2410 OUT UINTN
*NumberOfSenseKeys
2413 UINT8 HostAdapterStatus
;
2415 EFI_STATUS CommandStatus
;
2419 UINT8 SenseDataLength
;
2420 UINT32 DataLength10
;
2421 UINT32 DataLength16
;
2422 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
2423 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
2425 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2426 if (CapacityData10
== NULL
) {
2428 return EFI_DEVICE_ERROR
;
2430 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2431 if (CapacityData16
== NULL
) {
2432 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2434 return EFI_DEVICE_ERROR
;
2437 SenseDataLength
= 0;
2438 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
2439 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
2440 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2441 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2443 *NumberOfSenseKeys
= 0;
2447 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
2448 // 16 byte command should be used to access large hard disk >2TB
2450 CommandStatus
= ScsiReadCapacityCommand (
2451 ScsiDiskDevice
->ScsiIo
,
2457 (VOID
*) CapacityData10
,
2462 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
2463 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
2464 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff)) {
2466 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
2468 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
2470 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
2471 // and LowestAlignedLba
2473 CommandStatus
= ScsiReadCapacity16Command (
2474 ScsiDiskDevice
->ScsiIo
,
2480 (VOID
*) CapacityData16
,
2487 // no need to check HostAdapterStatus and TargetStatus
2489 if (CommandStatus
== EFI_SUCCESS
) {
2490 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
2491 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2492 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2496 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
2497 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
2499 if (CommandStatus
== EFI_NOT_READY
) {
2501 return EFI_DEVICE_ERROR
;
2502 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
2504 return EFI_DEVICE_ERROR
;
2508 // go ahead to check HostAdapterStatus and TargetStatus
2509 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2512 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2513 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2515 return EFI_DEVICE_ERROR
;
2517 } else if (Status
== EFI_DEVICE_ERROR
) {
2519 // reset the scsi channel
2521 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2523 return EFI_DEVICE_ERROR
;
2526 Status
= CheckTargetStatus (TargetStatus
);
2527 if (Status
== EFI_NOT_READY
) {
2529 // reset the scsi device
2531 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2533 return EFI_DEVICE_ERROR
;
2535 } else if (Status
== EFI_DEVICE_ERROR
) {
2537 return EFI_DEVICE_ERROR
;
2541 // if goes here, meant ScsiReadCapacityCommand() failed.
2542 // if ScsiDiskRequestSenseKeys() succeeds at last,
2543 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
2546 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2548 Status
= ScsiDiskRequestSenseKeys (
2555 if (!EFI_ERROR (Status
)) {
2560 return EFI_DEVICE_ERROR
;
2564 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2565 // set *NeedRetry = FALSE to avoid the outside caller try again.
2568 return EFI_DEVICE_ERROR
;
2572 Check the HostAdapter status and re-interpret it in EFI_STATUS.
2574 @param HostAdapterStatus Host Adapter status
2576 @retval EFI_SUCCESS Host adapter is OK.
2577 @retval EFI_TIMEOUT Timeout.
2578 @retval EFI_NOT_READY Adapter NOT ready.
2579 @retval EFI_DEVICE_ERROR Adapter device error.
2583 CheckHostAdapterStatus (
2584 IN UINT8 HostAdapterStatus
2587 switch (HostAdapterStatus
) {
2588 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
2591 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
2592 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
2593 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
2596 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
2597 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
2598 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
2599 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
2600 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
2601 return EFI_NOT_READY
;
2603 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
2604 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
2605 return EFI_DEVICE_ERROR
;
2614 Check the target status and re-interpret it in EFI_STATUS.
2616 @param TargetStatus Target status
2618 @retval EFI_NOT_READY Device is NOT ready.
2619 @retval EFI_DEVICE_ERROR
2625 IN UINT8 TargetStatus
2628 switch (TargetStatus
) {
2629 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
2630 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
2631 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
2634 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
2635 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
2636 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
2637 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
2638 return EFI_NOT_READY
;
2640 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
2641 return EFI_DEVICE_ERROR
;
2650 Retrieve all sense keys from the device.
2652 When encountering error during the process, if retrieve sense keys before
2653 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
2654 and NeedRetry set to FALSE; otherwize, return the proper return status.
2656 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2657 @param NeedRetry The pointer of flag indicates if need a retry
2658 @param SenseDataArray The pointer of an array of sense data
2659 @param NumberOfSenseKeys The number of sense key
2660 @param AskResetIfError The flag indicates if need reset when error occurs
2662 @retval EFI_DEVICE_ERROR Indicates that error occurs
2663 @retval EFI_SUCCESS Successfully to request sense key
2667 ScsiDiskRequestSenseKeys (
2668 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2669 OUT BOOLEAN
*NeedRetry
,
2670 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2671 OUT UINTN
*NumberOfSenseKeys
,
2672 IN BOOLEAN AskResetIfError
2675 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
2676 UINT8 SenseDataLength
;
2679 EFI_STATUS FallStatus
;
2680 UINT8 HostAdapterStatus
;
2683 FallStatus
= EFI_SUCCESS
;
2684 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
2687 ScsiDiskDevice
->SenseData
,
2688 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
2691 *NumberOfSenseKeys
= 0;
2692 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2693 Status
= EFI_SUCCESS
;
2694 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
2695 if (PtrSenseData
== NULL
) {
2696 return EFI_DEVICE_ERROR
;
2699 for (SenseReq
= TRUE
; SenseReq
;) {
2700 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2701 Status
= ScsiRequestSenseCommand (
2702 ScsiDiskDevice
->ScsiIo
,
2709 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
2710 FallStatus
= EFI_SUCCESS
;
2712 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2714 FallStatus
= EFI_DEVICE_ERROR
;
2716 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2718 FallStatus
= EFI_DEVICE_ERROR
;
2720 } else if (Status
== EFI_DEVICE_ERROR
) {
2721 if (AskResetIfError
) {
2722 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2725 FallStatus
= EFI_DEVICE_ERROR
;
2728 if (EFI_ERROR (FallStatus
)) {
2729 if (*NumberOfSenseKeys
!= 0) {
2731 Status
= EFI_SUCCESS
;
2734 Status
= EFI_DEVICE_ERROR
;
2739 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
2740 (*NumberOfSenseKeys
) += 1;
2743 // no more sense key or number of sense keys exceeds predefined,
2746 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
2747 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
2753 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2759 Get information from media read capacity command.
2761 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2762 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
2763 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
2768 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2769 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
2770 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
2775 if (!ScsiDiskDevice
->Cdb16Byte
) {
2776 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= ((UINT32
) Capacity10
->LastLba3
<< 24) |
2777 (Capacity10
->LastLba2
<< 16) |
2778 (Capacity10
->LastLba1
<< 8) |
2779 Capacity10
->LastLba0
;
2781 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
2782 (Capacity10
->BlockSize2
<< 16) |
2783 (Capacity10
->BlockSize1
<< 8) |
2784 Capacity10
->BlockSize0
;
2785 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
2786 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
2787 if (!ScsiDiskDevice
->BlockLimitsVpdSupported
) {
2788 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
) ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2791 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2792 *Ptr
++ = Capacity16
->LastLba0
;
2793 *Ptr
++ = Capacity16
->LastLba1
;
2794 *Ptr
++ = Capacity16
->LastLba2
;
2795 *Ptr
++ = Capacity16
->LastLba3
;
2796 *Ptr
++ = Capacity16
->LastLba4
;
2797 *Ptr
++ = Capacity16
->LastLba5
;
2798 *Ptr
++ = Capacity16
->LastLba6
;
2799 *Ptr
= Capacity16
->LastLba7
;
2801 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
2802 (Capacity16
->BlockSize2
<< 16) |
2803 (Capacity16
->BlockSize1
<< 8) |
2804 Capacity16
->BlockSize0
;
2806 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
2807 Capacity16
->LowestAlignLogic1
;
2808 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
2809 if (!ScsiDiskDevice
->BlockLimitsVpdSupported
) {
2810 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
> (UINT32
) -1) {
2811 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
) -1;
2813 ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
= (UINT32
) ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2818 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
2824 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2829 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2832 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
2833 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
2837 Read sector from SCSI Disk.
2839 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2840 @param Buffer The buffer to fill in the read out data
2841 @param Lba Logic block address
2842 @param NumberOfBlocks The number of blocks to read
2844 @retval EFI_DEVICE_ERROR Indicates a device error.
2845 @retval EFI_SUCCESS Operation is successful.
2849 ScsiDiskReadSectors (
2850 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2853 IN UINTN NumberOfBlocks
2856 UINTN BlocksRemaining
;
2862 UINT32 NextSectorCount
;
2869 Status
= EFI_SUCCESS
;
2871 BlocksRemaining
= NumberOfBlocks
;
2872 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2875 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2877 if (!ScsiDiskDevice
->Cdb16Byte
) {
2880 MaxBlock
= 0xFFFFFFFF;
2885 while (BlocksRemaining
> 0) {
2887 if (BlocksRemaining
<= MaxBlock
) {
2888 if (!ScsiDiskDevice
->Cdb16Byte
) {
2889 SectorCount
= (UINT16
) BlocksRemaining
;
2891 SectorCount
= (UINT32
) BlocksRemaining
;
2894 SectorCount
= MaxBlock
;
2897 ByteCount
= SectorCount
* BlockSize
;
2899 // |------------------------|-----------------|------------------|-----------------|
2900 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2901 // |------------------------|-----------------|------------------|-----------------|
2902 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2903 // |------------------------|-----------------|------------------|-----------------|
2904 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2905 // |------------------------|-----------------|------------------|-----------------|
2906 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2907 // |------------------------|-----------------|------------------|-----------------|
2908 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2909 // |------------------------|-----------------|------------------|-----------------|
2910 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2911 // |------------------------|-----------------|------------------|-----------------|
2912 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2913 // |------------------------|-----------------|------------------|-----------------|
2914 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2915 // |------------------------|-----------------|------------------|-----------------|
2916 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2917 // |------------------------|-----------------|------------------|-----------------|
2918 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2919 // |------------------------|-----------------|------------------|-----------------|
2920 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2921 // |------------------------|-----------------|------------------|-----------------|
2923 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2924 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2925 // From the above table, we could know 2.1Mbytes per second is lowest one.
2926 // The timout value is rounded up to nearest integar and here an additional 30s is added
2927 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2928 // commands in the Standby/Idle mode.
2930 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2933 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2934 if (!ScsiDiskDevice
->Cdb16Byte
) {
2935 Status
= ScsiDiskRead10 (
2945 Status
= ScsiDiskRead16 (
2955 if (!EFI_ERROR (Status
)) {
2960 return EFI_DEVICE_ERROR
;
2964 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
2965 // lowered ByteCount on output, we must make sure that we lower
2966 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2967 // it is invalid to request more sectors in the CDB than the entire
2968 // transfer (ie. ByteCount) can carry.
2970 // In addition, ByteCount is only expected to go down, or stay unchaged.
2971 // Therefore we don't need to update Timeout: the original timeout should
2972 // accommodate shorter transfers too.
2974 NextSectorCount
= ByteCount
/ BlockSize
;
2975 if (NextSectorCount
< SectorCount
) {
2976 SectorCount
= NextSectorCount
;
2978 // Account for any rounding down.
2980 ByteCount
= SectorCount
* BlockSize
;
2984 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2985 return EFI_DEVICE_ERROR
;
2989 // actual transferred sectors
2991 SectorCount
= ByteCount
/ BlockSize
;
2994 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2995 BlocksRemaining
-= SectorCount
;
3002 Write sector to SCSI Disk.
3004 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
3005 @param Buffer The buffer of data to be written into SCSI Disk
3006 @param Lba Logic block address
3007 @param NumberOfBlocks The number of blocks to read
3009 @retval EFI_DEVICE_ERROR Indicates a device error.
3010 @retval EFI_SUCCESS Operation is successful.
3014 ScsiDiskWriteSectors (
3015 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3018 IN UINTN NumberOfBlocks
3021 UINTN BlocksRemaining
;
3027 UINT32 NextSectorCount
;
3034 Status
= EFI_SUCCESS
;
3036 BlocksRemaining
= NumberOfBlocks
;
3037 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3040 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
3042 if (!ScsiDiskDevice
->Cdb16Byte
) {
3045 MaxBlock
= 0xFFFFFFFF;
3050 while (BlocksRemaining
> 0) {
3052 if (BlocksRemaining
<= MaxBlock
) {
3053 if (!ScsiDiskDevice
->Cdb16Byte
) {
3054 SectorCount
= (UINT16
) BlocksRemaining
;
3056 SectorCount
= (UINT32
) BlocksRemaining
;
3059 SectorCount
= MaxBlock
;
3062 ByteCount
= SectorCount
* BlockSize
;
3064 // |------------------------|-----------------|------------------|-----------------|
3065 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3066 // |------------------------|-----------------|------------------|-----------------|
3067 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3068 // |------------------------|-----------------|------------------|-----------------|
3069 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3070 // |------------------------|-----------------|------------------|-----------------|
3071 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3072 // |------------------------|-----------------|------------------|-----------------|
3073 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3074 // |------------------------|-----------------|------------------|-----------------|
3075 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3076 // |------------------------|-----------------|------------------|-----------------|
3077 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3078 // |------------------------|-----------------|------------------|-----------------|
3079 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3080 // |------------------------|-----------------|------------------|-----------------|
3081 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3082 // |------------------------|-----------------|------------------|-----------------|
3083 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3084 // |------------------------|-----------------|------------------|-----------------|
3085 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3086 // |------------------------|-----------------|------------------|-----------------|
3088 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
3089 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
3090 // From the above table, we could know 2.1Mbytes per second is lowest one.
3091 // The timout value is rounded up to nearest integar and here an additional 30s is added
3092 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
3093 // commands in the Standby/Idle mode.
3095 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3097 for (Index
= 0; Index
< MaxRetry
; Index
++) {
3098 if (!ScsiDiskDevice
->Cdb16Byte
) {
3099 Status
= ScsiDiskWrite10 (
3109 Status
= ScsiDiskWrite16 (
3119 if (!EFI_ERROR (Status
)) {
3124 return EFI_DEVICE_ERROR
;
3128 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
3129 // has lowered ByteCount on output, we must make sure that we lower
3130 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
3131 // it is invalid to request more sectors in the CDB than the entire
3132 // transfer (ie. ByteCount) can carry.
3134 // In addition, ByteCount is only expected to go down, or stay unchaged.
3135 // Therefore we don't need to update Timeout: the original timeout should
3136 // accommodate shorter transfers too.
3138 NextSectorCount
= ByteCount
/ BlockSize
;
3139 if (NextSectorCount
< SectorCount
) {
3140 SectorCount
= NextSectorCount
;
3142 // Account for any rounding down.
3144 ByteCount
= SectorCount
* BlockSize
;
3148 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
3149 return EFI_DEVICE_ERROR
;
3152 // actual transferred sectors
3154 SectorCount
= ByteCount
/ BlockSize
;
3157 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3158 BlocksRemaining
-= SectorCount
;
3165 Asynchronously read sector from SCSI Disk.
3167 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3168 @param Buffer The buffer to fill in the read out data.
3169 @param Lba Logic block address.
3170 @param NumberOfBlocks The number of blocks to read.
3171 @param Token A pointer to the token associated with the
3172 non-blocking read request.
3174 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
3175 @retval EFI_DEVICE_ERROR Indicates a device error.
3176 @retval EFI_SUCCESS Operation is successful.
3180 ScsiDiskAsyncReadSectors (
3181 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3184 IN UINTN NumberOfBlocks
,
3185 IN EFI_BLOCK_IO2_TOKEN
*Token
3188 UINTN BlocksRemaining
;
3195 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
3199 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
3200 return EFI_INVALID_PARAMETER
;
3203 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
3204 if (BlkIo2Req
== NULL
) {
3205 return EFI_OUT_OF_RESOURCES
;
3208 BlkIo2Req
->Token
= Token
;
3210 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3211 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &BlkIo2Req
->Link
);
3212 gBS
->RestoreTPL (OldTpl
);
3214 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
3216 Status
= EFI_SUCCESS
;
3218 BlocksRemaining
= NumberOfBlocks
;
3219 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3222 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3225 if (!ScsiDiskDevice
->Cdb16Byte
) {
3228 MaxBlock
= 0xFFFFFFFF;
3233 while (BlocksRemaining
> 0) {
3235 if (BlocksRemaining
<= MaxBlock
) {
3236 if (!ScsiDiskDevice
->Cdb16Byte
) {
3237 SectorCount
= (UINT16
) BlocksRemaining
;
3239 SectorCount
= (UINT32
) BlocksRemaining
;
3242 SectorCount
= MaxBlock
;
3245 ByteCount
= SectorCount
* BlockSize
;
3247 // |------------------------|-----------------|------------------|-----------------|
3248 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3249 // |------------------------|-----------------|------------------|-----------------|
3250 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3251 // |------------------------|-----------------|------------------|-----------------|
3252 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3253 // |------------------------|-----------------|------------------|-----------------|
3254 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3255 // |------------------------|-----------------|------------------|-----------------|
3256 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3257 // |------------------------|-----------------|------------------|-----------------|
3258 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3259 // |------------------------|-----------------|------------------|-----------------|
3260 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3261 // |------------------------|-----------------|------------------|-----------------|
3262 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3263 // |------------------------|-----------------|------------------|-----------------|
3264 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3265 // |------------------------|-----------------|------------------|-----------------|
3266 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3267 // |------------------------|-----------------|------------------|-----------------|
3268 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3269 // |------------------------|-----------------|------------------|-----------------|
3271 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3272 // we have to use the lowest transfer rate to calculate the possible
3273 // maximum timeout value for each operation.
3274 // From the above table, we could know 2.1Mbytes per second is lowest one.
3275 // The timout value is rounded up to nearest integar and here an additional
3276 // 30s is added to follow ATA spec in which it mentioned that the device
3277 // may take up to 30s to respond commands in the Standby/Idle mode.
3279 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3281 if (!ScsiDiskDevice
->Cdb16Byte
) {
3282 Status
= ScsiDiskAsyncRead10 (
3294 Status
= ScsiDiskAsyncRead16 (
3306 if (EFI_ERROR (Status
)) {
3308 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3309 // length of a SCSI I/O command is too large.
3310 // In this case, we retry sending the SCSI command with a data length
3311 // half of its previous value.
3313 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
3314 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
3315 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
3320 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3321 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3323 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3324 // SCSI sub-task running. Otherwise, it will be freed in the callback
3325 // function ScsiDiskNotify().
3327 RemoveEntryList (&BlkIo2Req
->Link
);
3328 FreePool (BlkIo2Req
);
3330 gBS
->RestoreTPL (OldTpl
);
3333 // It is safe to return error status to the caller, since there is no
3334 // previous SCSI sub-task executing.
3336 Status
= EFI_DEVICE_ERROR
;
3339 gBS
->RestoreTPL (OldTpl
);
3342 // There are previous SCSI commands still running, EFI_SUCCESS should
3343 // be returned to make sure that the caller does not free resources
3344 // still using by these SCSI commands.
3346 Status
= EFI_SUCCESS
;
3352 // Sectors submitted for transfer
3354 SectorCount
= ByteCount
/ BlockSize
;
3357 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3358 BlocksRemaining
-= SectorCount
;
3361 Status
= EFI_SUCCESS
;
3364 if (BlkIo2Req
!= NULL
) {
3365 BlkIo2Req
->LastScsiRW
= TRUE
;
3367 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3368 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3369 RemoveEntryList (&BlkIo2Req
->Link
);
3370 FreePool (BlkIo2Req
);
3373 gBS
->SignalEvent (Token
->Event
);
3375 gBS
->RestoreTPL (OldTpl
);
3382 Asynchronously write sector to SCSI Disk.
3384 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
3385 @param Buffer The buffer of data to be written into SCSI Disk.
3386 @param Lba Logic block address.
3387 @param NumberOfBlocks The number of blocks to read.
3388 @param Token A pointer to the token associated with the
3389 non-blocking read request.
3391 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
3392 @retval EFI_DEVICE_ERROR Indicates a device error.
3393 @retval EFI_SUCCESS Operation is successful.
3397 ScsiDiskAsyncWriteSectors (
3398 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3401 IN UINTN NumberOfBlocks
,
3402 IN EFI_BLOCK_IO2_TOKEN
*Token
3405 UINTN BlocksRemaining
;
3412 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
3416 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
3417 return EFI_INVALID_PARAMETER
;
3420 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
3421 if (BlkIo2Req
== NULL
) {
3422 return EFI_OUT_OF_RESOURCES
;
3425 BlkIo2Req
->Token
= Token
;
3427 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3428 InsertTailList (&ScsiDiskDevice
->AsyncTaskQueue
, &BlkIo2Req
->Link
);
3429 gBS
->RestoreTPL (OldTpl
);
3431 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
3433 Status
= EFI_SUCCESS
;
3435 BlocksRemaining
= NumberOfBlocks
;
3436 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3439 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
3442 if (!ScsiDiskDevice
->Cdb16Byte
) {
3445 MaxBlock
= 0xFFFFFFFF;
3450 while (BlocksRemaining
> 0) {
3452 if (BlocksRemaining
<= MaxBlock
) {
3453 if (!ScsiDiskDevice
->Cdb16Byte
) {
3454 SectorCount
= (UINT16
) BlocksRemaining
;
3456 SectorCount
= (UINT32
) BlocksRemaining
;
3459 SectorCount
= MaxBlock
;
3462 ByteCount
= SectorCount
* BlockSize
;
3464 // |------------------------|-----------------|------------------|-----------------|
3465 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
3466 // |------------------------|-----------------|------------------|-----------------|
3467 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
3468 // |------------------------|-----------------|------------------|-----------------|
3469 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
3470 // |------------------------|-----------------|------------------|-----------------|
3471 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
3472 // |------------------------|-----------------|------------------|-----------------|
3473 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
3474 // |------------------------|-----------------|------------------|-----------------|
3475 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
3476 // |------------------------|-----------------|------------------|-----------------|
3477 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
3478 // |------------------------|-----------------|------------------|-----------------|
3479 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
3480 // |------------------------|-----------------|------------------|-----------------|
3481 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
3482 // |------------------------|-----------------|------------------|-----------------|
3483 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
3484 // |------------------------|-----------------|------------------|-----------------|
3485 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
3486 // |------------------------|-----------------|------------------|-----------------|
3488 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
3489 // we have to use the lowest transfer rate to calculate the possible
3490 // maximum timeout value for each operation.
3491 // From the above table, we could know 2.1Mbytes per second is lowest one.
3492 // The timout value is rounded up to nearest integar and here an additional
3493 // 30s is added to follow ATA spec in which it mentioned that the device
3494 // may take up to 30s to respond commands in the Standby/Idle mode.
3496 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
3498 if (!ScsiDiskDevice
->Cdb16Byte
) {
3499 Status
= ScsiDiskAsyncWrite10 (
3511 Status
= ScsiDiskAsyncWrite16 (
3523 if (EFI_ERROR (Status
)) {
3525 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
3526 // length of a SCSI I/O command is too large.
3527 // In this case, we retry sending the SCSI command with a data length
3528 // half of its previous value.
3530 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
3531 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
3532 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
3537 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3538 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3540 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3541 // SCSI sub-task running. Otherwise, it will be freed in the callback
3542 // function ScsiDiskNotify().
3544 RemoveEntryList (&BlkIo2Req
->Link
);
3545 FreePool (BlkIo2Req
);
3547 gBS
->RestoreTPL (OldTpl
);
3550 // It is safe to return error status to the caller, since there is no
3551 // previous SCSI sub-task executing.
3553 Status
= EFI_DEVICE_ERROR
;
3556 gBS
->RestoreTPL (OldTpl
);
3559 // There are previous SCSI commands still running, EFI_SUCCESS should
3560 // be returned to make sure that the caller does not free resources
3561 // still using by these SCSI commands.
3563 Status
= EFI_SUCCESS
;
3569 // Sectors submitted for transfer
3571 SectorCount
= ByteCount
/ BlockSize
;
3574 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3575 BlocksRemaining
-= SectorCount
;
3578 Status
= EFI_SUCCESS
;
3581 if (BlkIo2Req
!= NULL
) {
3582 BlkIo2Req
->LastScsiRW
= TRUE
;
3584 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3585 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3586 RemoveEntryList (&BlkIo2Req
->Link
);
3587 FreePool (BlkIo2Req
);
3590 gBS
->SignalEvent (Token
->Event
);
3592 gBS
->RestoreTPL (OldTpl
);
3600 Submit Read(10) command.
3602 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3603 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3604 @param Timeout The time to complete the command
3605 @param DataBuffer The buffer to fill with the read out data
3606 @param DataLength The length of buffer
3607 @param StartLba The start logic block address
3608 @param SectorCount The number of blocks to read
3610 @return EFI_STATUS is returned by calling ScsiRead10Command().
3614 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3615 OUT BOOLEAN
*NeedRetry
,
3617 OUT UINT8
*DataBuffer
,
3618 IN OUT UINT32
*DataLength
,
3620 IN UINT32 SectorCount
3623 UINT8 SenseDataLength
;
3625 EFI_STATUS ReturnStatus
;
3626 UINT8 HostAdapterStatus
;
3631 // Implement a backoff algorithem to resolve some compatibility issues that
3632 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3633 // big data in a single operation.
3634 // This algorithem will at first try to execute original request. If the request fails
3635 // with media error sense data or else, it will reduce the transfer length to half and
3636 // try again till the operation succeeds or fails with one sector transfer length.
3640 Action
= ACTION_NO_ACTION
;
3641 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3642 ReturnStatus
= ScsiRead10Command (
3643 ScsiDiskDevice
->ScsiIo
,
3645 ScsiDiskDevice
->SenseData
,
3655 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3657 return EFI_DEVICE_ERROR
;
3658 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3660 return ReturnStatus
;
3664 // go ahead to check HostAdapterStatus and TargetStatus
3665 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3667 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3668 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3670 return EFI_DEVICE_ERROR
;
3671 } else if (Status
== EFI_DEVICE_ERROR
) {
3673 // reset the scsi channel
3675 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3677 return EFI_DEVICE_ERROR
;
3680 Status
= CheckTargetStatus (TargetStatus
);
3681 if (Status
== EFI_NOT_READY
) {
3683 // reset the scsi device
3685 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3687 return EFI_DEVICE_ERROR
;
3688 } else if (Status
== EFI_DEVICE_ERROR
) {
3690 return EFI_DEVICE_ERROR
;
3693 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3694 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
3695 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3696 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3698 return EFI_DEVICE_ERROR
;
3699 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3700 if (SectorCount
<= 1) {
3702 // Jump out if the operation still fails with one sector transfer length.
3705 return EFI_DEVICE_ERROR
;
3708 // Try again with half length if the sense data shows we need to retry.
3711 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3715 return EFI_DEVICE_ERROR
;
3719 return ReturnStatus
;
3724 Submit Write(10) Command.
3726 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3727 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3728 @param Timeout The time to complete the command
3729 @param DataBuffer The buffer to fill with the read out data
3730 @param DataLength The length of buffer
3731 @param StartLba The start logic block address
3732 @param SectorCount The number of blocks to write
3734 @return EFI_STATUS is returned by calling ScsiWrite10Command().
3739 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3740 OUT BOOLEAN
*NeedRetry
,
3742 IN UINT8
*DataBuffer
,
3743 IN OUT UINT32
*DataLength
,
3745 IN UINT32 SectorCount
3749 EFI_STATUS ReturnStatus
;
3750 UINT8 SenseDataLength
;
3751 UINT8 HostAdapterStatus
;
3756 // Implement a backoff algorithem to resolve some compatibility issues that
3757 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3758 // big data in a single operation.
3759 // This algorithem will at first try to execute original request. If the request fails
3760 // with media error sense data or else, it will reduce the transfer length to half and
3761 // try again till the operation succeeds or fails with one sector transfer length.
3765 Action
= ACTION_NO_ACTION
;
3766 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3767 ReturnStatus
= ScsiWrite10Command (
3768 ScsiDiskDevice
->ScsiIo
,
3770 ScsiDiskDevice
->SenseData
,
3779 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3781 return EFI_DEVICE_ERROR
;
3782 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3784 return ReturnStatus
;
3788 // go ahead to check HostAdapterStatus and TargetStatus
3789 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3791 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3792 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3794 return EFI_DEVICE_ERROR
;
3795 } else if (Status
== EFI_DEVICE_ERROR
) {
3797 // reset the scsi channel
3799 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3801 return EFI_DEVICE_ERROR
;
3804 Status
= CheckTargetStatus (TargetStatus
);
3805 if (Status
== EFI_NOT_READY
) {
3807 // reset the scsi device
3809 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3811 return EFI_DEVICE_ERROR
;
3812 } else if (Status
== EFI_DEVICE_ERROR
) {
3814 return EFI_DEVICE_ERROR
;
3817 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3818 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
3819 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3820 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3822 return EFI_DEVICE_ERROR
;
3823 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3824 if (SectorCount
<= 1) {
3826 // Jump out if the operation still fails with one sector transfer length.
3829 return EFI_DEVICE_ERROR
;
3832 // Try again with half length if the sense data shows we need to retry.
3835 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3839 return EFI_DEVICE_ERROR
;
3843 return ReturnStatus
;
3848 Submit Read(16) command.
3850 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3851 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3852 @param Timeout The time to complete the command
3853 @param DataBuffer The buffer to fill with the read out data
3854 @param DataLength The length of buffer
3855 @param StartLba The start logic block address
3856 @param SectorCount The number of blocks to read
3858 @return EFI_STATUS is returned by calling ScsiRead16Command().
3862 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3863 OUT BOOLEAN
*NeedRetry
,
3865 OUT UINT8
*DataBuffer
,
3866 IN OUT UINT32
*DataLength
,
3868 IN UINT32 SectorCount
3871 UINT8 SenseDataLength
;
3873 EFI_STATUS ReturnStatus
;
3874 UINT8 HostAdapterStatus
;
3879 // Implement a backoff algorithem to resolve some compatibility issues that
3880 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3881 // big data in a single operation.
3882 // This algorithem will at first try to execute original request. If the request fails
3883 // with media error sense data or else, it will reduce the transfer length to half and
3884 // try again till the operation succeeds or fails with one sector transfer length.
3888 Action
= ACTION_NO_ACTION
;
3889 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3890 ReturnStatus
= ScsiRead16Command (
3891 ScsiDiskDevice
->ScsiIo
,
3893 ScsiDiskDevice
->SenseData
,
3902 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3904 return EFI_DEVICE_ERROR
;
3905 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3907 return ReturnStatus
;
3911 // go ahead to check HostAdapterStatus and TargetStatus
3912 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3914 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3915 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3917 return EFI_DEVICE_ERROR
;
3918 } else if (Status
== EFI_DEVICE_ERROR
) {
3920 // reset the scsi channel
3922 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3924 return EFI_DEVICE_ERROR
;
3927 Status
= CheckTargetStatus (TargetStatus
);
3928 if (Status
== EFI_NOT_READY
) {
3930 // reset the scsi device
3932 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3934 return EFI_DEVICE_ERROR
;
3935 } else if (Status
== EFI_DEVICE_ERROR
) {
3937 return EFI_DEVICE_ERROR
;
3940 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3941 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
3942 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3943 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3945 return EFI_DEVICE_ERROR
;
3946 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3947 if (SectorCount
<= 1) {
3949 // Jump out if the operation still fails with one sector transfer length.
3952 return EFI_DEVICE_ERROR
;
3955 // Try again with half length if the sense data shows we need to retry.
3958 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3962 return EFI_DEVICE_ERROR
;
3966 return ReturnStatus
;
3971 Submit Write(16) Command.
3973 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3974 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3975 @param Timeout The time to complete the command
3976 @param DataBuffer The buffer to fill with the read out data
3977 @param DataLength The length of buffer
3978 @param StartLba The start logic block address
3979 @param SectorCount The number of blocks to write
3981 @return EFI_STATUS is returned by calling ScsiWrite16Command().
3986 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3987 OUT BOOLEAN
*NeedRetry
,
3989 IN UINT8
*DataBuffer
,
3990 IN OUT UINT32
*DataLength
,
3992 IN UINT32 SectorCount
3996 EFI_STATUS ReturnStatus
;
3997 UINT8 SenseDataLength
;
3998 UINT8 HostAdapterStatus
;
4003 // Implement a backoff algorithem to resolve some compatibility issues that
4004 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
4005 // big data in a single operation.
4006 // This algorithem will at first try to execute original request. If the request fails
4007 // with media error sense data or else, it will reduce the transfer length to half and
4008 // try again till the operation succeeds or fails with one sector transfer length.
4012 Action
= ACTION_NO_ACTION
;
4013 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
4014 ReturnStatus
= ScsiWrite16Command (
4015 ScsiDiskDevice
->ScsiIo
,
4017 ScsiDiskDevice
->SenseData
,
4026 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
4028 return EFI_DEVICE_ERROR
;
4029 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
4031 return ReturnStatus
;
4035 // go ahead to check HostAdapterStatus and TargetStatus
4036 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4038 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
4039 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4041 return EFI_DEVICE_ERROR
;
4042 } else if (Status
== EFI_DEVICE_ERROR
) {
4044 // reset the scsi channel
4046 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4048 return EFI_DEVICE_ERROR
;
4051 Status
= CheckTargetStatus (TargetStatus
);
4052 if (Status
== EFI_NOT_READY
) {
4054 // reset the scsi device
4056 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4058 return EFI_DEVICE_ERROR
;
4059 } else if (Status
== EFI_DEVICE_ERROR
) {
4061 return EFI_DEVICE_ERROR
;
4064 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
4065 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
4066 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
4067 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4069 return EFI_DEVICE_ERROR
;
4070 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4071 if (SectorCount
<= 1) {
4073 // Jump out if the operation still fails with one sector transfer length.
4076 return EFI_DEVICE_ERROR
;
4079 // Try again with half length if the sense data shows we need to retry.
4082 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4086 return EFI_DEVICE_ERROR
;
4090 return ReturnStatus
;
4095 Internal helper notify function in which determine whether retry of a SCSI
4096 Read/Write command is needed and signal the event passed from Block I/O(2) if
4097 the SCSI I/O operation completes.
4099 @param Event The instance of EFI_EVENT.
4100 @param Context The parameter passed in.
4111 SCSI_ASYNC_RW_REQUEST
*Request
;
4112 SCSI_DISK_DEV
*ScsiDiskDevice
;
4113 EFI_BLOCK_IO2_TOKEN
*Token
;
4115 UINT32 OldDataLength
;
4116 UINT32 OldSectorCount
;
4119 gBS
->CloseEvent (Event
);
4121 Request
= (SCSI_ASYNC_RW_REQUEST
*) Context
;
4122 ScsiDiskDevice
= Request
->ScsiDiskDevice
;
4123 Token
= Request
->BlkIo2Req
->Token
;
4124 OldDataLength
= Request
->DataLength
;
4125 OldSectorCount
= Request
->SectorCount
;
4129 // If previous sub-tasks already fails, no need to process this sub-task.
4131 if (Token
->TransactionStatus
!= EFI_SUCCESS
) {
4136 // Check HostAdapterStatus and TargetStatus
4137 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
4139 Status
= CheckHostAdapterStatus (Request
->HostAdapterStatus
);
4140 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
4141 if (++Request
->TimesRetry
> MaxRetry
) {
4142 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4147 } else if (Status
== EFI_DEVICE_ERROR
) {
4149 // reset the scsi channel
4151 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
4152 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4156 Status
= CheckTargetStatus (Request
->TargetStatus
);
4157 if (Status
== EFI_NOT_READY
) {
4159 // reset the scsi device
4161 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
4162 if (++Request
->TimesRetry
> MaxRetry
) {
4163 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4168 } else if (Status
== EFI_DEVICE_ERROR
) {
4169 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4173 if (Request
->TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) {
4174 DEBUG ((EFI_D_ERROR
, "ScsiDiskNotify: Check Condition happened!\n"));
4176 Status
= DetectMediaParsingSenseKeys (
4179 Request
->SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
),
4182 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
4183 if (++Request
->TimesRetry
> MaxRetry
) {
4184 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4189 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
4190 if (Request
->SectorCount
<= 1) {
4192 // Jump out if the operation still fails with one sector transfer
4195 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4199 // Try again with two half length request if the sense data shows we need
4202 Request
->SectorCount
>>= 1;
4203 Request
->DataLength
= Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
4204 Request
->TimesRetry
= 0;
4208 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4214 // This sub-task succeeds, no need to retry.
4219 if (Request
->InBuffer
!= NULL
) {
4221 // SCSI read command
4223 if (!ScsiDiskDevice
->Cdb16Byte
) {
4224 Status
= ScsiDiskAsyncRead10 (
4227 Request
->TimesRetry
,
4229 Request
->DataLength
,
4230 (UINT32
) Request
->StartLba
,
4231 Request
->SectorCount
,
4236 Status
= ScsiDiskAsyncRead16 (
4239 Request
->TimesRetry
,
4241 Request
->DataLength
,
4243 Request
->SectorCount
,
4249 if (EFI_ERROR (Status
)) {
4250 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4252 } else if (OldSectorCount
!= Request
->SectorCount
) {
4254 // Original sub-task will be split into two new sub-tasks with smaller
4257 if (!ScsiDiskDevice
->Cdb16Byte
) {
4258 Status
= ScsiDiskAsyncRead10 (
4262 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4263 OldDataLength
- Request
->DataLength
,
4264 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
4265 OldSectorCount
- Request
->SectorCount
,
4270 Status
= ScsiDiskAsyncRead16 (
4274 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4275 OldDataLength
- Request
->DataLength
,
4276 Request
->StartLba
+ Request
->SectorCount
,
4277 OldSectorCount
- Request
->SectorCount
,
4282 if (EFI_ERROR (Status
)) {
4283 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4289 // SCSI write command
4291 if (!ScsiDiskDevice
->Cdb16Byte
) {
4292 Status
= ScsiDiskAsyncWrite10 (
4295 Request
->TimesRetry
,
4297 Request
->DataLength
,
4298 (UINT32
) Request
->StartLba
,
4299 Request
->SectorCount
,
4304 Status
= ScsiDiskAsyncWrite16 (
4307 Request
->TimesRetry
,
4309 Request
->DataLength
,
4311 Request
->SectorCount
,
4317 if (EFI_ERROR (Status
)) {
4318 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4320 } else if (OldSectorCount
!= Request
->SectorCount
) {
4322 // Original sub-task will be split into two new sub-tasks with smaller
4325 if (!ScsiDiskDevice
->Cdb16Byte
) {
4326 Status
= ScsiDiskAsyncWrite10 (
4330 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4331 OldDataLength
- Request
->DataLength
,
4332 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
4333 OldSectorCount
- Request
->SectorCount
,
4338 Status
= ScsiDiskAsyncWrite16 (
4342 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
4343 OldDataLength
- Request
->DataLength
,
4344 Request
->StartLba
+ Request
->SectorCount
,
4345 OldSectorCount
- Request
->SectorCount
,
4350 if (EFI_ERROR (Status
)) {
4351 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
4358 RemoveEntryList (&Request
->Link
);
4359 if ((IsListEmpty (&Request
->BlkIo2Req
->ScsiRWQueue
)) &&
4360 (Request
->BlkIo2Req
->LastScsiRW
)) {
4362 // The last SCSI R/W command of a BlockIo2 request completes
4364 RemoveEntryList (&Request
->BlkIo2Req
->Link
);
4365 FreePool (Request
->BlkIo2Req
); // Should be freed only once
4366 gBS
->SignalEvent (Token
->Event
);
4369 FreePool (Request
->SenseData
);
4375 Submit Async Read(10) command.
4377 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4378 @param Timeout The time to complete the command.
4379 @param TimesRetry The number of times the command has been retried.
4380 @param DataBuffer The buffer to fill with the read out data.
4381 @param DataLength The length of buffer.
4382 @param StartLba The start logic block address.
4383 @param SectorCount The number of blocks to read.
4384 @param BlkIo2Req The upstream BlockIo2 request.
4385 @param Token The pointer to the token associated with the
4386 non-blocking read request.
4388 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4390 @return others Status returned by calling
4391 ScsiRead10CommandEx().
4395 ScsiDiskAsyncRead10 (
4396 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4398 IN UINT8 TimesRetry
,
4399 OUT UINT8
*DataBuffer
,
4400 IN UINT32 DataLength
,
4402 IN UINT32 SectorCount
,
4403 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4404 IN EFI_BLOCK_IO2_TOKEN
*Token
4408 SCSI_ASYNC_RW_REQUEST
*Request
;
4409 EFI_EVENT AsyncIoEvent
;
4412 AsyncIoEvent
= NULL
;
4414 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4415 if (Request
== NULL
) {
4416 return EFI_OUT_OF_RESOURCES
;
4419 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4420 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4421 gBS
->RestoreTPL (OldTpl
);
4423 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4424 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4425 if (Request
->SenseData
== NULL
) {
4426 Status
= EFI_OUT_OF_RESOURCES
;
4430 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4431 Request
->Timeout
= Timeout
;
4432 Request
->TimesRetry
= TimesRetry
;
4433 Request
->InBuffer
= DataBuffer
;
4434 Request
->DataLength
= DataLength
;
4435 Request
->StartLba
= StartLba
;
4436 Request
->SectorCount
= SectorCount
;
4437 Request
->BlkIo2Req
= BlkIo2Req
;
4442 Status
= gBS
->CreateEvent (
4449 if (EFI_ERROR(Status
)) {
4453 Status
= ScsiRead10CommandEx (
4454 ScsiDiskDevice
->ScsiIo
,
4457 &Request
->SenseDataLength
,
4458 &Request
->HostAdapterStatus
,
4459 &Request
->TargetStatus
,
4461 &Request
->DataLength
,
4462 (UINT32
) Request
->StartLba
,
4463 Request
->SectorCount
,
4466 if (EFI_ERROR(Status
)) {
4473 if (AsyncIoEvent
!= NULL
) {
4474 gBS
->CloseEvent (AsyncIoEvent
);
4477 if (Request
!= NULL
) {
4478 if (Request
->SenseData
!= NULL
) {
4479 FreePool (Request
->SenseData
);
4482 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4483 RemoveEntryList (&Request
->Link
);
4484 gBS
->RestoreTPL (OldTpl
);
4494 Submit Async Write(10) command.
4496 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4497 @param Timeout The time to complete the command.
4498 @param TimesRetry The number of times the command has been retried.
4499 @param DataBuffer The buffer contains the data to write.
4500 @param DataLength The length of buffer.
4501 @param StartLba The start logic block address.
4502 @param SectorCount The number of blocks to write.
4503 @param BlkIo2Req The upstream BlockIo2 request.
4504 @param Token The pointer to the token associated with the
4505 non-blocking read request.
4507 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4509 @return others Status returned by calling
4510 ScsiWrite10CommandEx().
4514 ScsiDiskAsyncWrite10 (
4515 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4517 IN UINT8 TimesRetry
,
4518 IN UINT8
*DataBuffer
,
4519 IN UINT32 DataLength
,
4521 IN UINT32 SectorCount
,
4522 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4523 IN EFI_BLOCK_IO2_TOKEN
*Token
4527 SCSI_ASYNC_RW_REQUEST
*Request
;
4528 EFI_EVENT AsyncIoEvent
;
4531 AsyncIoEvent
= NULL
;
4533 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4534 if (Request
== NULL
) {
4535 return EFI_OUT_OF_RESOURCES
;
4538 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4539 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4540 gBS
->RestoreTPL (OldTpl
);
4542 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4543 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4544 if (Request
->SenseData
== NULL
) {
4545 Status
= EFI_OUT_OF_RESOURCES
;
4549 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4550 Request
->Timeout
= Timeout
;
4551 Request
->TimesRetry
= TimesRetry
;
4552 Request
->OutBuffer
= DataBuffer
;
4553 Request
->DataLength
= DataLength
;
4554 Request
->StartLba
= StartLba
;
4555 Request
->SectorCount
= SectorCount
;
4556 Request
->BlkIo2Req
= BlkIo2Req
;
4561 Status
= gBS
->CreateEvent (
4568 if (EFI_ERROR(Status
)) {
4572 Status
= ScsiWrite10CommandEx (
4573 ScsiDiskDevice
->ScsiIo
,
4576 &Request
->SenseDataLength
,
4577 &Request
->HostAdapterStatus
,
4578 &Request
->TargetStatus
,
4580 &Request
->DataLength
,
4581 (UINT32
) Request
->StartLba
,
4582 Request
->SectorCount
,
4585 if (EFI_ERROR(Status
)) {
4592 if (AsyncIoEvent
!= NULL
) {
4593 gBS
->CloseEvent (AsyncIoEvent
);
4596 if (Request
!= NULL
) {
4597 if (Request
->SenseData
!= NULL
) {
4598 FreePool (Request
->SenseData
);
4601 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4602 RemoveEntryList (&Request
->Link
);
4603 gBS
->RestoreTPL (OldTpl
);
4613 Submit Async Read(16) command.
4615 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4616 @param Timeout The time to complete the command.
4617 @param TimesRetry The number of times the command has been retried.
4618 @param DataBuffer The buffer to fill with the read out data.
4619 @param DataLength The length of buffer.
4620 @param StartLba The start logic block address.
4621 @param SectorCount The number of blocks to read.
4622 @param BlkIo2Req The upstream BlockIo2 request.
4623 @param Token The pointer to the token associated with the
4624 non-blocking read request.
4626 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4628 @return others Status returned by calling
4629 ScsiRead16CommandEx().
4633 ScsiDiskAsyncRead16 (
4634 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4636 IN UINT8 TimesRetry
,
4637 OUT UINT8
*DataBuffer
,
4638 IN UINT32 DataLength
,
4640 IN UINT32 SectorCount
,
4641 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4642 IN EFI_BLOCK_IO2_TOKEN
*Token
4646 SCSI_ASYNC_RW_REQUEST
*Request
;
4647 EFI_EVENT AsyncIoEvent
;
4650 AsyncIoEvent
= NULL
;
4652 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4653 if (Request
== NULL
) {
4654 return EFI_OUT_OF_RESOURCES
;
4657 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4658 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4659 gBS
->RestoreTPL (OldTpl
);
4661 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4662 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4663 if (Request
->SenseData
== NULL
) {
4664 Status
= EFI_OUT_OF_RESOURCES
;
4668 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4669 Request
->Timeout
= Timeout
;
4670 Request
->TimesRetry
= TimesRetry
;
4671 Request
->InBuffer
= DataBuffer
;
4672 Request
->DataLength
= DataLength
;
4673 Request
->StartLba
= StartLba
;
4674 Request
->SectorCount
= SectorCount
;
4675 Request
->BlkIo2Req
= BlkIo2Req
;
4680 Status
= gBS
->CreateEvent (
4687 if (EFI_ERROR(Status
)) {
4691 Status
= ScsiRead16CommandEx (
4692 ScsiDiskDevice
->ScsiIo
,
4695 &Request
->SenseDataLength
,
4696 &Request
->HostAdapterStatus
,
4697 &Request
->TargetStatus
,
4699 &Request
->DataLength
,
4701 Request
->SectorCount
,
4704 if (EFI_ERROR(Status
)) {
4711 if (AsyncIoEvent
!= NULL
) {
4712 gBS
->CloseEvent (AsyncIoEvent
);
4715 if (Request
!= NULL
) {
4716 if (Request
->SenseData
!= NULL
) {
4717 FreePool (Request
->SenseData
);
4720 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4721 RemoveEntryList (&Request
->Link
);
4722 gBS
->RestoreTPL (OldTpl
);
4732 Submit Async Write(16) command.
4734 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4735 @param Timeout The time to complete the command.
4736 @param TimesRetry The number of times the command has been retried.
4737 @param DataBuffer The buffer contains the data to write.
4738 @param DataLength The length of buffer.
4739 @param StartLba The start logic block address.
4740 @param SectorCount The number of blocks to write.
4741 @param BlkIo2Req The upstream BlockIo2 request.
4742 @param Token The pointer to the token associated with the
4743 non-blocking read request.
4745 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4747 @return others Status returned by calling
4748 ScsiWrite16CommandEx().
4752 ScsiDiskAsyncWrite16 (
4753 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4755 IN UINT8 TimesRetry
,
4756 IN UINT8
*DataBuffer
,
4757 IN UINT32 DataLength
,
4759 IN UINT32 SectorCount
,
4760 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4761 IN EFI_BLOCK_IO2_TOKEN
*Token
4765 SCSI_ASYNC_RW_REQUEST
*Request
;
4766 EFI_EVENT AsyncIoEvent
;
4769 AsyncIoEvent
= NULL
;
4771 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4772 if (Request
== NULL
) {
4773 return EFI_OUT_OF_RESOURCES
;
4776 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4777 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4778 gBS
->RestoreTPL (OldTpl
);
4780 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4781 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4782 if (Request
->SenseData
== NULL
) {
4783 Status
= EFI_OUT_OF_RESOURCES
;
4787 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4788 Request
->Timeout
= Timeout
;
4789 Request
->TimesRetry
= TimesRetry
;
4790 Request
->OutBuffer
= DataBuffer
;
4791 Request
->DataLength
= DataLength
;
4792 Request
->StartLba
= StartLba
;
4793 Request
->SectorCount
= SectorCount
;
4794 Request
->BlkIo2Req
= BlkIo2Req
;
4799 Status
= gBS
->CreateEvent (
4806 if (EFI_ERROR(Status
)) {
4810 Status
= ScsiWrite16CommandEx (
4811 ScsiDiskDevice
->ScsiIo
,
4814 &Request
->SenseDataLength
,
4815 &Request
->HostAdapterStatus
,
4816 &Request
->TargetStatus
,
4818 &Request
->DataLength
,
4820 Request
->SectorCount
,
4823 if (EFI_ERROR(Status
)) {
4830 if (AsyncIoEvent
!= NULL
) {
4831 gBS
->CloseEvent (AsyncIoEvent
);
4834 if (Request
!= NULL
) {
4835 if (Request
->SenseData
!= NULL
) {
4836 FreePool (Request
->SenseData
);
4839 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4840 RemoveEntryList (&Request
->Link
);
4841 gBS
->RestoreTPL (OldTpl
);
4851 Check sense key to find if media presents.
4853 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4854 @param SenseCounts The number of sense key
4856 @retval TRUE NOT any media
4857 @retval FALSE Media presents
4861 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4862 IN UINTN SenseCounts
4865 EFI_SCSI_SENSE_DATA
*SensePtr
;
4870 SensePtr
= SenseData
;
4872 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4874 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
4875 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
4877 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
4878 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
4891 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4892 @param SenseCounts The number of sense key
4895 @retval FALSE NOT error
4899 ScsiDiskIsMediaError (
4900 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4901 IN UINTN SenseCounts
4904 EFI_SCSI_SENSE_DATA
*SensePtr
;
4909 SensePtr
= SenseData
;
4911 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4913 switch (SensePtr
->Sense_Key
) {
4915 case EFI_SCSI_SK_MEDIUM_ERROR
:
4917 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
4919 switch (SensePtr
->Addnl_Sense_Code
) {
4924 case EFI_SCSI_ASC_MEDIA_ERR1
:
4929 case EFI_SCSI_ASC_MEDIA_ERR2
:
4934 case EFI_SCSI_ASC_MEDIA_ERR3
:
4935 case EFI_SCSI_ASC_MEDIA_ERR4
:
4945 case EFI_SCSI_SK_NOT_READY
:
4947 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4949 switch (SensePtr
->Addnl_Sense_Code
) {
4951 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
4953 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
4974 Check sense key to find if hardware error happens.
4976 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4977 @param SenseCounts The number of sense key
4979 @retval TRUE Hardware error exits.
4980 @retval FALSE NO error.
4984 ScsiDiskIsHardwareError (
4985 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4986 IN UINTN SenseCounts
4989 EFI_SCSI_SENSE_DATA
*SensePtr
;
4994 SensePtr
= SenseData
;
4996 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4999 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
5001 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
5013 Check sense key to find if media has changed.
5015 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5016 @param SenseCounts The number of sense key
5018 @retval TRUE Media is changed.
5019 @retval FALSE Media is NOT changed.
5022 ScsiDiskIsMediaChange (
5023 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5024 IN UINTN SenseCounts
5027 EFI_SCSI_SENSE_DATA
*SensePtr
;
5029 BOOLEAN IsMediaChanged
;
5031 IsMediaChanged
= FALSE
;
5032 SensePtr
= SenseData
;
5034 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5036 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
5037 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
5039 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
5040 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
5041 IsMediaChanged
= TRUE
;
5047 return IsMediaChanged
;
5051 Check sense key to find if reset happens.
5053 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5054 @param SenseCounts The number of sense key
5056 @retval TRUE It is reset before.
5057 @retval FALSE It is NOT reset before.
5061 ScsiDiskIsResetBefore (
5062 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5063 IN UINTN SenseCounts
5066 EFI_SCSI_SENSE_DATA
*SensePtr
;
5068 BOOLEAN IsResetBefore
;
5070 IsResetBefore
= FALSE
;
5071 SensePtr
= SenseData
;
5073 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5076 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
5077 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
5079 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
5080 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
5081 IsResetBefore
= TRUE
;
5087 return IsResetBefore
;
5091 Check sense key to find if the drive is ready.
5093 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
5094 @param SenseCounts The number of sense key
5095 @param RetryLater The flag means if need a retry
5097 @retval TRUE Drive is ready.
5098 @retval FALSE Drive is NOT ready.
5102 ScsiDiskIsDriveReady (
5103 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5104 IN UINTN SenseCounts
,
5105 OUT BOOLEAN
*RetryLater
5108 EFI_SCSI_SENSE_DATA
*SensePtr
;
5113 *RetryLater
= FALSE
;
5114 SensePtr
= SenseData
;
5116 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5118 switch (SensePtr
->Sense_Key
) {
5120 case EFI_SCSI_SK_NOT_READY
:
5122 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
5124 switch (SensePtr
->Addnl_Sense_Code
) {
5125 case EFI_SCSI_ASC_NOT_READY
:
5127 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
5129 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
5130 case EFI_SCSI_ASCQ_IN_PROGRESS
:
5132 // Additional Sense Code Qualifier is
5133 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
5141 *RetryLater
= FALSE
;
5162 Check sense key to find if it has sense key.
5164 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
5165 @param SenseCounts - The number of sense key
5167 @retval TRUE It has sense key.
5168 @retval FALSE It has NOT any sense key.
5172 ScsiDiskHaveSenseKey (
5173 IN EFI_SCSI_SENSE_DATA
*SenseData
,
5174 IN UINTN SenseCounts
5177 EFI_SCSI_SENSE_DATA
*SensePtr
;
5179 BOOLEAN HaveSenseKey
;
5181 if (SenseCounts
== 0) {
5182 HaveSenseKey
= FALSE
;
5184 HaveSenseKey
= TRUE
;
5187 SensePtr
= SenseData
;
5189 for (Index
= 0; Index
< SenseCounts
; Index
++) {
5192 // Sense Key is SK_NO_SENSE (0x0)
5194 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
5196 HaveSenseKey
= FALSE
;
5202 return HaveSenseKey
;
5206 Release resource about disk device.
5208 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
5212 ReleaseScsiDiskDeviceResources (
5213 IN SCSI_DISK_DEV
*ScsiDiskDevice
5216 if (ScsiDiskDevice
== NULL
) {
5220 if (ScsiDiskDevice
->SenseData
!= NULL
) {
5221 FreePool (ScsiDiskDevice
->SenseData
);
5222 ScsiDiskDevice
->SenseData
= NULL
;
5225 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
5226 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
5227 ScsiDiskDevice
->ControllerNameTable
= NULL
;
5230 FreePool (ScsiDiskDevice
);
5232 ScsiDiskDevice
= NULL
;
5236 Determine if Block Io & Block Io2 should be produced.
5239 @param ChildHandle Child Handle to retrieve Parent information.
5241 @retval TRUE Should produce Block Io & Block Io2.
5242 @retval FALSE Should not produce Block Io & Block Io2.
5246 DetermineInstallBlockIo (
5247 IN EFI_HANDLE ChildHandle
5250 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
5251 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
5254 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
5255 // check its attribute, logic or physical.
5257 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
5258 if (ExtScsiPassThru
!= NULL
) {
5259 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
5265 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
5266 // check its attribute, logic or physical.
5268 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
5269 if (ScsiPassThru
!= NULL
) {
5270 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
5279 Search protocol database and check to see if the protocol
5280 specified by ProtocolGuid is present on a ControllerHandle and opened by
5281 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
5282 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
5283 will be opened on it.
5286 @param ProtocolGuid ProtocolGuid pointer.
5287 @param ChildHandle Child Handle to retrieve Parent information.
5293 IN EFI_GUID
*ProtocolGuid
,
5294 IN EFI_HANDLE ChildHandle
5301 EFI_HANDLE
*HandleBuffer
;
5304 // Retrieve the list of all handles from the handle database
5306 Status
= gBS
->LocateHandleBuffer (
5314 if (EFI_ERROR (Status
)) {
5319 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
5321 for (Index
= 0; Index
< HandleCount
; Index
++) {
5322 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
5323 if (!EFI_ERROR (Status
)) {
5324 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
5325 if (!EFI_ERROR (Status
)) {
5326 gBS
->FreePool (HandleBuffer
);
5332 gBS
->FreePool (HandleBuffer
);
5337 Determine if EFI Erase Block Protocol should be produced.
5339 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
5340 @param ChildHandle Handle of device.
5342 @retval TRUE Should produce EFI Erase Block Protocol.
5343 @retval FALSE Should not produce EFI Erase Block Protocol.
5347 DetermineInstallEraseBlock (
5348 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5349 IN EFI_HANDLE ChildHandle
5352 UINT8 HostAdapterStatus
;
5354 EFI_STATUS CommandStatus
;
5358 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
5359 UINT8 SenseDataLength
;
5360 UINT32 DataLength16
;
5361 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
5365 CapacityData16
= NULL
;
5367 Status
= gBS
->HandleProtocol (
5369 &gEfiDevicePathProtocolGuid
,
5370 (VOID
**) &DevicePathNode
5373 // Device Path protocol must be installed on the device handle.
5375 ASSERT_EFI_ERROR (Status
);
5377 while (!IsDevicePathEndType (DevicePathNode
)) {
5379 // For now, only support Erase Block Protocol on UFS devices.
5381 if ((DevicePathNode
->Type
== MESSAGING_DEVICE_PATH
) &&
5382 (DevicePathNode
->SubType
== MSG_UFS_DP
)) {
5387 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
5395 // Check whether the erase functionality is enabled on the UFS device.
5397 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
5398 if (CapacityData16
== NULL
) {
5403 SenseDataLength
= 0;
5404 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
5405 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
5407 CommandStatus
= ScsiReadCapacity16Command (
5408 ScsiDiskDevice
->ScsiIo
,
5414 (VOID
*) CapacityData16
,
5419 if (CommandStatus
== EFI_SUCCESS
) {
5421 // Universal Flash Storage (UFS) Version 2.0
5423 // Bits TPE and TPRZ should both be set to enable the erase feature on UFS.
5425 if (((CapacityData16
->LowestAlignLogic2
& BIT7
) == 0) ||
5426 ((CapacityData16
->LowestAlignLogic2
& BIT6
) == 0)) {
5429 "ScsiDisk EraseBlock: Either TPE or TPRZ is not set: 0x%x.\n",
5430 CapacityData16
->LowestAlignLogic2
5439 "ScsiDisk EraseBlock: ReadCapacity16 failed with status %r.\n",
5448 // Check whether the UFS device server implements the UNMAP command.
5450 if ((ScsiDiskDevice
->UnmapInfo
.MaxLbaCnt
== 0) ||
5451 (ScsiDiskDevice
->UnmapInfo
.MaxBlkDespCnt
== 0)) {
5454 "ScsiDisk EraseBlock: The device server does not implement the UNMAP command.\n"
5462 if (CapacityData16
!= NULL
) {
5463 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
5470 Provides inquiry information for the controller type.
5472 This function is used by the IDE bus driver to get inquiry data. Data format
5473 of Identify data is defined by the Interface GUID.
5475 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
5476 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
5477 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
5479 @retval EFI_SUCCESS The command was accepted without any errors.
5480 @retval EFI_NOT_FOUND Device does not support this data class
5481 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
5482 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
5487 ScsiDiskInfoInquiry (
5488 IN EFI_DISK_INFO_PROTOCOL
*This
,
5489 IN OUT VOID
*InquiryData
,
5490 IN OUT UINT32
*InquiryDataSize
5494 SCSI_DISK_DEV
*ScsiDiskDevice
;
5496 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
5498 Status
= EFI_BUFFER_TOO_SMALL
;
5499 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
5500 Status
= EFI_SUCCESS
;
5501 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
5503 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
5509 Provides identify information for the controller type.
5511 This function is used by the IDE bus driver to get identify data. Data format
5512 of Identify data is defined by the Interface GUID.
5514 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
5516 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
5517 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
5520 @retval EFI_SUCCESS The command was accepted without any errors.
5521 @retval EFI_NOT_FOUND Device does not support this data class
5522 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
5523 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
5528 ScsiDiskInfoIdentify (
5529 IN EFI_DISK_INFO_PROTOCOL
*This
,
5530 IN OUT VOID
*IdentifyData
,
5531 IN OUT UINT32
*IdentifyDataSize
5535 SCSI_DISK_DEV
*ScsiDiskDevice
;
5537 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
5539 // Physical SCSI bus does not support this data class.
5541 return EFI_NOT_FOUND
;
5544 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
5546 Status
= EFI_BUFFER_TOO_SMALL
;
5547 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
5548 Status
= EFI_SUCCESS
;
5549 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
5551 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
5556 Provides sense data information for the controller type.
5558 This function is used by the IDE bus driver to get sense data.
5559 Data format of Sense data is defined by the Interface GUID.
5561 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
5562 @param[in, out] SenseData Pointer to the SenseData.
5563 @param[in, out] SenseDataSize Size of SenseData in bytes.
5564 @param[out] SenseDataNumber Pointer to the value for the sense data size.
5566 @retval EFI_SUCCESS The command was accepted without any errors.
5567 @retval EFI_NOT_FOUND Device does not support this data class.
5568 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
5569 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
5574 ScsiDiskInfoSenseData (
5575 IN EFI_DISK_INFO_PROTOCOL
*This
,
5576 IN OUT VOID
*SenseData
,
5577 IN OUT UINT32
*SenseDataSize
,
5578 OUT UINT8
*SenseDataNumber
5581 return EFI_NOT_FOUND
;
5586 This function is used by the IDE bus driver to get controller information.
5588 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
5589 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
5590 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
5592 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
5593 @retval EFI_UNSUPPORTED This is not an IDE device.
5598 ScsiDiskInfoWhichIde (
5599 IN EFI_DISK_INFO_PROTOCOL
*This
,
5600 OUT UINT32
*IdeChannel
,
5601 OUT UINT32
*IdeDevice
5604 SCSI_DISK_DEV
*ScsiDiskDevice
;
5606 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
5608 // This is not an IDE physical device.
5610 return EFI_UNSUPPORTED
;
5613 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
5614 *IdeChannel
= ScsiDiskDevice
->Channel
;
5615 *IdeDevice
= ScsiDiskDevice
->Device
;
5622 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
5624 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
5625 implement Identify() interface for DiskInfo protocol. The ATA command is sent
5626 via SCSI Request Packet.
5628 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
5630 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
5631 @retval others Some error occurred during the identification that ATAPI device.
5635 AtapiIdentifyDevice (
5636 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
5639 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
5643 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
5645 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
5646 ZeroMem (Cdb
, sizeof (Cdb
));
5648 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
5649 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
5650 CommandPacket
.Cdb
= Cdb
;
5651 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
5652 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
5653 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
5655 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
5660 Initialize the installation of DiskInfo protocol.
5662 This function prepares for the installation of DiskInfo protocol on the child handle.
5663 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
5664 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
5665 to be IDE/AHCI interface GUID.
5667 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
5668 @param ChildHandle Child handle to install DiskInfo protocol.
5672 InitializeInstallDiskInfo (
5673 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5674 IN EFI_HANDLE ChildHandle
5678 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
5679 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
5680 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
5681 SATA_DEVICE_PATH
*SataDevicePath
;
5682 UINTN IdentifyRetry
;
5684 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
5686 // Device Path protocol must be installed on the device handle.
5688 ASSERT_EFI_ERROR (Status
);
5690 // Copy the DiskInfo protocol template.
5692 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
5694 while (!IsDevicePathEnd (DevicePathNode
)) {
5695 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
5696 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
5697 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
5698 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
5699 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
5700 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
5705 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
5706 // with IDE/AHCI interface GUID.
5708 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
5709 if (!EFI_ERROR (Status
)) {
5710 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
5712 // We find the valid ATAPI device path
5714 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
5715 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
5716 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
5718 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
5720 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
5723 // We find the valid SATA device path
5725 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
5726 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
5727 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
5729 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
5731 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
5735 } while (--IdentifyRetry
> 0);
5736 } else if ((DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
5737 (DevicePathSubType (ChildDevicePathNode
) == MSG_UFS_DP
)) {
5738 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoUfsInterfaceGuid
);
5741 DevicePathNode
= ChildDevicePathNode
;