2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2015, 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
->Handle
= Controller
;
248 InitializeListHead (&ScsiDiskDevice
->BlkIo2Queue
);
250 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
251 switch (ScsiDiskDevice
->DeviceType
) {
252 case EFI_SCSI_TYPE_DISK
:
253 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
254 MustReadCapacity
= TRUE
;
257 case EFI_SCSI_TYPE_CDROM
:
258 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
259 ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
= TRUE
;
260 MustReadCapacity
= FALSE
;
264 // The Sense Data Array's initial size is 6
266 ScsiDiskDevice
->SenseDataNumber
= 6;
267 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
268 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
270 if (ScsiDiskDevice
->SenseData
== NULL
) {
273 &gEfiScsiIoProtocolGuid
,
274 This
->DriverBindingHandle
,
277 FreePool (ScsiDiskDevice
);
278 return EFI_OUT_OF_RESOURCES
;
282 // Retrieve device information
285 for (Index
= 0; Index
< MaxRetry
; Index
++) {
286 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
287 if (!EFI_ERROR (Status
)) {
292 FreePool (ScsiDiskDevice
->SenseData
);
295 &gEfiScsiIoProtocolGuid
,
296 This
->DriverBindingHandle
,
299 FreePool (ScsiDiskDevice
);
300 return EFI_DEVICE_ERROR
;
304 // The second parameter "TRUE" means must
305 // retrieve media capacity
307 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, MustReadCapacity
, &Temp
);
308 if (!EFI_ERROR (Status
)) {
310 // Determine if Block IO & Block IO2 should be produced on this controller
313 if (DetermineInstallBlockIo(Controller
)) {
314 InitializeInstallDiskInfo(ScsiDiskDevice
, Controller
);
315 Status
= gBS
->InstallMultipleProtocolInterfaces (
317 &gEfiBlockIoProtocolGuid
,
318 &ScsiDiskDevice
->BlkIo
,
319 &gEfiBlockIo2ProtocolGuid
,
320 &ScsiDiskDevice
->BlkIo2
,
321 &gEfiDiskInfoProtocolGuid
,
322 &ScsiDiskDevice
->DiskInfo
,
325 if (!EFI_ERROR(Status
)) {
326 ScsiDiskDevice
->ControllerNameTable
= NULL
;
329 gScsiDiskComponentName
.SupportedLanguages
,
330 &ScsiDiskDevice
->ControllerNameTable
,
336 gScsiDiskComponentName2
.SupportedLanguages
,
337 &ScsiDiskDevice
->ControllerNameTable
,
346 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
347 gBS
->FreePool (ScsiDiskDevice
);
350 &gEfiScsiIoProtocolGuid
,
351 This
->DriverBindingHandle
,
360 Stop this driver on ControllerHandle.
362 This service is called by the EFI boot service DisconnectController().
363 In order to make drivers as small as possible, there are a few calling
364 restrictions for this service. DisconnectController() must follow these
365 calling restrictions. If any other agent wishes to call Stop() it must
366 also follow these calling restrictions.
368 @param This Protocol instance pointer.
369 @param ControllerHandle Handle of device to stop driver on
370 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
371 children is zero stop the entire bus driver.
372 @param ChildHandleBuffer List of Child Handles to Stop.
374 @retval EFI_SUCCESS This driver is removed ControllerHandle
375 @retval other This driver was not removed from this device
380 ScsiDiskDriverBindingStop (
381 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
382 IN EFI_HANDLE Controller
,
383 IN UINTN NumberOfChildren
,
384 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
387 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
388 SCSI_DISK_DEV
*ScsiDiskDevice
;
391 Status
= gBS
->OpenProtocol (
393 &gEfiBlockIoProtocolGuid
,
395 This
->DriverBindingHandle
,
397 EFI_OPEN_PROTOCOL_GET_PROTOCOL
399 if (EFI_ERROR (Status
)) {
403 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (BlkIo
);
406 // Wait for the BlockIo2 requests queue to become empty
408 while (!IsListEmpty (&ScsiDiskDevice
->BlkIo2Queue
));
410 Status
= gBS
->UninstallMultipleProtocolInterfaces (
412 &gEfiBlockIoProtocolGuid
,
413 &ScsiDiskDevice
->BlkIo
,
414 &gEfiBlockIo2ProtocolGuid
,
415 &ScsiDiskDevice
->BlkIo2
,
416 &gEfiDiskInfoProtocolGuid
,
417 &ScsiDiskDevice
->DiskInfo
,
420 if (!EFI_ERROR (Status
)) {
423 &gEfiScsiIoProtocolGuid
,
424 This
->DriverBindingHandle
,
428 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
442 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
443 @param ExtendedVerification The flag about if extend verificate
445 @retval EFI_SUCCESS The device was reset.
446 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
448 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
454 IN EFI_BLOCK_IO_PROTOCOL
*This
,
455 IN BOOLEAN ExtendedVerification
459 SCSI_DISK_DEV
*ScsiDiskDevice
;
462 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
464 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
466 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
468 if (EFI_ERROR (Status
)) {
469 Status
= EFI_DEVICE_ERROR
;
473 if (!ExtendedVerification
) {
477 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
479 if (EFI_ERROR (Status
)) {
480 Status
= EFI_DEVICE_ERROR
;
485 gBS
->RestoreTPL (OldTpl
);
490 The function is to Read Block from SCSI Disk.
492 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
493 @param MediaId The Id of Media detected
494 @param Lba The logic block address
495 @param BufferSize The size of Buffer
496 @param Buffer The buffer to fill the read out data
498 @retval EFI_SUCCESS Successfully to read out block.
499 @retval EFI_DEVICE_ERROR Fail to detect media.
500 @retval EFI_NO_MEDIA Media is not present.
501 @retval EFI_MEDIA_CHANGED Media has changed.
502 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
503 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
509 IN EFI_BLOCK_IO_PROTOCOL
*This
,
516 SCSI_DISK_DEV
*ScsiDiskDevice
;
517 EFI_BLOCK_IO_MEDIA
*Media
;
520 UINTN NumberOfBlocks
;
525 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
526 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
528 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
530 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
531 if (EFI_ERROR (Status
)) {
532 Status
= EFI_DEVICE_ERROR
;
537 gBS
->ReinstallProtocolInterface (
538 ScsiDiskDevice
->Handle
,
539 &gEfiBlockIoProtocolGuid
,
540 &ScsiDiskDevice
->BlkIo
,
541 &ScsiDiskDevice
->BlkIo
543 gBS
->ReinstallProtocolInterface (
544 ScsiDiskDevice
->Handle
,
545 &gEfiBlockIo2ProtocolGuid
,
546 &ScsiDiskDevice
->BlkIo2
,
547 &ScsiDiskDevice
->BlkIo2
549 Status
= EFI_MEDIA_CHANGED
;
554 // Get the intrinsic block size
556 Media
= ScsiDiskDevice
->BlkIo
.Media
;
557 BlockSize
= Media
->BlockSize
;
559 NumberOfBlocks
= BufferSize
/ BlockSize
;
561 if (!(Media
->MediaPresent
)) {
562 Status
= EFI_NO_MEDIA
;
566 if (MediaId
!= Media
->MediaId
) {
567 Status
= EFI_MEDIA_CHANGED
;
571 if (Buffer
== NULL
) {
572 Status
= EFI_INVALID_PARAMETER
;
576 if (BufferSize
== 0) {
577 Status
= EFI_SUCCESS
;
581 if (BufferSize
% BlockSize
!= 0) {
582 Status
= EFI_BAD_BUFFER_SIZE
;
586 if (Lba
> Media
->LastBlock
) {
587 Status
= EFI_INVALID_PARAMETER
;
591 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
592 Status
= EFI_INVALID_PARAMETER
;
596 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
597 Status
= EFI_INVALID_PARAMETER
;
602 // If all the parameters are valid, then perform read sectors command
603 // to transfer data from device to host.
605 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
608 gBS
->RestoreTPL (OldTpl
);
613 The function is to Write Block to SCSI Disk.
615 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
616 @param MediaId The Id of Media detected
617 @param Lba The logic block address
618 @param BufferSize The size of Buffer
619 @param Buffer The buffer to fill the read out data
621 @retval EFI_SUCCESS Successfully to read out block.
622 @retval EFI_WRITE_PROTECTED The device can not be written to.
623 @retval EFI_DEVICE_ERROR Fail to detect media.
624 @retval EFI_NO_MEDIA Media is not present.
625 @retval EFI_MEDIA_CHNAGED Media has changed.
626 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
627 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
632 ScsiDiskWriteBlocks (
633 IN EFI_BLOCK_IO_PROTOCOL
*This
,
640 SCSI_DISK_DEV
*ScsiDiskDevice
;
641 EFI_BLOCK_IO_MEDIA
*Media
;
644 UINTN NumberOfBlocks
;
649 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
650 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
652 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
654 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
655 if (EFI_ERROR (Status
)) {
656 Status
= EFI_DEVICE_ERROR
;
661 gBS
->ReinstallProtocolInterface (
662 ScsiDiskDevice
->Handle
,
663 &gEfiBlockIoProtocolGuid
,
664 &ScsiDiskDevice
->BlkIo
,
665 &ScsiDiskDevice
->BlkIo
667 gBS
->ReinstallProtocolInterface (
668 ScsiDiskDevice
->Handle
,
669 &gEfiBlockIo2ProtocolGuid
,
670 &ScsiDiskDevice
->BlkIo2
,
671 &ScsiDiskDevice
->BlkIo2
673 Status
= EFI_MEDIA_CHANGED
;
678 // Get the intrinsic block size
680 Media
= ScsiDiskDevice
->BlkIo
.Media
;
681 BlockSize
= Media
->BlockSize
;
683 NumberOfBlocks
= BufferSize
/ BlockSize
;
685 if (!(Media
->MediaPresent
)) {
686 Status
= EFI_NO_MEDIA
;
690 if (MediaId
!= Media
->MediaId
) {
691 Status
= EFI_MEDIA_CHANGED
;
695 if (BufferSize
== 0) {
696 Status
= EFI_SUCCESS
;
700 if (Buffer
== NULL
) {
701 Status
= EFI_INVALID_PARAMETER
;
705 if (BufferSize
% BlockSize
!= 0) {
706 Status
= EFI_BAD_BUFFER_SIZE
;
710 if (Lba
> Media
->LastBlock
) {
711 Status
= EFI_INVALID_PARAMETER
;
715 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
716 Status
= EFI_INVALID_PARAMETER
;
720 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
721 Status
= EFI_INVALID_PARAMETER
;
725 // if all the parameters are valid, then perform read sectors command
726 // to transfer data from device to host.
728 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
731 gBS
->RestoreTPL (OldTpl
);
738 EFI_SUCCESS is returned directly.
740 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
742 @retval EFI_SUCCESS All outstanding data was written to the device
747 ScsiDiskFlushBlocks (
748 IN EFI_BLOCK_IO_PROTOCOL
*This
761 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
762 @param ExtendedVerification The flag about if extend verificate.
764 @retval EFI_SUCCESS The device was reset.
765 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
767 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
773 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
774 IN BOOLEAN ExtendedVerification
778 SCSI_DISK_DEV
*ScsiDiskDevice
;
781 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
783 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
785 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
787 if (EFI_ERROR (Status
)) {
788 Status
= EFI_DEVICE_ERROR
;
792 if (!ExtendedVerification
) {
796 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
798 if (EFI_ERROR (Status
)) {
799 Status
= EFI_DEVICE_ERROR
;
804 gBS
->RestoreTPL (OldTpl
);
809 The function is to Read Block from SCSI Disk.
811 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
812 @param MediaId The Id of Media detected.
813 @param Lba The logic block address.
814 @param Token A pointer to the token associated with the transaction.
815 @param BufferSize The size of Buffer.
816 @param Buffer The buffer to fill the read out data.
818 @retval EFI_SUCCESS The read request was queued if Token-> Event is
819 not NULL. The data was read correctly from the
820 device if theToken-> Event is NULL.
821 @retval EFI_DEVICE_ERROR The device reported an error while attempting
822 to perform the read operation.
823 @retval EFI_NO_MEDIA There is no media in the device.
824 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
825 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
826 the intrinsic block size of the device.
827 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
828 valid, or the buffer is not on proper
830 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
836 ScsiDiskReadBlocksEx (
837 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
840 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
845 SCSI_DISK_DEV
*ScsiDiskDevice
;
846 EFI_BLOCK_IO_MEDIA
*Media
;
849 UINTN NumberOfBlocks
;
854 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
855 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
857 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
859 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
860 if (EFI_ERROR (Status
)) {
861 Status
= EFI_DEVICE_ERROR
;
866 gBS
->ReinstallProtocolInterface (
867 ScsiDiskDevice
->Handle
,
868 &gEfiBlockIoProtocolGuid
,
869 &ScsiDiskDevice
->BlkIo
,
870 &ScsiDiskDevice
->BlkIo
872 gBS
->ReinstallProtocolInterface (
873 ScsiDiskDevice
->Handle
,
874 &gEfiBlockIo2ProtocolGuid
,
875 &ScsiDiskDevice
->BlkIo2
,
876 &ScsiDiskDevice
->BlkIo2
878 Status
= EFI_MEDIA_CHANGED
;
883 // Get the intrinsic block size
885 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
886 BlockSize
= Media
->BlockSize
;
888 NumberOfBlocks
= BufferSize
/ BlockSize
;
890 if (!(Media
->MediaPresent
)) {
891 Status
= EFI_NO_MEDIA
;
895 if (MediaId
!= Media
->MediaId
) {
896 Status
= EFI_MEDIA_CHANGED
;
900 if (Buffer
== NULL
) {
901 Status
= EFI_INVALID_PARAMETER
;
905 if (BufferSize
== 0) {
906 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
907 Token
->TransactionStatus
= EFI_SUCCESS
;
908 gBS
->SignalEvent (Token
->Event
);
911 Status
= EFI_SUCCESS
;
915 if (BufferSize
% BlockSize
!= 0) {
916 Status
= EFI_BAD_BUFFER_SIZE
;
920 if (Lba
> Media
->LastBlock
) {
921 Status
= EFI_INVALID_PARAMETER
;
925 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
926 Status
= EFI_INVALID_PARAMETER
;
930 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
931 Status
= EFI_INVALID_PARAMETER
;
936 // If all the parameters are valid, then perform read sectors command
937 // to transfer data from device to host.
939 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
940 Token
->TransactionStatus
= EFI_SUCCESS
;
941 Status
= ScsiDiskAsyncReadSectors (
949 Status
= ScsiDiskReadSectors (
958 gBS
->RestoreTPL (OldTpl
);
963 The function is to Write Block to SCSI Disk.
965 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
966 @param MediaId The Id of Media detected.
967 @param Lba The logic block address.
968 @param Token A pointer to the token associated with the transaction.
969 @param BufferSize The size of Buffer.
970 @param Buffer The buffer to fill the read out data.
972 @retval EFI_SUCCESS The data were written correctly to the device.
973 @retval EFI_WRITE_PROTECTED The device cannot be written to.
974 @retval EFI_NO_MEDIA There is no media in the device.
975 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
976 @retval EFI_DEVICE_ERROR The device reported an error while attempting
977 to perform the write operation.
978 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
979 the intrinsic block size of the device.
980 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
981 valid, or the buffer is not on proper
987 ScsiDiskWriteBlocksEx (
988 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
991 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
996 SCSI_DISK_DEV
*ScsiDiskDevice
;
997 EFI_BLOCK_IO_MEDIA
*Media
;
1000 UINTN NumberOfBlocks
;
1001 BOOLEAN MediaChange
;
1004 MediaChange
= FALSE
;
1005 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1006 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1008 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1010 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1011 if (EFI_ERROR (Status
)) {
1012 Status
= EFI_DEVICE_ERROR
;
1017 gBS
->ReinstallProtocolInterface (
1018 ScsiDiskDevice
->Handle
,
1019 &gEfiBlockIoProtocolGuid
,
1020 &ScsiDiskDevice
->BlkIo
,
1021 &ScsiDiskDevice
->BlkIo
1023 gBS
->ReinstallProtocolInterface (
1024 ScsiDiskDevice
->Handle
,
1025 &gEfiBlockIo2ProtocolGuid
,
1026 &ScsiDiskDevice
->BlkIo2
,
1027 &ScsiDiskDevice
->BlkIo2
1029 Status
= EFI_MEDIA_CHANGED
;
1034 // Get the intrinsic block size
1036 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
1037 BlockSize
= Media
->BlockSize
;
1039 NumberOfBlocks
= BufferSize
/ BlockSize
;
1041 if (!(Media
->MediaPresent
)) {
1042 Status
= EFI_NO_MEDIA
;
1046 if (MediaId
!= Media
->MediaId
) {
1047 Status
= EFI_MEDIA_CHANGED
;
1051 if (BufferSize
== 0) {
1052 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1053 Token
->TransactionStatus
= EFI_SUCCESS
;
1054 gBS
->SignalEvent (Token
->Event
);
1057 Status
= EFI_SUCCESS
;
1061 if (Buffer
== NULL
) {
1062 Status
= EFI_INVALID_PARAMETER
;
1066 if (BufferSize
% BlockSize
!= 0) {
1067 Status
= EFI_BAD_BUFFER_SIZE
;
1071 if (Lba
> Media
->LastBlock
) {
1072 Status
= EFI_INVALID_PARAMETER
;
1076 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1077 Status
= EFI_INVALID_PARAMETER
;
1081 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1082 Status
= EFI_INVALID_PARAMETER
;
1087 // if all the parameters are valid, then perform write sectors command
1088 // to transfer data from device to host.
1090 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1091 Token
->TransactionStatus
= EFI_SUCCESS
;
1092 Status
= ScsiDiskAsyncWriteSectors (
1100 Status
= ScsiDiskWriteSectors (
1109 gBS
->RestoreTPL (OldTpl
);
1114 Flush the Block Device.
1116 @param This Indicates a pointer to the calling context.
1117 @param Token A pointer to the token associated with the transaction.
1119 @retval EFI_SUCCESS All outstanding data was written to the device.
1120 @retval EFI_DEVICE_ERROR The device reported an error while writing back the
1122 @retval EFI_NO_MEDIA There is no media in the device.
1127 ScsiDiskFlushBlocksEx (
1128 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1129 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1133 // Signal event and return directly.
1135 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1136 Token
->TransactionStatus
= EFI_SUCCESS
;
1137 gBS
->SignalEvent (Token
->Event
);
1145 Detect Device and read out capacity ,if error occurs, parse the sense key.
1147 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1148 @param MustReadCapacity The flag about reading device capacity
1149 @param MediaChange The pointer of flag indicates if media has changed
1151 @retval EFI_DEVICE_ERROR Indicates that error occurs
1152 @retval EFI_SUCCESS Successfully to detect media
1156 ScsiDiskDetectMedia (
1157 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1158 IN BOOLEAN MustReadCapacity
,
1159 OUT BOOLEAN
*MediaChange
1163 EFI_SCSI_SENSE_DATA
*SenseData
;
1164 UINTN NumberOfSenseKeys
;
1166 BOOLEAN NeedReadCapacity
;
1169 EFI_BLOCK_IO_MEDIA OldMedia
;
1171 EFI_EVENT TimeoutEvt
;
1173 Status
= EFI_SUCCESS
;
1175 NumberOfSenseKeys
= 0;
1178 Action
= ACTION_NO_ACTION
;
1179 NeedReadCapacity
= FALSE
;
1180 *MediaChange
= FALSE
;
1183 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
1185 Status
= gBS
->CreateEvent (
1192 if (EFI_ERROR (Status
)) {
1196 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
1197 if (EFI_ERROR (Status
)) {
1202 // Sending Test_Unit cmd to poll device status.
1203 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
1204 // We limit the upper boundary to 120 seconds.
1206 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
1207 Status
= ScsiDiskTestUnitReady (
1213 if (!EFI_ERROR (Status
)) {
1214 Status
= DetectMediaParsingSenseKeys (
1220 if (EFI_ERROR (Status
)) {
1222 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1229 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1235 if (EFI_ERROR (Status
)) {
1240 // ACTION_NO_ACTION: need not read capacity
1241 // other action code: need read capacity
1243 if (Action
== ACTION_READ_CAPACITY
) {
1244 NeedReadCapacity
= TRUE
;
1248 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
1249 // retrieve capacity via Read Capacity command
1251 if (NeedReadCapacity
|| MustReadCapacity
) {
1253 // retrieve media information
1255 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
1256 Status
= ScsiDiskReadCapacity (
1262 if (!EFI_ERROR (Status
)) {
1264 // analyze sense key to action
1266 Status
= DetectMediaParsingSenseKeys (
1272 if (EFI_ERROR (Status
)) {
1274 // if Status is error, it may indicate crisis error,
1275 // so return without retry.
1278 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1286 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1292 if (EFI_ERROR (Status
)) {
1297 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
1299 // Media change information got from the device
1301 *MediaChange
= TRUE
;
1304 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
1305 *MediaChange
= TRUE
;
1306 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1309 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
1310 *MediaChange
= TRUE
;
1311 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1314 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
1315 *MediaChange
= TRUE
;
1316 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1319 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
1320 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
1322 // when change from no media to media present, reset the MediaId to 1.
1324 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
1327 // when no media, reset the MediaId to zero.
1329 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
1332 *MediaChange
= TRUE
;
1336 if (TimeoutEvt
!= NULL
) {
1337 gBS
->CloseEvent (TimeoutEvt
);
1344 Send out Inquiry command to Device.
1346 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1347 @param NeedRetry Indicates if needs try again when error happens
1349 @retval EFI_DEVICE_ERROR Indicates that error occurs
1350 @retval EFI_SUCCESS Successfully to detect media
1354 ScsiDiskInquiryDevice (
1355 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1356 OUT BOOLEAN
*NeedRetry
1359 UINT32 InquiryDataLength
;
1360 UINT8 SenseDataLength
;
1361 UINT8 HostAdapterStatus
;
1363 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
1364 UINTN NumberOfSenseKeys
;
1368 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
1369 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
1372 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1373 SenseDataLength
= 0;
1375 Status
= ScsiInquiryCommand (
1376 ScsiDiskDevice
->ScsiIo
,
1382 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
1387 // no need to check HostAdapterStatus and TargetStatus
1389 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1390 ParseInquiryData (ScsiDiskDevice
);
1392 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1394 // Check whether the device supports Block Limits VPD page (0xB0)
1396 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1397 if (SupportedVpdPages
== NULL
) {
1399 return EFI_DEVICE_ERROR
;
1401 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1402 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
1403 SenseDataLength
= 0;
1404 Status
= ScsiInquiryCommandEx (
1405 ScsiDiskDevice
->ScsiIo
,
1411 (VOID
*) SupportedVpdPages
,
1414 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
1416 if (!EFI_ERROR (Status
)) {
1417 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
1418 | SupportedVpdPages
->PageLength1
;
1419 for (Index
= 0; Index
< PageLength
; Index
++) {
1420 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
1426 // Query the Block Limits VPD page
1428 if (Index
< PageLength
) {
1429 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1430 if (BlockLimits
== NULL
) {
1431 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1433 return EFI_DEVICE_ERROR
;
1435 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1436 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
1437 SenseDataLength
= 0;
1438 Status
= ScsiInquiryCommandEx (
1439 ScsiDiskDevice
->ScsiIo
,
1445 (VOID
*) BlockLimits
,
1448 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
1450 if (!EFI_ERROR (Status
)) {
1451 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
1452 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
1453 BlockLimits
->OptimalTransferLengthGranularity1
;
1456 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1460 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1464 if (!EFI_ERROR (Status
)) {
1467 } else if (Status
== EFI_NOT_READY
) {
1469 return EFI_DEVICE_ERROR
;
1471 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1473 return EFI_DEVICE_ERROR
;
1476 // go ahead to check HostAdapterStatus and TargetStatus
1477 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1480 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1481 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1483 return EFI_DEVICE_ERROR
;
1484 } else if (Status
== EFI_DEVICE_ERROR
) {
1486 // reset the scsi channel
1488 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1490 return EFI_DEVICE_ERROR
;
1493 Status
= CheckTargetStatus (TargetStatus
);
1494 if (Status
== EFI_NOT_READY
) {
1496 // reset the scsi device
1498 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1500 return EFI_DEVICE_ERROR
;
1502 } else if (Status
== EFI_DEVICE_ERROR
) {
1504 return EFI_DEVICE_ERROR
;
1508 // if goes here, meant ScsiInquiryCommand() failed.
1509 // if ScsiDiskRequestSenseKeys() succeeds at last,
1510 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1513 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1514 Status
= ScsiDiskRequestSenseKeys (
1521 if (!EFI_ERROR (Status
)) {
1523 return EFI_DEVICE_ERROR
;
1527 return EFI_DEVICE_ERROR
;
1531 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1532 // set *NeedRetry = FALSE to avoid the outside caller try again.
1535 return EFI_DEVICE_ERROR
;
1541 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1542 When Test Unit Ready command encounters any error caused by host adapter or
1543 target, return error without retrieving Sense Keys.
1545 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1546 @param NeedRetry The pointer of flag indicates try again
1547 @param SenseDataArray The pointer of an array of sense data
1548 @param NumberOfSenseKeys The pointer of the number of sense data array
1550 @retval EFI_DEVICE_ERROR Indicates that error occurs
1551 @retval EFI_SUCCESS Successfully to test unit
1555 ScsiDiskTestUnitReady (
1556 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1557 OUT BOOLEAN
*NeedRetry
,
1558 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1559 OUT UINTN
*NumberOfSenseKeys
1563 UINT8 SenseDataLength
;
1564 UINT8 HostAdapterStatus
;
1569 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
1570 *NumberOfSenseKeys
= 0;
1573 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1575 Status
= ScsiTestUnitReadyCommand (
1576 ScsiDiskDevice
->ScsiIo
,
1578 ScsiDiskDevice
->SenseData
,
1584 // no need to check HostAdapterStatus and TargetStatus
1586 if (Status
== EFI_NOT_READY
) {
1588 return EFI_DEVICE_ERROR
;
1590 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1592 return EFI_DEVICE_ERROR
;
1595 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1598 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1599 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1601 return EFI_DEVICE_ERROR
;
1603 } else if (Status
== EFI_DEVICE_ERROR
) {
1605 // reset the scsi channel
1607 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1609 return EFI_DEVICE_ERROR
;
1612 Status
= CheckTargetStatus (TargetStatus
);
1613 if (Status
== EFI_NOT_READY
) {
1615 // reset the scsi device
1617 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1619 return EFI_DEVICE_ERROR
;
1621 } else if (Status
== EFI_DEVICE_ERROR
) {
1623 return EFI_DEVICE_ERROR
;
1626 if (SenseDataLength
!= 0) {
1627 *NumberOfSenseKeys
= SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
);
1628 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1633 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1634 Status
= ScsiDiskRequestSenseKeys (
1641 if (!EFI_ERROR (Status
)) {
1646 return EFI_DEVICE_ERROR
;
1650 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1651 // set *NeedRetry = FALSE to avoid the outside caller try again.
1654 return EFI_DEVICE_ERROR
;
1658 Parsing Sense Keys which got from request sense command.
1660 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1661 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1662 @param NumberOfSenseKeys The number of sense key
1663 @param Action The pointer of action which indicates what is need to do next
1665 @retval EFI_DEVICE_ERROR Indicates that error occurs
1666 @retval EFI_SUCCESS Successfully to complete the parsing
1670 DetectMediaParsingSenseKeys (
1671 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1672 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1673 IN UINTN NumberOfSenseKeys
,
1680 // Default is to read capacity, unless..
1682 *Action
= ACTION_READ_CAPACITY
;
1684 if (NumberOfSenseKeys
== 0) {
1685 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1686 *Action
= ACTION_NO_ACTION
;
1691 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1693 // No Sense Key returned from last submitted command
1695 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1696 *Action
= ACTION_NO_ACTION
;
1701 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1702 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1703 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1704 *Action
= ACTION_NO_ACTION
;
1705 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
1709 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1710 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1711 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
1715 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
1716 *Action
= ACTION_RETRY_COMMAND_LATER
;
1717 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
1721 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1722 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
1723 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1724 return EFI_DEVICE_ERROR
;
1727 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1728 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
1729 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1730 return EFI_DEVICE_ERROR
;
1733 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1735 *Action
= ACTION_RETRY_COMMAND_LATER
;
1736 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
1739 *Action
= ACTION_NO_ACTION
;
1740 return EFI_DEVICE_ERROR
;
1743 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1744 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
1750 Send read capacity command to device and get the device parameter.
1752 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1753 @param NeedRetry The pointer of flag indicates if need a retry
1754 @param SenseDataArray The pointer of an array of sense data
1755 @param NumberOfSenseKeys The number of sense key
1757 @retval EFI_DEVICE_ERROR Indicates that error occurs
1758 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1762 ScsiDiskReadCapacity (
1763 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1764 OUT BOOLEAN
*NeedRetry
,
1765 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1766 OUT UINTN
*NumberOfSenseKeys
1769 UINT8 HostAdapterStatus
;
1771 EFI_STATUS CommandStatus
;
1775 UINT8 SenseDataLength
;
1776 UINT32 DataLength10
;
1777 UINT32 DataLength16
;
1778 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
1779 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
1781 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1782 if (CapacityData10
== NULL
) {
1784 return EFI_DEVICE_ERROR
;
1786 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1787 if (CapacityData16
== NULL
) {
1788 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1790 return EFI_DEVICE_ERROR
;
1793 SenseDataLength
= 0;
1794 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1795 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1796 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1797 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1799 *NumberOfSenseKeys
= 0;
1803 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1804 // 16 byte command should be used to access large hard disk >2TB
1806 CommandStatus
= ScsiReadCapacityCommand (
1807 ScsiDiskDevice
->ScsiIo
,
1813 (VOID
*) CapacityData10
,
1818 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1819 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
1820 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff)) {
1822 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1824 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1826 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1827 // and LowestAlignedLba
1829 CommandStatus
= ScsiReadCapacity16Command (
1830 ScsiDiskDevice
->ScsiIo
,
1836 (VOID
*) CapacityData16
,
1843 // no need to check HostAdapterStatus and TargetStatus
1845 if (CommandStatus
== EFI_SUCCESS
) {
1846 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
1847 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1848 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1852 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1853 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1855 if (CommandStatus
== EFI_NOT_READY
) {
1857 return EFI_DEVICE_ERROR
;
1858 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1860 return EFI_DEVICE_ERROR
;
1864 // go ahead to check HostAdapterStatus and TargetStatus
1865 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1868 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1869 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1871 return EFI_DEVICE_ERROR
;
1873 } else if (Status
== EFI_DEVICE_ERROR
) {
1875 // reset the scsi channel
1877 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1879 return EFI_DEVICE_ERROR
;
1882 Status
= CheckTargetStatus (TargetStatus
);
1883 if (Status
== EFI_NOT_READY
) {
1885 // reset the scsi device
1887 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1889 return EFI_DEVICE_ERROR
;
1891 } else if (Status
== EFI_DEVICE_ERROR
) {
1893 return EFI_DEVICE_ERROR
;
1897 // if goes here, meant ScsiReadCapacityCommand() failed.
1898 // if ScsiDiskRequestSenseKeys() succeeds at last,
1899 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1902 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1904 Status
= ScsiDiskRequestSenseKeys (
1911 if (!EFI_ERROR (Status
)) {
1916 return EFI_DEVICE_ERROR
;
1920 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1921 // set *NeedRetry = FALSE to avoid the outside caller try again.
1924 return EFI_DEVICE_ERROR
;
1928 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1930 @param HostAdapterStatus Host Adapter status
1932 @retval EFI_SUCCESS Host adapter is OK.
1933 @retval EFI_TIMEOUT Timeout.
1934 @retval EFI_NOT_READY Adapter NOT ready.
1935 @retval EFI_DEVICE_ERROR Adapter device error.
1939 CheckHostAdapterStatus (
1940 IN UINT8 HostAdapterStatus
1943 switch (HostAdapterStatus
) {
1944 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1947 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1948 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1949 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1952 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1953 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1954 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1955 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1956 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1957 return EFI_NOT_READY
;
1959 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1960 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1961 return EFI_DEVICE_ERROR
;
1970 Check the target status and re-interpret it in EFI_STATUS.
1972 @param TargetStatus Target status
1974 @retval EFI_NOT_READY Device is NOT ready.
1975 @retval EFI_DEVICE_ERROR
1981 IN UINT8 TargetStatus
1984 switch (TargetStatus
) {
1985 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1986 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1987 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1990 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1991 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1992 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1993 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1994 return EFI_NOT_READY
;
1996 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1997 return EFI_DEVICE_ERROR
;
2006 Retrieve all sense keys from the device.
2008 When encountering error during the process, if retrieve sense keys before
2009 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
2010 and NeedRetry set to FALSE; otherwize, return the proper return status.
2012 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2013 @param NeedRetry The pointer of flag indicates if need a retry
2014 @param SenseDataArray The pointer of an array of sense data
2015 @param NumberOfSenseKeys The number of sense key
2016 @param AskResetIfError The flag indicates if need reset when error occurs
2018 @retval EFI_DEVICE_ERROR Indicates that error occurs
2019 @retval EFI_SUCCESS Successfully to request sense key
2023 ScsiDiskRequestSenseKeys (
2024 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2025 OUT BOOLEAN
*NeedRetry
,
2026 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2027 OUT UINTN
*NumberOfSenseKeys
,
2028 IN BOOLEAN AskResetIfError
2031 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
2032 UINT8 SenseDataLength
;
2035 EFI_STATUS FallStatus
;
2036 UINT8 HostAdapterStatus
;
2039 FallStatus
= EFI_SUCCESS
;
2040 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
2043 ScsiDiskDevice
->SenseData
,
2044 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
2047 *NumberOfSenseKeys
= 0;
2048 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2049 Status
= EFI_SUCCESS
;
2050 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
2051 if (PtrSenseData
== NULL
) {
2052 return EFI_DEVICE_ERROR
;
2055 for (SenseReq
= TRUE
; SenseReq
;) {
2056 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2057 Status
= ScsiRequestSenseCommand (
2058 ScsiDiskDevice
->ScsiIo
,
2065 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
2066 FallStatus
= EFI_SUCCESS
;
2068 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2070 FallStatus
= EFI_DEVICE_ERROR
;
2072 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2074 FallStatus
= EFI_DEVICE_ERROR
;
2076 } else if (Status
== EFI_DEVICE_ERROR
) {
2077 if (AskResetIfError
) {
2078 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2081 FallStatus
= EFI_DEVICE_ERROR
;
2084 if (EFI_ERROR (FallStatus
)) {
2085 if (*NumberOfSenseKeys
!= 0) {
2087 Status
= EFI_SUCCESS
;
2090 Status
= EFI_DEVICE_ERROR
;
2095 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
2096 (*NumberOfSenseKeys
) += 1;
2099 // no more sense key or number of sense keys exceeds predefined,
2102 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
2103 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
2109 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2115 Get information from media read capacity command.
2117 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2118 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
2119 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
2124 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2125 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
2126 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
2131 if (!ScsiDiskDevice
->Cdb16Byte
) {
2132 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
2133 (Capacity10
->LastLba2
<< 16) |
2134 (Capacity10
->LastLba1
<< 8) |
2135 Capacity10
->LastLba0
;
2137 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
2138 (Capacity10
->BlockSize2
<< 16) |
2139 (Capacity10
->BlockSize1
<< 8) |
2140 Capacity10
->BlockSize0
;
2141 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
2142 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
2144 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2145 *Ptr
++ = Capacity16
->LastLba0
;
2146 *Ptr
++ = Capacity16
->LastLba1
;
2147 *Ptr
++ = Capacity16
->LastLba2
;
2148 *Ptr
++ = Capacity16
->LastLba3
;
2149 *Ptr
++ = Capacity16
->LastLba4
;
2150 *Ptr
++ = Capacity16
->LastLba5
;
2151 *Ptr
++ = Capacity16
->LastLba6
;
2152 *Ptr
= Capacity16
->LastLba7
;
2154 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
2155 (Capacity16
->BlockSize2
<< 16) |
2156 (Capacity16
->BlockSize1
<< 8) |
2157 Capacity16
->BlockSize0
;
2159 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
2160 Capacity16
->LowestAlignLogic1
;
2161 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
2164 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
2170 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2175 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2178 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
2179 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
2183 Read sector from SCSI Disk.
2185 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2186 @param Buffer The buffer to fill in the read out data
2187 @param Lba Logic block address
2188 @param NumberOfBlocks The number of blocks to read
2190 @retval EFI_DEVICE_ERROR Indicates a device error.
2191 @retval EFI_SUCCESS Operation is successful.
2195 ScsiDiskReadSectors (
2196 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2199 IN UINTN NumberOfBlocks
2202 UINTN BlocksRemaining
;
2208 UINT32 NextSectorCount
;
2215 Status
= EFI_SUCCESS
;
2217 BlocksRemaining
= NumberOfBlocks
;
2218 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2221 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2223 if (!ScsiDiskDevice
->Cdb16Byte
) {
2226 MaxBlock
= 0xFFFFFFFF;
2231 while (BlocksRemaining
> 0) {
2233 if (BlocksRemaining
<= MaxBlock
) {
2234 if (!ScsiDiskDevice
->Cdb16Byte
) {
2235 SectorCount
= (UINT16
) BlocksRemaining
;
2237 SectorCount
= (UINT32
) BlocksRemaining
;
2240 SectorCount
= MaxBlock
;
2243 ByteCount
= SectorCount
* BlockSize
;
2245 // |------------------------|-----------------|------------------|-----------------|
2246 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2247 // |------------------------|-----------------|------------------|-----------------|
2248 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2249 // |------------------------|-----------------|------------------|-----------------|
2250 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2251 // |------------------------|-----------------|------------------|-----------------|
2252 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2253 // |------------------------|-----------------|------------------|-----------------|
2254 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2255 // |------------------------|-----------------|------------------|-----------------|
2256 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2257 // |------------------------|-----------------|------------------|-----------------|
2258 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2259 // |------------------------|-----------------|------------------|-----------------|
2260 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2261 // |------------------------|-----------------|------------------|-----------------|
2262 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2263 // |------------------------|-----------------|------------------|-----------------|
2264 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2265 // |------------------------|-----------------|------------------|-----------------|
2266 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2267 // |------------------------|-----------------|------------------|-----------------|
2269 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2270 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2271 // From the above table, we could know 2.1Mbytes per second is lowest one.
2272 // The timout value is rounded up to nearest integar and here an additional 30s is added
2273 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2274 // commands in the Standby/Idle mode.
2276 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2279 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2280 if (!ScsiDiskDevice
->Cdb16Byte
) {
2281 Status
= ScsiDiskRead10 (
2291 Status
= ScsiDiskRead16 (
2301 if (!EFI_ERROR (Status
)) {
2306 return EFI_DEVICE_ERROR
;
2310 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
2311 // lowered ByteCount on output, we must make sure that we lower
2312 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2313 // it is invalid to request more sectors in the CDB than the entire
2314 // transfer (ie. ByteCount) can carry.
2316 // In addition, ByteCount is only expected to go down, or stay unchaged.
2317 // Therefore we don't need to update Timeout: the original timeout should
2318 // accommodate shorter transfers too.
2320 NextSectorCount
= ByteCount
/ BlockSize
;
2321 if (NextSectorCount
< SectorCount
) {
2322 SectorCount
= NextSectorCount
;
2324 // Account for any rounding down.
2326 ByteCount
= SectorCount
* BlockSize
;
2330 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2331 return EFI_DEVICE_ERROR
;
2335 // actual transferred sectors
2337 SectorCount
= ByteCount
/ BlockSize
;
2340 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2341 BlocksRemaining
-= SectorCount
;
2348 Write sector to SCSI Disk.
2350 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2351 @param Buffer The buffer of data to be written into SCSI Disk
2352 @param Lba Logic block address
2353 @param NumberOfBlocks The number of blocks to read
2355 @retval EFI_DEVICE_ERROR Indicates a device error.
2356 @retval EFI_SUCCESS Operation is successful.
2360 ScsiDiskWriteSectors (
2361 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2364 IN UINTN NumberOfBlocks
2367 UINTN BlocksRemaining
;
2373 UINT32 NextSectorCount
;
2380 Status
= EFI_SUCCESS
;
2382 BlocksRemaining
= NumberOfBlocks
;
2383 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2386 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2388 if (!ScsiDiskDevice
->Cdb16Byte
) {
2391 MaxBlock
= 0xFFFFFFFF;
2396 while (BlocksRemaining
> 0) {
2398 if (BlocksRemaining
<= MaxBlock
) {
2399 if (!ScsiDiskDevice
->Cdb16Byte
) {
2400 SectorCount
= (UINT16
) BlocksRemaining
;
2402 SectorCount
= (UINT32
) BlocksRemaining
;
2405 SectorCount
= MaxBlock
;
2408 ByteCount
= SectorCount
* BlockSize
;
2410 // |------------------------|-----------------|------------------|-----------------|
2411 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2412 // |------------------------|-----------------|------------------|-----------------|
2413 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2414 // |------------------------|-----------------|------------------|-----------------|
2415 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2416 // |------------------------|-----------------|------------------|-----------------|
2417 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2418 // |------------------------|-----------------|------------------|-----------------|
2419 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2420 // |------------------------|-----------------|------------------|-----------------|
2421 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2422 // |------------------------|-----------------|------------------|-----------------|
2423 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2424 // |------------------------|-----------------|------------------|-----------------|
2425 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2426 // |------------------------|-----------------|------------------|-----------------|
2427 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2428 // |------------------------|-----------------|------------------|-----------------|
2429 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2430 // |------------------------|-----------------|------------------|-----------------|
2431 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2432 // |------------------------|-----------------|------------------|-----------------|
2434 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2435 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2436 // From the above table, we could know 2.1Mbytes per second is lowest one.
2437 // The timout value is rounded up to nearest integar and here an additional 30s is added
2438 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2439 // commands in the Standby/Idle mode.
2441 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2443 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2444 if (!ScsiDiskDevice
->Cdb16Byte
) {
2445 Status
= ScsiDiskWrite10 (
2455 Status
= ScsiDiskWrite16 (
2465 if (!EFI_ERROR (Status
)) {
2470 return EFI_DEVICE_ERROR
;
2474 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
2475 // has lowered ByteCount on output, we must make sure that we lower
2476 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2477 // it is invalid to request more sectors in the CDB than the entire
2478 // transfer (ie. ByteCount) can carry.
2480 // In addition, ByteCount is only expected to go down, or stay unchaged.
2481 // Therefore we don't need to update Timeout: the original timeout should
2482 // accommodate shorter transfers too.
2484 NextSectorCount
= ByteCount
/ BlockSize
;
2485 if (NextSectorCount
< SectorCount
) {
2486 SectorCount
= NextSectorCount
;
2488 // Account for any rounding down.
2490 ByteCount
= SectorCount
* BlockSize
;
2494 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2495 return EFI_DEVICE_ERROR
;
2498 // actual transferred sectors
2500 SectorCount
= ByteCount
/ BlockSize
;
2503 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2504 BlocksRemaining
-= SectorCount
;
2511 Asynchronously read sector from SCSI Disk.
2513 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2514 @param Buffer The buffer to fill in the read out data.
2515 @param Lba Logic block address.
2516 @param NumberOfBlocks The number of blocks to read.
2517 @param Token A pointer to the token associated with the
2518 non-blocking read request.
2520 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
2521 @retval EFI_DEVICE_ERROR Indicates a device error.
2522 @retval EFI_SUCCESS Operation is successful.
2526 ScsiDiskAsyncReadSectors (
2527 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2530 IN UINTN NumberOfBlocks
,
2531 IN EFI_BLOCK_IO2_TOKEN
*Token
2534 UINTN BlocksRemaining
;
2541 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
2544 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
2545 return EFI_INVALID_PARAMETER
;
2548 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
2549 if (BlkIo2Req
== NULL
) {
2550 return EFI_OUT_OF_RESOURCES
;
2553 BlkIo2Req
->Token
= Token
;
2554 InsertTailList (&ScsiDiskDevice
->BlkIo2Queue
, &BlkIo2Req
->Link
);
2555 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
2557 Status
= EFI_SUCCESS
;
2559 BlocksRemaining
= NumberOfBlocks
;
2560 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2563 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2566 if (!ScsiDiskDevice
->Cdb16Byte
) {
2569 MaxBlock
= 0xFFFFFFFF;
2574 while (BlocksRemaining
> 0) {
2576 if (BlocksRemaining
<= MaxBlock
) {
2577 if (!ScsiDiskDevice
->Cdb16Byte
) {
2578 SectorCount
= (UINT16
) BlocksRemaining
;
2580 SectorCount
= (UINT32
) BlocksRemaining
;
2583 SectorCount
= MaxBlock
;
2586 ByteCount
= SectorCount
* BlockSize
;
2588 // |------------------------|-----------------|------------------|-----------------|
2589 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2590 // |------------------------|-----------------|------------------|-----------------|
2591 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2592 // |------------------------|-----------------|------------------|-----------------|
2593 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2594 // |------------------------|-----------------|------------------|-----------------|
2595 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2596 // |------------------------|-----------------|------------------|-----------------|
2597 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2598 // |------------------------|-----------------|------------------|-----------------|
2599 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2600 // |------------------------|-----------------|------------------|-----------------|
2601 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2602 // |------------------------|-----------------|------------------|-----------------|
2603 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2604 // |------------------------|-----------------|------------------|-----------------|
2605 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2606 // |------------------------|-----------------|------------------|-----------------|
2607 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2608 // |------------------------|-----------------|------------------|-----------------|
2609 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2610 // |------------------------|-----------------|------------------|-----------------|
2612 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2613 // we have to use the lowest transfer rate to calculate the possible
2614 // maximum timeout value for each operation.
2615 // From the above table, we could know 2.1Mbytes per second is lowest one.
2616 // The timout value is rounded up to nearest integar and here an additional
2617 // 30s is added to follow ATA spec in which it mentioned that the device
2618 // may take up to 30s to respond commands in the Standby/Idle mode.
2620 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2622 if (!ScsiDiskDevice
->Cdb16Byte
) {
2623 Status
= ScsiDiskAsyncRead10 (
2634 Status
= ScsiDiskAsyncRead16 (
2645 if (EFI_ERROR (Status
)) {
2647 // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI
2648 // command fails. Otherwise, it will be freed in the callback function
2649 // ScsiDiskNotify().
2651 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2652 RemoveEntryList (&BlkIo2Req
->Link
);
2653 FreePool (BlkIo2Req
);
2655 return EFI_DEVICE_ERROR
;
2659 // Sectors submitted for transfer
2661 SectorCount
= ByteCount
/ BlockSize
;
2664 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2665 BlocksRemaining
-= SectorCount
;
2672 Asynchronously write sector to SCSI Disk.
2674 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2675 @param Buffer The buffer of data to be written into SCSI Disk.
2676 @param Lba Logic block address.
2677 @param NumberOfBlocks The number of blocks to read.
2678 @param Token A pointer to the token associated with the
2679 non-blocking read request.
2681 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
2682 @retval EFI_DEVICE_ERROR Indicates a device error.
2683 @retval EFI_SUCCESS Operation is successful.
2687 ScsiDiskAsyncWriteSectors (
2688 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2691 IN UINTN NumberOfBlocks
,
2692 IN EFI_BLOCK_IO2_TOKEN
*Token
2695 UINTN BlocksRemaining
;
2702 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
2705 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
2706 return EFI_INVALID_PARAMETER
;
2709 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
2710 if (BlkIo2Req
== NULL
) {
2711 return EFI_OUT_OF_RESOURCES
;
2714 BlkIo2Req
->Token
= Token
;
2715 InsertTailList (&ScsiDiskDevice
->BlkIo2Queue
, &BlkIo2Req
->Link
);
2716 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
2718 Status
= EFI_SUCCESS
;
2720 BlocksRemaining
= NumberOfBlocks
;
2721 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2724 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2727 if (!ScsiDiskDevice
->Cdb16Byte
) {
2730 MaxBlock
= 0xFFFFFFFF;
2735 while (BlocksRemaining
> 0) {
2737 if (BlocksRemaining
<= MaxBlock
) {
2738 if (!ScsiDiskDevice
->Cdb16Byte
) {
2739 SectorCount
= (UINT16
) BlocksRemaining
;
2741 SectorCount
= (UINT32
) BlocksRemaining
;
2744 SectorCount
= MaxBlock
;
2747 ByteCount
= SectorCount
* BlockSize
;
2749 // |------------------------|-----------------|------------------|-----------------|
2750 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2751 // |------------------------|-----------------|------------------|-----------------|
2752 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2753 // |------------------------|-----------------|------------------|-----------------|
2754 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2755 // |------------------------|-----------------|------------------|-----------------|
2756 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2757 // |------------------------|-----------------|------------------|-----------------|
2758 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2759 // |------------------------|-----------------|------------------|-----------------|
2760 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2761 // |------------------------|-----------------|------------------|-----------------|
2762 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2763 // |------------------------|-----------------|------------------|-----------------|
2764 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2765 // |------------------------|-----------------|------------------|-----------------|
2766 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2767 // |------------------------|-----------------|------------------|-----------------|
2768 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2769 // |------------------------|-----------------|------------------|-----------------|
2770 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2771 // |------------------------|-----------------|------------------|-----------------|
2773 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2774 // we have to use the lowest transfer rate to calculate the possible
2775 // maximum timeout value for each operation.
2776 // From the above table, we could know 2.1Mbytes per second is lowest one.
2777 // The timout value is rounded up to nearest integar and here an additional
2778 // 30s is added to follow ATA spec in which it mentioned that the device
2779 // may take up to 30s to respond commands in the Standby/Idle mode.
2781 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2783 if (!ScsiDiskDevice
->Cdb16Byte
) {
2784 Status
= ScsiDiskAsyncWrite10 (
2795 Status
= ScsiDiskAsyncWrite16 (
2806 if (EFI_ERROR (Status
)) {
2808 // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI
2809 // command fails. Otherwise, it will be freed in the callback function
2810 // ScsiDiskNotify().
2812 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2813 RemoveEntryList (&BlkIo2Req
->Link
);
2814 FreePool (BlkIo2Req
);
2816 return EFI_DEVICE_ERROR
;
2820 // Sectors submitted for transfer
2822 SectorCount
= ByteCount
/ BlockSize
;
2825 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2826 BlocksRemaining
-= SectorCount
;
2834 Submit Read(10) command.
2836 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2837 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2838 @param Timeout The time to complete the command
2839 @param DataBuffer The buffer to fill with the read out data
2840 @param DataLength The length of buffer
2841 @param StartLba The start logic block address
2842 @param SectorCount The number of blocks to read
2844 @return EFI_STATUS is returned by calling ScsiRead10Command().
2848 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2849 OUT BOOLEAN
*NeedRetry
,
2851 OUT UINT8
*DataBuffer
,
2852 IN OUT UINT32
*DataLength
,
2854 IN UINT32 SectorCount
2857 UINT8 SenseDataLength
;
2859 EFI_STATUS ReturnStatus
;
2860 UINT8 HostAdapterStatus
;
2865 // Implement a backoff algorithem to resolve some compatibility issues that
2866 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2867 // big data in a single operation.
2868 // This algorithem will at first try to execute original request. If the request fails
2869 // with media error sense data or else, it will reduce the transfer length to half and
2870 // try again till the operation succeeds or fails with one sector transfer length.
2874 Action
= ACTION_NO_ACTION
;
2875 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2876 ReturnStatus
= ScsiRead10Command (
2877 ScsiDiskDevice
->ScsiIo
,
2879 ScsiDiskDevice
->SenseData
,
2889 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
2891 return EFI_DEVICE_ERROR
;
2892 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
2894 return ReturnStatus
;
2898 // go ahead to check HostAdapterStatus and TargetStatus
2899 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2901 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2902 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2904 return EFI_DEVICE_ERROR
;
2905 } else if (Status
== EFI_DEVICE_ERROR
) {
2907 // reset the scsi channel
2909 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2911 return EFI_DEVICE_ERROR
;
2914 Status
= CheckTargetStatus (TargetStatus
);
2915 if (Status
== EFI_NOT_READY
) {
2917 // reset the scsi device
2919 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2921 return EFI_DEVICE_ERROR
;
2922 } else if (Status
== EFI_DEVICE_ERROR
) {
2924 return EFI_DEVICE_ERROR
;
2927 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
2928 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
2929 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
2930 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2932 return EFI_DEVICE_ERROR
;
2933 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
2934 if (SectorCount
<= 1) {
2936 // Jump out if the operation still fails with one sector transfer length.
2939 return EFI_DEVICE_ERROR
;
2942 // Try again with half length if the sense data shows we need to retry.
2945 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2949 return EFI_DEVICE_ERROR
;
2953 return ReturnStatus
;
2958 Submit Write(10) Command.
2960 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2961 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2962 @param Timeout The time to complete the command
2963 @param DataBuffer The buffer to fill with the read out data
2964 @param DataLength The length of buffer
2965 @param StartLba The start logic block address
2966 @param SectorCount The number of blocks to write
2968 @return EFI_STATUS is returned by calling ScsiWrite10Command().
2973 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2974 OUT BOOLEAN
*NeedRetry
,
2976 IN UINT8
*DataBuffer
,
2977 IN OUT UINT32
*DataLength
,
2979 IN UINT32 SectorCount
2983 EFI_STATUS ReturnStatus
;
2984 UINT8 SenseDataLength
;
2985 UINT8 HostAdapterStatus
;
2990 // Implement a backoff algorithem to resolve some compatibility issues that
2991 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2992 // big data in a single operation.
2993 // This algorithem will at first try to execute original request. If the request fails
2994 // with media error sense data or else, it will reduce the transfer length to half and
2995 // try again till the operation succeeds or fails with one sector transfer length.
2999 Action
= ACTION_NO_ACTION
;
3000 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3001 ReturnStatus
= ScsiWrite10Command (
3002 ScsiDiskDevice
->ScsiIo
,
3004 ScsiDiskDevice
->SenseData
,
3013 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3015 return EFI_DEVICE_ERROR
;
3016 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3018 return ReturnStatus
;
3022 // go ahead to check HostAdapterStatus and TargetStatus
3023 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3025 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3026 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3028 return EFI_DEVICE_ERROR
;
3029 } else if (Status
== EFI_DEVICE_ERROR
) {
3031 // reset the scsi channel
3033 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3035 return EFI_DEVICE_ERROR
;
3038 Status
= CheckTargetStatus (TargetStatus
);
3039 if (Status
== EFI_NOT_READY
) {
3041 // reset the scsi device
3043 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3045 return EFI_DEVICE_ERROR
;
3046 } else if (Status
== EFI_DEVICE_ERROR
) {
3048 return EFI_DEVICE_ERROR
;
3051 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3052 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
3053 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3054 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3056 return EFI_DEVICE_ERROR
;
3057 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3058 if (SectorCount
<= 1) {
3060 // Jump out if the operation still fails with one sector transfer length.
3063 return EFI_DEVICE_ERROR
;
3066 // Try again with half length if the sense data shows we need to retry.
3069 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3073 return EFI_DEVICE_ERROR
;
3077 return ReturnStatus
;
3082 Submit Read(16) command.
3084 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3085 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3086 @param Timeout The time to complete the command
3087 @param DataBuffer The buffer to fill with the read out data
3088 @param DataLength The length of buffer
3089 @param StartLba The start logic block address
3090 @param SectorCount The number of blocks to read
3092 @return EFI_STATUS is returned by calling ScsiRead16Command().
3096 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3097 OUT BOOLEAN
*NeedRetry
,
3099 OUT UINT8
*DataBuffer
,
3100 IN OUT UINT32
*DataLength
,
3102 IN UINT32 SectorCount
3105 UINT8 SenseDataLength
;
3107 EFI_STATUS ReturnStatus
;
3108 UINT8 HostAdapterStatus
;
3113 // Implement a backoff algorithem to resolve some compatibility issues that
3114 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3115 // big data in a single operation.
3116 // This algorithem will at first try to execute original request. If the request fails
3117 // with media error sense data or else, it will reduce the transfer length to half and
3118 // try again till the operation succeeds or fails with one sector transfer length.
3122 Action
= ACTION_NO_ACTION
;
3123 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3124 ReturnStatus
= ScsiRead16Command (
3125 ScsiDiskDevice
->ScsiIo
,
3127 ScsiDiskDevice
->SenseData
,
3136 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3138 return EFI_DEVICE_ERROR
;
3139 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3141 return ReturnStatus
;
3145 // go ahead to check HostAdapterStatus and TargetStatus
3146 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3148 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3149 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3151 return EFI_DEVICE_ERROR
;
3152 } else if (Status
== EFI_DEVICE_ERROR
) {
3154 // reset the scsi channel
3156 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3158 return EFI_DEVICE_ERROR
;
3161 Status
= CheckTargetStatus (TargetStatus
);
3162 if (Status
== EFI_NOT_READY
) {
3164 // reset the scsi device
3166 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3168 return EFI_DEVICE_ERROR
;
3169 } else if (Status
== EFI_DEVICE_ERROR
) {
3171 return EFI_DEVICE_ERROR
;
3174 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3175 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
3176 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3177 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3179 return EFI_DEVICE_ERROR
;
3180 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3181 if (SectorCount
<= 1) {
3183 // Jump out if the operation still fails with one sector transfer length.
3186 return EFI_DEVICE_ERROR
;
3189 // Try again with half length if the sense data shows we need to retry.
3192 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3196 return EFI_DEVICE_ERROR
;
3200 return ReturnStatus
;
3205 Submit Write(16) Command.
3207 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3208 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3209 @param Timeout The time to complete the command
3210 @param DataBuffer The buffer to fill with the read out data
3211 @param DataLength The length of buffer
3212 @param StartLba The start logic block address
3213 @param SectorCount The number of blocks to write
3215 @return EFI_STATUS is returned by calling ScsiWrite16Command().
3220 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3221 OUT BOOLEAN
*NeedRetry
,
3223 IN UINT8
*DataBuffer
,
3224 IN OUT UINT32
*DataLength
,
3226 IN UINT32 SectorCount
3230 EFI_STATUS ReturnStatus
;
3231 UINT8 SenseDataLength
;
3232 UINT8 HostAdapterStatus
;
3237 // Implement a backoff algorithem to resolve some compatibility issues that
3238 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3239 // big data in a single operation.
3240 // This algorithem will at first try to execute original request. If the request fails
3241 // with media error sense data or else, it will reduce the transfer length to half and
3242 // try again till the operation succeeds or fails with one sector transfer length.
3246 Action
= ACTION_NO_ACTION
;
3247 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3248 ReturnStatus
= ScsiWrite16Command (
3249 ScsiDiskDevice
->ScsiIo
,
3251 ScsiDiskDevice
->SenseData
,
3260 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3262 return EFI_DEVICE_ERROR
;
3263 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3265 return ReturnStatus
;
3269 // go ahead to check HostAdapterStatus and TargetStatus
3270 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3272 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3273 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3275 return EFI_DEVICE_ERROR
;
3276 } else if (Status
== EFI_DEVICE_ERROR
) {
3278 // reset the scsi channel
3280 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3282 return EFI_DEVICE_ERROR
;
3285 Status
= CheckTargetStatus (TargetStatus
);
3286 if (Status
== EFI_NOT_READY
) {
3288 // reset the scsi device
3290 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3292 return EFI_DEVICE_ERROR
;
3293 } else if (Status
== EFI_DEVICE_ERROR
) {
3295 return EFI_DEVICE_ERROR
;
3298 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3299 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
3300 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3301 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3303 return EFI_DEVICE_ERROR
;
3304 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3305 if (SectorCount
<= 1) {
3307 // Jump out if the operation still fails with one sector transfer length.
3310 return EFI_DEVICE_ERROR
;
3313 // Try again with half length if the sense data shows we need to retry.
3316 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3320 return EFI_DEVICE_ERROR
;
3324 return ReturnStatus
;
3329 Internal helper notify function in which determine whether retry of a SCSI
3330 Read/Write command is needed and signal the event passed from Block I/O(2) if
3331 the SCSI I/O operation completes.
3333 @param Event The instance of EFI_EVENT.
3334 @param Context The parameter passed in.
3345 SCSI_ASYNC_RW_REQUEST
*Request
;
3346 SCSI_DISK_DEV
*ScsiDiskDevice
;
3347 EFI_BLOCK_IO2_TOKEN
*Token
;
3349 UINT32 OldDataLength
;
3350 UINT32 OldSectorCount
;
3353 gBS
->CloseEvent (Event
);
3355 Request
= (SCSI_ASYNC_RW_REQUEST
*) Context
;
3356 ScsiDiskDevice
= Request
->ScsiDiskDevice
;
3357 Token
= Request
->BlkIo2Req
->Token
;
3358 OldDataLength
= Request
->DataLength
;
3359 OldSectorCount
= Request
->SectorCount
;
3363 // If previous sub-tasks already fails, no need to process this sub-task.
3365 if (Token
->TransactionStatus
!= EFI_SUCCESS
) {
3370 // Check HostAdapterStatus and TargetStatus
3371 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3373 Status
= CheckHostAdapterStatus (Request
->HostAdapterStatus
);
3374 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3375 if (++Request
->TimesRetry
> MaxRetry
) {
3376 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3381 } else if (Status
== EFI_DEVICE_ERROR
) {
3383 // reset the scsi channel
3385 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3386 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3390 Status
= CheckTargetStatus (Request
->TargetStatus
);
3391 if (Status
== EFI_NOT_READY
) {
3393 // reset the scsi device
3395 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3396 if (++Request
->TimesRetry
> MaxRetry
) {
3397 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3402 } else if (Status
== EFI_DEVICE_ERROR
) {
3403 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3407 if (Request
->TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) {
3408 DEBUG ((EFI_D_ERROR
, "ScsiDiskNotify: Check Condition happened!\n"));
3410 Status
= DetectMediaParsingSenseKeys (
3413 Request
->SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
),
3416 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3417 if (++Request
->TimesRetry
> MaxRetry
) {
3418 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3423 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3424 if (Request
->SectorCount
<= 1) {
3426 // Jump out if the operation still fails with one sector transfer
3429 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3433 // Try again with two half length request if the sense data shows we need
3436 Request
->SectorCount
>>= 1;
3437 Request
->DataLength
= Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3438 Request
->TimesRetry
= 0;
3442 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3448 // This sub-task succeeds, no need to retry.
3453 if (Request
->InBuffer
!= NULL
) {
3455 // SCSI read command
3457 if (!ScsiDiskDevice
->Cdb16Byte
) {
3458 Status
= ScsiDiskAsyncRead10 (
3462 Request
->DataLength
,
3463 (UINT32
) Request
->StartLba
,
3464 Request
->SectorCount
,
3469 Status
= ScsiDiskAsyncRead16 (
3473 Request
->DataLength
,
3475 Request
->SectorCount
,
3481 if (EFI_ERROR (Status
)) {
3482 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3484 } else if (OldSectorCount
!= Request
->SectorCount
) {
3486 // Original sub-task will be split into two new sub-tasks with smaller
3489 if (!ScsiDiskDevice
->Cdb16Byte
) {
3490 Status
= ScsiDiskAsyncRead10 (
3493 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3494 OldDataLength
- Request
->DataLength
,
3495 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
3496 OldSectorCount
- Request
->SectorCount
,
3501 Status
= ScsiDiskAsyncRead16 (
3504 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3505 OldDataLength
- Request
->DataLength
,
3506 Request
->StartLba
+ Request
->SectorCount
,
3507 OldSectorCount
- Request
->SectorCount
,
3512 if (EFI_ERROR (Status
)) {
3513 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3519 // SCSI write command
3521 if (!ScsiDiskDevice
->Cdb16Byte
) {
3522 Status
= ScsiDiskAsyncWrite10 (
3526 Request
->DataLength
,
3527 (UINT32
) Request
->StartLba
,
3528 Request
->SectorCount
,
3533 Status
= ScsiDiskAsyncWrite16 (
3537 Request
->DataLength
,
3539 Request
->SectorCount
,
3545 if (EFI_ERROR (Status
)) {
3546 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3548 } else if (OldSectorCount
!= Request
->SectorCount
) {
3550 // Original sub-task will be split into two new sub-tasks with smaller
3553 if (!ScsiDiskDevice
->Cdb16Byte
) {
3554 Status
= ScsiDiskAsyncWrite10 (
3557 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3558 OldDataLength
- Request
->DataLength
,
3559 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
3560 OldSectorCount
- Request
->SectorCount
,
3565 Status
= ScsiDiskAsyncWrite16 (
3568 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3569 OldDataLength
- Request
->DataLength
,
3570 Request
->StartLba
+ Request
->SectorCount
,
3571 OldSectorCount
- Request
->SectorCount
,
3576 if (EFI_ERROR (Status
)) {
3577 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3584 RemoveEntryList (&Request
->Link
);
3585 if (IsListEmpty (&Request
->BlkIo2Req
->ScsiRWQueue
)) {
3587 // The last SCSI R/W command of a BlockIo2 request completes
3589 RemoveEntryList (&Request
->BlkIo2Req
->Link
);
3590 FreePool (Request
->BlkIo2Req
); // Should be freed only once
3591 gBS
->SignalEvent (Token
->Event
);
3594 FreePool (Request
->SenseData
);
3600 Submit Async Read(10) command.
3602 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3603 @param Timeout The time to complete the command.
3604 @param DataBuffer The buffer to fill with the read out data.
3605 @param DataLength The length of buffer.
3606 @param StartLba The start logic block address.
3607 @param SectorCount The number of blocks to read.
3608 @param BlkIo2Req The upstream BlockIo2 request.
3609 @param Token The pointer to the token associated with the
3610 non-blocking read request.
3612 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3614 @return others Status returned by calling
3615 ScsiRead10CommandEx().
3619 ScsiDiskAsyncRead10 (
3620 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3622 OUT UINT8
*DataBuffer
,
3623 IN UINT32 DataLength
,
3625 IN UINT32 SectorCount
,
3626 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3627 IN EFI_BLOCK_IO2_TOKEN
*Token
3631 SCSI_ASYNC_RW_REQUEST
*Request
;
3632 EFI_EVENT AsyncIoEvent
;
3634 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3635 if (Request
== NULL
) {
3636 return EFI_OUT_OF_RESOURCES
;
3638 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3640 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3641 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3642 if (Request
->SenseData
== NULL
) {
3643 Status
= EFI_OUT_OF_RESOURCES
;
3647 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3648 Request
->Timeout
= Timeout
;
3649 Request
->InBuffer
= DataBuffer
;
3650 Request
->DataLength
= DataLength
;
3651 Request
->StartLba
= StartLba
;
3652 Request
->SectorCount
= SectorCount
;
3653 Request
->BlkIo2Req
= BlkIo2Req
;
3658 Status
= gBS
->CreateEvent (
3665 if (EFI_ERROR(Status
)) {
3669 Status
= ScsiRead10CommandEx (
3670 ScsiDiskDevice
->ScsiIo
,
3673 &Request
->SenseDataLength
,
3674 &Request
->HostAdapterStatus
,
3675 &Request
->TargetStatus
,
3677 &Request
->DataLength
,
3678 (UINT32
) Request
->StartLba
,
3679 Request
->SectorCount
,
3682 if (EFI_ERROR(Status
)) {
3689 if (Request
!= NULL
) {
3690 if (Request
->SenseData
!= NULL
) {
3691 FreePool (Request
->SenseData
);
3694 RemoveEntryList (&Request
->Link
);
3703 Submit Async Write(10) command.
3705 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3706 @param Timeout The time to complete the command.
3707 @param DataBuffer The buffer contains the data to write.
3708 @param DataLength The length of buffer.
3709 @param StartLba The start logic block address.
3710 @param SectorCount The number of blocks to write.
3711 @param BlkIo2Req The upstream BlockIo2 request.
3712 @param Token The pointer to the token associated with the
3713 non-blocking read request.
3715 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3717 @return others Status returned by calling
3718 ScsiWrite10CommandEx().
3722 ScsiDiskAsyncWrite10 (
3723 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3725 IN UINT8
*DataBuffer
,
3726 IN UINT32 DataLength
,
3728 IN UINT32 SectorCount
,
3729 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3730 IN EFI_BLOCK_IO2_TOKEN
*Token
3734 SCSI_ASYNC_RW_REQUEST
*Request
;
3735 EFI_EVENT AsyncIoEvent
;
3737 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3738 if (Request
== NULL
) {
3739 return EFI_OUT_OF_RESOURCES
;
3741 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3743 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3744 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3745 if (Request
->SenseData
== NULL
) {
3746 Status
= EFI_OUT_OF_RESOURCES
;
3750 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3751 Request
->Timeout
= Timeout
;
3752 Request
->OutBuffer
= DataBuffer
;
3753 Request
->DataLength
= DataLength
;
3754 Request
->StartLba
= StartLba
;
3755 Request
->SectorCount
= SectorCount
;
3756 Request
->BlkIo2Req
= BlkIo2Req
;
3761 Status
= gBS
->CreateEvent (
3768 if (EFI_ERROR(Status
)) {
3772 Status
= ScsiWrite10CommandEx (
3773 ScsiDiskDevice
->ScsiIo
,
3776 &Request
->SenseDataLength
,
3777 &Request
->HostAdapterStatus
,
3778 &Request
->TargetStatus
,
3780 &Request
->DataLength
,
3781 (UINT32
) Request
->StartLba
,
3782 Request
->SectorCount
,
3785 if (EFI_ERROR(Status
)) {
3792 if (Request
!= NULL
) {
3793 if (Request
->SenseData
!= NULL
) {
3794 FreePool (Request
->SenseData
);
3797 RemoveEntryList (&Request
->Link
);
3806 Submit Async Read(16) command.
3808 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3809 @param Timeout The time to complete the command.
3810 @param DataBuffer The buffer to fill with the read out data.
3811 @param DataLength The length of buffer.
3812 @param StartLba The start logic block address.
3813 @param SectorCount The number of blocks to read.
3814 @param BlkIo2Req The upstream BlockIo2 request.
3815 @param Token The pointer to the token associated with the
3816 non-blocking read request.
3818 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3820 @return others Status returned by calling
3821 ScsiRead16CommandEx().
3825 ScsiDiskAsyncRead16 (
3826 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3828 OUT UINT8
*DataBuffer
,
3829 IN UINT32 DataLength
,
3831 IN UINT32 SectorCount
,
3832 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3833 IN EFI_BLOCK_IO2_TOKEN
*Token
3837 SCSI_ASYNC_RW_REQUEST
*Request
;
3838 EFI_EVENT AsyncIoEvent
;
3840 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3841 if (Request
== NULL
) {
3842 return EFI_OUT_OF_RESOURCES
;
3844 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3846 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3847 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3848 if (Request
->SenseData
== NULL
) {
3849 Status
= EFI_OUT_OF_RESOURCES
;
3853 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3854 Request
->Timeout
= Timeout
;
3855 Request
->InBuffer
= DataBuffer
;
3856 Request
->DataLength
= DataLength
;
3857 Request
->StartLba
= StartLba
;
3858 Request
->SectorCount
= SectorCount
;
3859 Request
->BlkIo2Req
= BlkIo2Req
;
3864 Status
= gBS
->CreateEvent (
3871 if (EFI_ERROR(Status
)) {
3875 Status
= ScsiRead16CommandEx (
3876 ScsiDiskDevice
->ScsiIo
,
3879 &Request
->SenseDataLength
,
3880 &Request
->HostAdapterStatus
,
3881 &Request
->TargetStatus
,
3883 &Request
->DataLength
,
3885 Request
->SectorCount
,
3888 if (EFI_ERROR(Status
)) {
3895 if (Request
!= NULL
) {
3896 if (Request
->SenseData
!= NULL
) {
3897 FreePool (Request
->SenseData
);
3900 RemoveEntryList (&Request
->Link
);
3909 Submit Async Write(16) command.
3911 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3912 @param Timeout The time to complete the command.
3913 @param DataBuffer The buffer contains the data to write.
3914 @param DataLength The length of buffer.
3915 @param StartLba The start logic block address.
3916 @param SectorCount The number of blocks to write.
3917 @param BlkIo2Req The upstream BlockIo2 request.
3918 @param Token The pointer to the token associated with the
3919 non-blocking read request.
3921 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3923 @return others Status returned by calling
3924 ScsiWrite16CommandEx().
3928 ScsiDiskAsyncWrite16 (
3929 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3931 IN UINT8
*DataBuffer
,
3932 IN UINT32 DataLength
,
3934 IN UINT32 SectorCount
,
3935 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3936 IN EFI_BLOCK_IO2_TOKEN
*Token
3940 SCSI_ASYNC_RW_REQUEST
*Request
;
3941 EFI_EVENT AsyncIoEvent
;
3943 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3944 if (Request
== NULL
) {
3945 return EFI_OUT_OF_RESOURCES
;
3947 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3949 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3950 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3951 if (Request
->SenseData
== NULL
) {
3952 Status
= EFI_OUT_OF_RESOURCES
;
3956 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3957 Request
->Timeout
= Timeout
;
3958 Request
->OutBuffer
= DataBuffer
;
3959 Request
->DataLength
= DataLength
;
3960 Request
->StartLba
= StartLba
;
3961 Request
->SectorCount
= SectorCount
;
3962 Request
->BlkIo2Req
= BlkIo2Req
;
3967 Status
= gBS
->CreateEvent (
3974 if (EFI_ERROR(Status
)) {
3978 Status
= ScsiWrite16CommandEx (
3979 ScsiDiskDevice
->ScsiIo
,
3982 &Request
->SenseDataLength
,
3983 &Request
->HostAdapterStatus
,
3984 &Request
->TargetStatus
,
3986 &Request
->DataLength
,
3988 Request
->SectorCount
,
3991 if (EFI_ERROR(Status
)) {
3998 if (Request
!= NULL
) {
3999 if (Request
->SenseData
!= NULL
) {
4000 FreePool (Request
->SenseData
);
4003 RemoveEntryList (&Request
->Link
);
4012 Check sense key to find if media presents.
4014 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4015 @param SenseCounts The number of sense key
4017 @retval TRUE NOT any media
4018 @retval FALSE Media presents
4022 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4023 IN UINTN SenseCounts
4026 EFI_SCSI_SENSE_DATA
*SensePtr
;
4031 SensePtr
= SenseData
;
4033 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4035 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
4036 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
4038 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
4039 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
4052 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4053 @param SenseCounts The number of sense key
4056 @retval FALSE NOT error
4060 ScsiDiskIsMediaError (
4061 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4062 IN UINTN SenseCounts
4065 EFI_SCSI_SENSE_DATA
*SensePtr
;
4070 SensePtr
= SenseData
;
4072 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4074 switch (SensePtr
->Sense_Key
) {
4076 case EFI_SCSI_SK_MEDIUM_ERROR
:
4078 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
4080 switch (SensePtr
->Addnl_Sense_Code
) {
4085 case EFI_SCSI_ASC_MEDIA_ERR1
:
4090 case EFI_SCSI_ASC_MEDIA_ERR2
:
4095 case EFI_SCSI_ASC_MEDIA_ERR3
:
4096 case EFI_SCSI_ASC_MEDIA_ERR4
:
4106 case EFI_SCSI_SK_NOT_READY
:
4108 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4110 switch (SensePtr
->Addnl_Sense_Code
) {
4112 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
4114 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
4135 Check sense key to find if hardware error happens.
4137 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4138 @param SenseCounts The number of sense key
4140 @retval TRUE Hardware error exits.
4141 @retval FALSE NO error.
4145 ScsiDiskIsHardwareError (
4146 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4147 IN UINTN SenseCounts
4150 EFI_SCSI_SENSE_DATA
*SensePtr
;
4155 SensePtr
= SenseData
;
4157 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4160 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
4162 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
4174 Check sense key to find if media has changed.
4176 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4177 @param SenseCounts The number of sense key
4179 @retval TRUE Media is changed.
4180 @retval FALSE Media is NOT changed.
4183 ScsiDiskIsMediaChange (
4184 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4185 IN UINTN SenseCounts
4188 EFI_SCSI_SENSE_DATA
*SensePtr
;
4190 BOOLEAN IsMediaChanged
;
4192 IsMediaChanged
= FALSE
;
4193 SensePtr
= SenseData
;
4195 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4197 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
4198 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
4200 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
4201 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
4202 IsMediaChanged
= TRUE
;
4208 return IsMediaChanged
;
4212 Check sense key to find if reset happens.
4214 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4215 @param SenseCounts The number of sense key
4217 @retval TRUE It is reset before.
4218 @retval FALSE It is NOT reset before.
4222 ScsiDiskIsResetBefore (
4223 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4224 IN UINTN SenseCounts
4227 EFI_SCSI_SENSE_DATA
*SensePtr
;
4229 BOOLEAN IsResetBefore
;
4231 IsResetBefore
= FALSE
;
4232 SensePtr
= SenseData
;
4234 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4237 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
4238 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
4240 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
4241 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
4242 IsResetBefore
= TRUE
;
4248 return IsResetBefore
;
4252 Check sense key to find if the drive is ready.
4254 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4255 @param SenseCounts The number of sense key
4256 @param RetryLater The flag means if need a retry
4258 @retval TRUE Drive is ready.
4259 @retval FALSE Drive is NOT ready.
4263 ScsiDiskIsDriveReady (
4264 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4265 IN UINTN SenseCounts
,
4266 OUT BOOLEAN
*RetryLater
4269 EFI_SCSI_SENSE_DATA
*SensePtr
;
4274 *RetryLater
= FALSE
;
4275 SensePtr
= SenseData
;
4277 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4279 switch (SensePtr
->Sense_Key
) {
4281 case EFI_SCSI_SK_NOT_READY
:
4283 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4285 switch (SensePtr
->Addnl_Sense_Code
) {
4286 case EFI_SCSI_ASC_NOT_READY
:
4288 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
4290 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
4291 case EFI_SCSI_ASCQ_IN_PROGRESS
:
4293 // Additional Sense Code Qualifier is
4294 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
4302 *RetryLater
= FALSE
;
4323 Check sense key to find if it has sense key.
4325 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
4326 @param SenseCounts - The number of sense key
4328 @retval TRUE It has sense key.
4329 @retval FALSE It has NOT any sense key.
4333 ScsiDiskHaveSenseKey (
4334 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4335 IN UINTN SenseCounts
4338 EFI_SCSI_SENSE_DATA
*SensePtr
;
4340 BOOLEAN HaveSenseKey
;
4342 if (SenseCounts
== 0) {
4343 HaveSenseKey
= FALSE
;
4345 HaveSenseKey
= TRUE
;
4348 SensePtr
= SenseData
;
4350 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4353 // Sense Key is SK_NO_SENSE (0x0)
4355 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
4357 HaveSenseKey
= FALSE
;
4363 return HaveSenseKey
;
4367 Release resource about disk device.
4369 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4373 ReleaseScsiDiskDeviceResources (
4374 IN SCSI_DISK_DEV
*ScsiDiskDevice
4377 if (ScsiDiskDevice
== NULL
) {
4381 if (ScsiDiskDevice
->SenseData
!= NULL
) {
4382 FreePool (ScsiDiskDevice
->SenseData
);
4383 ScsiDiskDevice
->SenseData
= NULL
;
4386 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
4387 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
4388 ScsiDiskDevice
->ControllerNameTable
= NULL
;
4391 FreePool (ScsiDiskDevice
);
4393 ScsiDiskDevice
= NULL
;
4397 Determine if Block Io & Block Io2 should be produced.
4400 @param ChildHandle Child Handle to retrieve Parent information.
4402 @retval TRUE Should produce Block Io & Block Io2.
4403 @retval FALSE Should not produce Block Io & Block Io2.
4407 DetermineInstallBlockIo (
4408 IN EFI_HANDLE ChildHandle
4411 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
4412 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
4415 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
4416 // check its attribute, logic or physical.
4418 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
4419 if (ExtScsiPassThru
!= NULL
) {
4420 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
4426 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
4427 // check its attribute, logic or physical.
4429 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
4430 if (ScsiPassThru
!= NULL
) {
4431 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
4440 Search protocol database and check to see if the protocol
4441 specified by ProtocolGuid is present on a ControllerHandle and opened by
4442 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
4443 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
4444 will be opened on it.
4447 @param ProtocolGuid ProtocolGuid pointer.
4448 @param ChildHandle Child Handle to retrieve Parent information.
4454 IN EFI_GUID
*ProtocolGuid
,
4455 IN EFI_HANDLE ChildHandle
4462 EFI_HANDLE
*HandleBuffer
;
4465 // Retrieve the list of all handles from the handle database
4467 Status
= gBS
->LocateHandleBuffer (
4475 if (EFI_ERROR (Status
)) {
4480 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
4482 for (Index
= 0; Index
< HandleCount
; Index
++) {
4483 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
4484 if (!EFI_ERROR (Status
)) {
4485 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
4486 if (!EFI_ERROR (Status
)) {
4487 gBS
->FreePool (HandleBuffer
);
4493 gBS
->FreePool (HandleBuffer
);
4498 Provides inquiry information for the controller type.
4500 This function is used by the IDE bus driver to get inquiry data. Data format
4501 of Identify data is defined by the Interface GUID.
4503 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4504 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
4505 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
4507 @retval EFI_SUCCESS The command was accepted without any errors.
4508 @retval EFI_NOT_FOUND Device does not support this data class
4509 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
4510 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
4515 ScsiDiskInfoInquiry (
4516 IN EFI_DISK_INFO_PROTOCOL
*This
,
4517 IN OUT VOID
*InquiryData
,
4518 IN OUT UINT32
*InquiryDataSize
4522 SCSI_DISK_DEV
*ScsiDiskDevice
;
4524 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4526 Status
= EFI_BUFFER_TOO_SMALL
;
4527 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
4528 Status
= EFI_SUCCESS
;
4529 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
4531 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
4537 Provides identify information for the controller type.
4539 This function is used by the IDE bus driver to get identify data. Data format
4540 of Identify data is defined by the Interface GUID.
4542 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
4544 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
4545 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
4548 @retval EFI_SUCCESS The command was accepted without any errors.
4549 @retval EFI_NOT_FOUND Device does not support this data class
4550 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
4551 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
4556 ScsiDiskInfoIdentify (
4557 IN EFI_DISK_INFO_PROTOCOL
*This
,
4558 IN OUT VOID
*IdentifyData
,
4559 IN OUT UINT32
*IdentifyDataSize
4563 SCSI_DISK_DEV
*ScsiDiskDevice
;
4565 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
4567 // Physical SCSI bus does not support this data class.
4569 return EFI_NOT_FOUND
;
4572 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4574 Status
= EFI_BUFFER_TOO_SMALL
;
4575 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
4576 Status
= EFI_SUCCESS
;
4577 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
4579 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
4584 Provides sense data information for the controller type.
4586 This function is used by the IDE bus driver to get sense data.
4587 Data format of Sense data is defined by the Interface GUID.
4589 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4590 @param[in, out] SenseData Pointer to the SenseData.
4591 @param[in, out] SenseDataSize Size of SenseData in bytes.
4592 @param[out] SenseDataNumber Pointer to the value for the sense data size.
4594 @retval EFI_SUCCESS The command was accepted without any errors.
4595 @retval EFI_NOT_FOUND Device does not support this data class.
4596 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
4597 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
4602 ScsiDiskInfoSenseData (
4603 IN EFI_DISK_INFO_PROTOCOL
*This
,
4604 IN OUT VOID
*SenseData
,
4605 IN OUT UINT32
*SenseDataSize
,
4606 OUT UINT8
*SenseDataNumber
4609 return EFI_NOT_FOUND
;
4614 This function is used by the IDE bus driver to get controller information.
4616 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4617 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
4618 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
4620 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
4621 @retval EFI_UNSUPPORTED This is not an IDE device.
4626 ScsiDiskInfoWhichIde (
4627 IN EFI_DISK_INFO_PROTOCOL
*This
,
4628 OUT UINT32
*IdeChannel
,
4629 OUT UINT32
*IdeDevice
4632 SCSI_DISK_DEV
*ScsiDiskDevice
;
4634 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
4636 // This is not an IDE physical device.
4638 return EFI_UNSUPPORTED
;
4641 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4642 *IdeChannel
= ScsiDiskDevice
->Channel
;
4643 *IdeDevice
= ScsiDiskDevice
->Device
;
4650 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
4652 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
4653 implement Identify() interface for DiskInfo protocol. The ATA command is sent
4654 via SCSI Request Packet.
4656 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4658 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
4659 @retval others Some error occurred during the identification that ATAPI device.
4663 AtapiIdentifyDevice (
4664 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
4667 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
4671 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
4673 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
4674 ZeroMem (Cdb
, sizeof (Cdb
));
4676 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
4677 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
4678 CommandPacket
.Cdb
= Cdb
;
4679 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
4680 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
4681 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
4683 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
4688 Initialize the installation of DiskInfo protocol.
4690 This function prepares for the installation of DiskInfo protocol on the child handle.
4691 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
4692 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
4693 to be IDE/AHCI interface GUID.
4695 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
4696 @param ChildHandle Child handle to install DiskInfo protocol.
4700 InitializeInstallDiskInfo (
4701 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4702 IN EFI_HANDLE ChildHandle
4706 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
4707 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
4708 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
4709 SATA_DEVICE_PATH
*SataDevicePath
;
4710 UINTN IdentifyRetry
;
4712 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
4714 // Device Path protocol must be installed on the device handle.
4716 ASSERT_EFI_ERROR (Status
);
4718 // Copy the DiskInfo protocol template.
4720 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
4722 while (!IsDevicePathEnd (DevicePathNode
)) {
4723 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
4724 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
4725 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
4726 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
4727 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
4728 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
4733 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
4734 // with IDE/AHCI interface GUID.
4736 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
4737 if (!EFI_ERROR (Status
)) {
4738 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
4740 // We find the valid ATAPI device path
4742 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
4743 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
4744 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
4746 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
4748 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
4751 // We find the valid SATA device path
4753 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
4754 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
4755 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
4757 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
4759 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
4763 } while (--IdentifyRetry
> 0);
4764 } else if ((DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
4765 (DevicePathSubType (ChildDevicePathNode
) == MSG_UFS_DP
)) {
4766 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoUfsInterfaceGuid
);
4769 DevicePathNode
= ChildDevicePathNode
;