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 attempting to
1122 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1123 @retval EFI_NO_MEDIA There is no media in the device.
1124 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1129 ScsiDiskFlushBlocksEx (
1130 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1131 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1134 SCSI_DISK_DEV
*ScsiDiskDevice
;
1135 EFI_BLOCK_IO_MEDIA
*Media
;
1137 BOOLEAN MediaChange
;
1140 MediaChange
= FALSE
;
1141 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1142 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1144 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1146 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1147 if (EFI_ERROR (Status
)) {
1148 Status
= EFI_DEVICE_ERROR
;
1153 gBS
->ReinstallProtocolInterface (
1154 ScsiDiskDevice
->Handle
,
1155 &gEfiBlockIoProtocolGuid
,
1156 &ScsiDiskDevice
->BlkIo
,
1157 &ScsiDiskDevice
->BlkIo
1159 gBS
->ReinstallProtocolInterface (
1160 ScsiDiskDevice
->Handle
,
1161 &gEfiBlockIo2ProtocolGuid
,
1162 &ScsiDiskDevice
->BlkIo2
,
1163 &ScsiDiskDevice
->BlkIo2
1165 Status
= EFI_MEDIA_CHANGED
;
1170 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
1172 if (!(Media
->MediaPresent
)) {
1173 Status
= EFI_NO_MEDIA
;
1177 if (Media
->ReadOnly
) {
1178 Status
= EFI_WRITE_PROTECTED
;
1183 // Wait for the BlockIo2 requests queue to become empty
1185 while (!IsListEmpty (&ScsiDiskDevice
->BlkIo2Queue
));
1187 Status
= EFI_SUCCESS
;
1190 // Signal caller event
1192 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1193 Token
->TransactionStatus
= EFI_SUCCESS
;
1194 gBS
->SignalEvent (Token
->Event
);
1198 gBS
->RestoreTPL (OldTpl
);
1204 Detect Device and read out capacity ,if error occurs, parse the sense key.
1206 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1207 @param MustReadCapacity The flag about reading device capacity
1208 @param MediaChange The pointer of flag indicates if media has changed
1210 @retval EFI_DEVICE_ERROR Indicates that error occurs
1211 @retval EFI_SUCCESS Successfully to detect media
1215 ScsiDiskDetectMedia (
1216 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1217 IN BOOLEAN MustReadCapacity
,
1218 OUT BOOLEAN
*MediaChange
1222 EFI_SCSI_SENSE_DATA
*SenseData
;
1223 UINTN NumberOfSenseKeys
;
1225 BOOLEAN NeedReadCapacity
;
1228 EFI_BLOCK_IO_MEDIA OldMedia
;
1230 EFI_EVENT TimeoutEvt
;
1232 Status
= EFI_SUCCESS
;
1234 NumberOfSenseKeys
= 0;
1237 Action
= ACTION_NO_ACTION
;
1238 NeedReadCapacity
= FALSE
;
1239 *MediaChange
= FALSE
;
1242 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
1244 Status
= gBS
->CreateEvent (
1251 if (EFI_ERROR (Status
)) {
1255 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
1256 if (EFI_ERROR (Status
)) {
1261 // Sending Test_Unit cmd to poll device status.
1262 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
1263 // We limit the upper boundary to 120 seconds.
1265 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
1266 Status
= ScsiDiskTestUnitReady (
1272 if (!EFI_ERROR (Status
)) {
1273 Status
= DetectMediaParsingSenseKeys (
1279 if (EFI_ERROR (Status
)) {
1281 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1288 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1294 if (EFI_ERROR (Status
)) {
1299 // ACTION_NO_ACTION: need not read capacity
1300 // other action code: need read capacity
1302 if (Action
== ACTION_READ_CAPACITY
) {
1303 NeedReadCapacity
= TRUE
;
1307 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
1308 // retrieve capacity via Read Capacity command
1310 if (NeedReadCapacity
|| MustReadCapacity
) {
1312 // retrieve media information
1314 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
1315 Status
= ScsiDiskReadCapacity (
1321 if (!EFI_ERROR (Status
)) {
1323 // analyze sense key to action
1325 Status
= DetectMediaParsingSenseKeys (
1331 if (EFI_ERROR (Status
)) {
1333 // if Status is error, it may indicate crisis error,
1334 // so return without retry.
1337 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1345 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1351 if (EFI_ERROR (Status
)) {
1356 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
1358 // Media change information got from the device
1360 *MediaChange
= TRUE
;
1363 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
1364 *MediaChange
= TRUE
;
1365 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1368 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
1369 *MediaChange
= TRUE
;
1370 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1373 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
1374 *MediaChange
= TRUE
;
1375 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1378 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
1379 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
1381 // when change from no media to media present, reset the MediaId to 1.
1383 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
1386 // when no media, reset the MediaId to zero.
1388 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
1391 *MediaChange
= TRUE
;
1395 if (TimeoutEvt
!= NULL
) {
1396 gBS
->CloseEvent (TimeoutEvt
);
1403 Send out Inquiry command to Device.
1405 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1406 @param NeedRetry Indicates if needs try again when error happens
1408 @retval EFI_DEVICE_ERROR Indicates that error occurs
1409 @retval EFI_SUCCESS Successfully to detect media
1413 ScsiDiskInquiryDevice (
1414 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1415 OUT BOOLEAN
*NeedRetry
1418 UINT32 InquiryDataLength
;
1419 UINT8 SenseDataLength
;
1420 UINT8 HostAdapterStatus
;
1422 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
1423 UINTN NumberOfSenseKeys
;
1427 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
1428 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
1431 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1432 SenseDataLength
= 0;
1434 Status
= ScsiInquiryCommand (
1435 ScsiDiskDevice
->ScsiIo
,
1441 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
1446 // no need to check HostAdapterStatus and TargetStatus
1448 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1449 ParseInquiryData (ScsiDiskDevice
);
1451 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1453 // Check whether the device supports Block Limits VPD page (0xB0)
1455 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1456 if (SupportedVpdPages
== NULL
) {
1458 return EFI_DEVICE_ERROR
;
1460 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1461 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
1462 SenseDataLength
= 0;
1463 Status
= ScsiInquiryCommandEx (
1464 ScsiDiskDevice
->ScsiIo
,
1470 (VOID
*) SupportedVpdPages
,
1473 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
1475 if (!EFI_ERROR (Status
)) {
1476 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
1477 | SupportedVpdPages
->PageLength1
;
1478 for (Index
= 0; Index
< PageLength
; Index
++) {
1479 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
1485 // Query the Block Limits VPD page
1487 if (Index
< PageLength
) {
1488 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1489 if (BlockLimits
== NULL
) {
1490 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1492 return EFI_DEVICE_ERROR
;
1494 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1495 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
1496 SenseDataLength
= 0;
1497 Status
= ScsiInquiryCommandEx (
1498 ScsiDiskDevice
->ScsiIo
,
1504 (VOID
*) BlockLimits
,
1507 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
1509 if (!EFI_ERROR (Status
)) {
1510 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
1511 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
1512 BlockLimits
->OptimalTransferLengthGranularity1
;
1515 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1519 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1523 if (!EFI_ERROR (Status
)) {
1526 } else if (Status
== EFI_NOT_READY
) {
1528 return EFI_DEVICE_ERROR
;
1530 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1532 return EFI_DEVICE_ERROR
;
1535 // go ahead to check HostAdapterStatus and TargetStatus
1536 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1539 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1540 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1542 return EFI_DEVICE_ERROR
;
1543 } else if (Status
== EFI_DEVICE_ERROR
) {
1545 // reset the scsi channel
1547 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1549 return EFI_DEVICE_ERROR
;
1552 Status
= CheckTargetStatus (TargetStatus
);
1553 if (Status
== EFI_NOT_READY
) {
1555 // reset the scsi device
1557 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1559 return EFI_DEVICE_ERROR
;
1561 } else if (Status
== EFI_DEVICE_ERROR
) {
1563 return EFI_DEVICE_ERROR
;
1567 // if goes here, meant ScsiInquiryCommand() failed.
1568 // if ScsiDiskRequestSenseKeys() succeeds at last,
1569 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1572 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1573 Status
= ScsiDiskRequestSenseKeys (
1580 if (!EFI_ERROR (Status
)) {
1582 return EFI_DEVICE_ERROR
;
1586 return EFI_DEVICE_ERROR
;
1590 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1591 // set *NeedRetry = FALSE to avoid the outside caller try again.
1594 return EFI_DEVICE_ERROR
;
1600 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1601 When Test Unit Ready command encounters any error caused by host adapter or
1602 target, return error without retrieving Sense Keys.
1604 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1605 @param NeedRetry The pointer of flag indicates try again
1606 @param SenseDataArray The pointer of an array of sense data
1607 @param NumberOfSenseKeys The pointer of the number of sense data array
1609 @retval EFI_DEVICE_ERROR Indicates that error occurs
1610 @retval EFI_SUCCESS Successfully to test unit
1614 ScsiDiskTestUnitReady (
1615 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1616 OUT BOOLEAN
*NeedRetry
,
1617 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1618 OUT UINTN
*NumberOfSenseKeys
1622 UINT8 SenseDataLength
;
1623 UINT8 HostAdapterStatus
;
1628 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
1629 *NumberOfSenseKeys
= 0;
1632 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1634 Status
= ScsiTestUnitReadyCommand (
1635 ScsiDiskDevice
->ScsiIo
,
1637 ScsiDiskDevice
->SenseData
,
1643 // no need to check HostAdapterStatus and TargetStatus
1645 if (Status
== EFI_NOT_READY
) {
1647 return EFI_DEVICE_ERROR
;
1649 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1651 return EFI_DEVICE_ERROR
;
1654 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1657 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1658 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1660 return EFI_DEVICE_ERROR
;
1662 } else if (Status
== EFI_DEVICE_ERROR
) {
1664 // reset the scsi channel
1666 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1668 return EFI_DEVICE_ERROR
;
1671 Status
= CheckTargetStatus (TargetStatus
);
1672 if (Status
== EFI_NOT_READY
) {
1674 // reset the scsi device
1676 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1678 return EFI_DEVICE_ERROR
;
1680 } else if (Status
== EFI_DEVICE_ERROR
) {
1682 return EFI_DEVICE_ERROR
;
1685 if (SenseDataLength
!= 0) {
1686 *NumberOfSenseKeys
= SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
);
1687 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1692 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1693 Status
= ScsiDiskRequestSenseKeys (
1700 if (!EFI_ERROR (Status
)) {
1705 return EFI_DEVICE_ERROR
;
1709 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1710 // set *NeedRetry = FALSE to avoid the outside caller try again.
1713 return EFI_DEVICE_ERROR
;
1717 Parsing Sense Keys which got from request sense command.
1719 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1720 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1721 @param NumberOfSenseKeys The number of sense key
1722 @param Action The pointer of action which indicates what is need to do next
1724 @retval EFI_DEVICE_ERROR Indicates that error occurs
1725 @retval EFI_SUCCESS Successfully to complete the parsing
1729 DetectMediaParsingSenseKeys (
1730 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1731 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1732 IN UINTN NumberOfSenseKeys
,
1739 // Default is to read capacity, unless..
1741 *Action
= ACTION_READ_CAPACITY
;
1743 if (NumberOfSenseKeys
== 0) {
1744 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1745 *Action
= ACTION_NO_ACTION
;
1750 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1752 // No Sense Key returned from last submitted command
1754 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1755 *Action
= ACTION_NO_ACTION
;
1760 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1761 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1762 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1763 *Action
= ACTION_NO_ACTION
;
1764 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
1768 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1769 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1770 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
1774 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
1775 *Action
= ACTION_RETRY_COMMAND_LATER
;
1776 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
1780 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1781 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
1782 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1783 return EFI_DEVICE_ERROR
;
1786 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1787 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
1788 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1789 return EFI_DEVICE_ERROR
;
1792 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1794 *Action
= ACTION_RETRY_COMMAND_LATER
;
1795 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
1798 *Action
= ACTION_NO_ACTION
;
1799 return EFI_DEVICE_ERROR
;
1802 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1803 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
1809 Send read capacity command to device and get the device parameter.
1811 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1812 @param NeedRetry The pointer of flag indicates if need a retry
1813 @param SenseDataArray The pointer of an array of sense data
1814 @param NumberOfSenseKeys The number of sense key
1816 @retval EFI_DEVICE_ERROR Indicates that error occurs
1817 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1821 ScsiDiskReadCapacity (
1822 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1823 OUT BOOLEAN
*NeedRetry
,
1824 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1825 OUT UINTN
*NumberOfSenseKeys
1828 UINT8 HostAdapterStatus
;
1830 EFI_STATUS CommandStatus
;
1834 UINT8 SenseDataLength
;
1835 UINT32 DataLength10
;
1836 UINT32 DataLength16
;
1837 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
1838 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
1840 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1841 if (CapacityData10
== NULL
) {
1843 return EFI_DEVICE_ERROR
;
1845 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1846 if (CapacityData16
== NULL
) {
1847 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1849 return EFI_DEVICE_ERROR
;
1852 SenseDataLength
= 0;
1853 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1854 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1855 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1856 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1858 *NumberOfSenseKeys
= 0;
1862 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1863 // 16 byte command should be used to access large hard disk >2TB
1865 CommandStatus
= ScsiReadCapacityCommand (
1866 ScsiDiskDevice
->ScsiIo
,
1872 (VOID
*) CapacityData10
,
1877 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1878 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
1879 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff)) {
1881 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1883 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1885 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1886 // and LowestAlignedLba
1888 CommandStatus
= ScsiReadCapacity16Command (
1889 ScsiDiskDevice
->ScsiIo
,
1895 (VOID
*) CapacityData16
,
1902 // no need to check HostAdapterStatus and TargetStatus
1904 if (CommandStatus
== EFI_SUCCESS
) {
1905 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
1906 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1907 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1911 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1912 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1914 if (CommandStatus
== EFI_NOT_READY
) {
1916 return EFI_DEVICE_ERROR
;
1917 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1919 return EFI_DEVICE_ERROR
;
1923 // go ahead to check HostAdapterStatus and TargetStatus
1924 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1927 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1928 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1930 return EFI_DEVICE_ERROR
;
1932 } else if (Status
== EFI_DEVICE_ERROR
) {
1934 // reset the scsi channel
1936 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1938 return EFI_DEVICE_ERROR
;
1941 Status
= CheckTargetStatus (TargetStatus
);
1942 if (Status
== EFI_NOT_READY
) {
1944 // reset the scsi device
1946 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1948 return EFI_DEVICE_ERROR
;
1950 } else if (Status
== EFI_DEVICE_ERROR
) {
1952 return EFI_DEVICE_ERROR
;
1956 // if goes here, meant ScsiReadCapacityCommand() failed.
1957 // if ScsiDiskRequestSenseKeys() succeeds at last,
1958 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1961 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1963 Status
= ScsiDiskRequestSenseKeys (
1970 if (!EFI_ERROR (Status
)) {
1975 return EFI_DEVICE_ERROR
;
1979 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1980 // set *NeedRetry = FALSE to avoid the outside caller try again.
1983 return EFI_DEVICE_ERROR
;
1987 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1989 @param HostAdapterStatus Host Adapter status
1991 @retval EFI_SUCCESS Host adapter is OK.
1992 @retval EFI_TIMEOUT Timeout.
1993 @retval EFI_NOT_READY Adapter NOT ready.
1994 @retval EFI_DEVICE_ERROR Adapter device error.
1998 CheckHostAdapterStatus (
1999 IN UINT8 HostAdapterStatus
2002 switch (HostAdapterStatus
) {
2003 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
2006 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
2007 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
2008 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
2011 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
2012 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
2013 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
2014 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
2015 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
2016 return EFI_NOT_READY
;
2018 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
2019 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
2020 return EFI_DEVICE_ERROR
;
2029 Check the target status and re-interpret it in EFI_STATUS.
2031 @param TargetStatus Target status
2033 @retval EFI_NOT_READY Device is NOT ready.
2034 @retval EFI_DEVICE_ERROR
2040 IN UINT8 TargetStatus
2043 switch (TargetStatus
) {
2044 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
2045 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
2046 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
2049 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
2050 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
2051 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
2052 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
2053 return EFI_NOT_READY
;
2055 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
2056 return EFI_DEVICE_ERROR
;
2065 Retrieve all sense keys from the device.
2067 When encountering error during the process, if retrieve sense keys before
2068 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
2069 and NeedRetry set to FALSE; otherwize, return the proper return status.
2071 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2072 @param NeedRetry The pointer of flag indicates if need a retry
2073 @param SenseDataArray The pointer of an array of sense data
2074 @param NumberOfSenseKeys The number of sense key
2075 @param AskResetIfError The flag indicates if need reset when error occurs
2077 @retval EFI_DEVICE_ERROR Indicates that error occurs
2078 @retval EFI_SUCCESS Successfully to request sense key
2082 ScsiDiskRequestSenseKeys (
2083 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2084 OUT BOOLEAN
*NeedRetry
,
2085 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2086 OUT UINTN
*NumberOfSenseKeys
,
2087 IN BOOLEAN AskResetIfError
2090 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
2091 UINT8 SenseDataLength
;
2094 EFI_STATUS FallStatus
;
2095 UINT8 HostAdapterStatus
;
2098 FallStatus
= EFI_SUCCESS
;
2099 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
2102 ScsiDiskDevice
->SenseData
,
2103 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
2106 *NumberOfSenseKeys
= 0;
2107 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2108 Status
= EFI_SUCCESS
;
2109 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
2110 if (PtrSenseData
== NULL
) {
2111 return EFI_DEVICE_ERROR
;
2114 for (SenseReq
= TRUE
; SenseReq
;) {
2115 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2116 Status
= ScsiRequestSenseCommand (
2117 ScsiDiskDevice
->ScsiIo
,
2124 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
2125 FallStatus
= EFI_SUCCESS
;
2127 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2129 FallStatus
= EFI_DEVICE_ERROR
;
2131 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2133 FallStatus
= EFI_DEVICE_ERROR
;
2135 } else if (Status
== EFI_DEVICE_ERROR
) {
2136 if (AskResetIfError
) {
2137 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2140 FallStatus
= EFI_DEVICE_ERROR
;
2143 if (EFI_ERROR (FallStatus
)) {
2144 if (*NumberOfSenseKeys
!= 0) {
2146 Status
= EFI_SUCCESS
;
2149 Status
= EFI_DEVICE_ERROR
;
2154 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
2155 (*NumberOfSenseKeys
) += 1;
2158 // no more sense key or number of sense keys exceeds predefined,
2161 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
2162 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
2168 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2174 Get information from media read capacity command.
2176 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2177 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
2178 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
2183 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2184 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
2185 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
2190 if (!ScsiDiskDevice
->Cdb16Byte
) {
2191 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
2192 (Capacity10
->LastLba2
<< 16) |
2193 (Capacity10
->LastLba1
<< 8) |
2194 Capacity10
->LastLba0
;
2196 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
2197 (Capacity10
->BlockSize2
<< 16) |
2198 (Capacity10
->BlockSize1
<< 8) |
2199 Capacity10
->BlockSize0
;
2200 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
2201 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
2203 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2204 *Ptr
++ = Capacity16
->LastLba0
;
2205 *Ptr
++ = Capacity16
->LastLba1
;
2206 *Ptr
++ = Capacity16
->LastLba2
;
2207 *Ptr
++ = Capacity16
->LastLba3
;
2208 *Ptr
++ = Capacity16
->LastLba4
;
2209 *Ptr
++ = Capacity16
->LastLba5
;
2210 *Ptr
++ = Capacity16
->LastLba6
;
2211 *Ptr
= Capacity16
->LastLba7
;
2213 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
2214 (Capacity16
->BlockSize2
<< 16) |
2215 (Capacity16
->BlockSize1
<< 8) |
2216 Capacity16
->BlockSize0
;
2218 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
2219 Capacity16
->LowestAlignLogic1
;
2220 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
2223 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
2229 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2234 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2237 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
2238 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
2242 Read sector from SCSI Disk.
2244 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2245 @param Buffer The buffer to fill in the read out data
2246 @param Lba Logic block address
2247 @param NumberOfBlocks The number of blocks to read
2249 @retval EFI_DEVICE_ERROR Indicates a device error.
2250 @retval EFI_SUCCESS Operation is successful.
2254 ScsiDiskReadSectors (
2255 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2258 IN UINTN NumberOfBlocks
2261 UINTN BlocksRemaining
;
2267 UINT32 NextSectorCount
;
2274 Status
= EFI_SUCCESS
;
2276 BlocksRemaining
= NumberOfBlocks
;
2277 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2280 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2282 if (!ScsiDiskDevice
->Cdb16Byte
) {
2285 MaxBlock
= 0xFFFFFFFF;
2290 while (BlocksRemaining
> 0) {
2292 if (BlocksRemaining
<= MaxBlock
) {
2293 if (!ScsiDiskDevice
->Cdb16Byte
) {
2294 SectorCount
= (UINT16
) BlocksRemaining
;
2296 SectorCount
= (UINT32
) BlocksRemaining
;
2299 SectorCount
= MaxBlock
;
2302 ByteCount
= SectorCount
* BlockSize
;
2304 // |------------------------|-----------------|------------------|-----------------|
2305 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2306 // |------------------------|-----------------|------------------|-----------------|
2307 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2308 // |------------------------|-----------------|------------------|-----------------|
2309 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2310 // |------------------------|-----------------|------------------|-----------------|
2311 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2312 // |------------------------|-----------------|------------------|-----------------|
2313 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2314 // |------------------------|-----------------|------------------|-----------------|
2315 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2316 // |------------------------|-----------------|------------------|-----------------|
2317 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2318 // |------------------------|-----------------|------------------|-----------------|
2319 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2320 // |------------------------|-----------------|------------------|-----------------|
2321 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2322 // |------------------------|-----------------|------------------|-----------------|
2323 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2324 // |------------------------|-----------------|------------------|-----------------|
2325 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2326 // |------------------------|-----------------|------------------|-----------------|
2328 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2329 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2330 // From the above table, we could know 2.1Mbytes per second is lowest one.
2331 // The timout value is rounded up to nearest integar and here an additional 30s is added
2332 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2333 // commands in the Standby/Idle mode.
2335 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2338 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2339 if (!ScsiDiskDevice
->Cdb16Byte
) {
2340 Status
= ScsiDiskRead10 (
2350 Status
= ScsiDiskRead16 (
2360 if (!EFI_ERROR (Status
)) {
2365 return EFI_DEVICE_ERROR
;
2369 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
2370 // lowered ByteCount on output, we must make sure that we lower
2371 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2372 // it is invalid to request more sectors in the CDB than the entire
2373 // transfer (ie. ByteCount) can carry.
2375 // In addition, ByteCount is only expected to go down, or stay unchaged.
2376 // Therefore we don't need to update Timeout: the original timeout should
2377 // accommodate shorter transfers too.
2379 NextSectorCount
= ByteCount
/ BlockSize
;
2380 if (NextSectorCount
< SectorCount
) {
2381 SectorCount
= NextSectorCount
;
2383 // Account for any rounding down.
2385 ByteCount
= SectorCount
* BlockSize
;
2389 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2390 return EFI_DEVICE_ERROR
;
2394 // actual transferred sectors
2396 SectorCount
= ByteCount
/ BlockSize
;
2399 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2400 BlocksRemaining
-= SectorCount
;
2407 Write sector to SCSI Disk.
2409 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2410 @param Buffer The buffer of data to be written into SCSI Disk
2411 @param Lba Logic block address
2412 @param NumberOfBlocks The number of blocks to read
2414 @retval EFI_DEVICE_ERROR Indicates a device error.
2415 @retval EFI_SUCCESS Operation is successful.
2419 ScsiDiskWriteSectors (
2420 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2423 IN UINTN NumberOfBlocks
2426 UINTN BlocksRemaining
;
2432 UINT32 NextSectorCount
;
2439 Status
= EFI_SUCCESS
;
2441 BlocksRemaining
= NumberOfBlocks
;
2442 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2445 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2447 if (!ScsiDiskDevice
->Cdb16Byte
) {
2450 MaxBlock
= 0xFFFFFFFF;
2455 while (BlocksRemaining
> 0) {
2457 if (BlocksRemaining
<= MaxBlock
) {
2458 if (!ScsiDiskDevice
->Cdb16Byte
) {
2459 SectorCount
= (UINT16
) BlocksRemaining
;
2461 SectorCount
= (UINT32
) BlocksRemaining
;
2464 SectorCount
= MaxBlock
;
2467 ByteCount
= SectorCount
* BlockSize
;
2469 // |------------------------|-----------------|------------------|-----------------|
2470 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2471 // |------------------------|-----------------|------------------|-----------------|
2472 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2473 // |------------------------|-----------------|------------------|-----------------|
2474 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2475 // |------------------------|-----------------|------------------|-----------------|
2476 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2477 // |------------------------|-----------------|------------------|-----------------|
2478 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2479 // |------------------------|-----------------|------------------|-----------------|
2480 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2481 // |------------------------|-----------------|------------------|-----------------|
2482 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2483 // |------------------------|-----------------|------------------|-----------------|
2484 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2485 // |------------------------|-----------------|------------------|-----------------|
2486 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2487 // |------------------------|-----------------|------------------|-----------------|
2488 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2489 // |------------------------|-----------------|------------------|-----------------|
2490 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2491 // |------------------------|-----------------|------------------|-----------------|
2493 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2494 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2495 // From the above table, we could know 2.1Mbytes per second is lowest one.
2496 // The timout value is rounded up to nearest integar and here an additional 30s is added
2497 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2498 // commands in the Standby/Idle mode.
2500 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2502 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2503 if (!ScsiDiskDevice
->Cdb16Byte
) {
2504 Status
= ScsiDiskWrite10 (
2514 Status
= ScsiDiskWrite16 (
2524 if (!EFI_ERROR (Status
)) {
2529 return EFI_DEVICE_ERROR
;
2533 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
2534 // has lowered ByteCount on output, we must make sure that we lower
2535 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2536 // it is invalid to request more sectors in the CDB than the entire
2537 // transfer (ie. ByteCount) can carry.
2539 // In addition, ByteCount is only expected to go down, or stay unchaged.
2540 // Therefore we don't need to update Timeout: the original timeout should
2541 // accommodate shorter transfers too.
2543 NextSectorCount
= ByteCount
/ BlockSize
;
2544 if (NextSectorCount
< SectorCount
) {
2545 SectorCount
= NextSectorCount
;
2547 // Account for any rounding down.
2549 ByteCount
= SectorCount
* BlockSize
;
2553 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2554 return EFI_DEVICE_ERROR
;
2557 // actual transferred sectors
2559 SectorCount
= ByteCount
/ BlockSize
;
2562 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2563 BlocksRemaining
-= SectorCount
;
2570 Asynchronously read sector from SCSI Disk.
2572 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2573 @param Buffer The buffer to fill in the read out data.
2574 @param Lba Logic block address.
2575 @param NumberOfBlocks The number of blocks to read.
2576 @param Token A pointer to the token associated with the
2577 non-blocking read request.
2579 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
2580 @retval EFI_DEVICE_ERROR Indicates a device error.
2581 @retval EFI_SUCCESS Operation is successful.
2585 ScsiDiskAsyncReadSectors (
2586 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2589 IN UINTN NumberOfBlocks
,
2590 IN EFI_BLOCK_IO2_TOKEN
*Token
2593 UINTN BlocksRemaining
;
2600 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
2603 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
2604 return EFI_INVALID_PARAMETER
;
2607 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
2608 if (BlkIo2Req
== NULL
) {
2609 return EFI_OUT_OF_RESOURCES
;
2612 BlkIo2Req
->Token
= Token
;
2613 InsertTailList (&ScsiDiskDevice
->BlkIo2Queue
, &BlkIo2Req
->Link
);
2614 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
2616 Status
= EFI_SUCCESS
;
2618 BlocksRemaining
= NumberOfBlocks
;
2619 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2622 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2625 if (!ScsiDiskDevice
->Cdb16Byte
) {
2628 MaxBlock
= 0xFFFFFFFF;
2633 while (BlocksRemaining
> 0) {
2635 if (BlocksRemaining
<= MaxBlock
) {
2636 if (!ScsiDiskDevice
->Cdb16Byte
) {
2637 SectorCount
= (UINT16
) BlocksRemaining
;
2639 SectorCount
= (UINT32
) BlocksRemaining
;
2642 SectorCount
= MaxBlock
;
2645 ByteCount
= SectorCount
* BlockSize
;
2647 // |------------------------|-----------------|------------------|-----------------|
2648 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2649 // |------------------------|-----------------|------------------|-----------------|
2650 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2651 // |------------------------|-----------------|------------------|-----------------|
2652 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2653 // |------------------------|-----------------|------------------|-----------------|
2654 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2655 // |------------------------|-----------------|------------------|-----------------|
2656 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2657 // |------------------------|-----------------|------------------|-----------------|
2658 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2659 // |------------------------|-----------------|------------------|-----------------|
2660 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2661 // |------------------------|-----------------|------------------|-----------------|
2662 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2663 // |------------------------|-----------------|------------------|-----------------|
2664 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2665 // |------------------------|-----------------|------------------|-----------------|
2666 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2667 // |------------------------|-----------------|------------------|-----------------|
2668 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2669 // |------------------------|-----------------|------------------|-----------------|
2671 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2672 // we have to use the lowest transfer rate to calculate the possible
2673 // maximum timeout value for each operation.
2674 // From the above table, we could know 2.1Mbytes per second is lowest one.
2675 // The timout value is rounded up to nearest integar and here an additional
2676 // 30s is added to follow ATA spec in which it mentioned that the device
2677 // may take up to 30s to respond commands in the Standby/Idle mode.
2679 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2681 if (!ScsiDiskDevice
->Cdb16Byte
) {
2682 Status
= ScsiDiskAsyncRead10 (
2693 Status
= ScsiDiskAsyncRead16 (
2704 if (EFI_ERROR (Status
)) {
2706 // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI
2707 // command fails. Otherwise, it will be freed in the callback function
2708 // ScsiDiskNotify().
2710 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2711 RemoveEntryList (&BlkIo2Req
->Link
);
2712 FreePool (BlkIo2Req
);
2714 return EFI_DEVICE_ERROR
;
2718 // Sectors submitted for transfer
2720 SectorCount
= ByteCount
/ BlockSize
;
2723 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2724 BlocksRemaining
-= SectorCount
;
2731 Asynchronously write sector to SCSI Disk.
2733 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2734 @param Buffer The buffer of data to be written into SCSI Disk.
2735 @param Lba Logic block address.
2736 @param NumberOfBlocks The number of blocks to read.
2737 @param Token A pointer to the token associated with the
2738 non-blocking read request.
2740 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
2741 @retval EFI_DEVICE_ERROR Indicates a device error.
2742 @retval EFI_SUCCESS Operation is successful.
2746 ScsiDiskAsyncWriteSectors (
2747 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2750 IN UINTN NumberOfBlocks
,
2751 IN EFI_BLOCK_IO2_TOKEN
*Token
2754 UINTN BlocksRemaining
;
2761 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
2764 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
2765 return EFI_INVALID_PARAMETER
;
2768 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
2769 if (BlkIo2Req
== NULL
) {
2770 return EFI_OUT_OF_RESOURCES
;
2773 BlkIo2Req
->Token
= Token
;
2774 InsertTailList (&ScsiDiskDevice
->BlkIo2Queue
, &BlkIo2Req
->Link
);
2775 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
2777 Status
= EFI_SUCCESS
;
2779 BlocksRemaining
= NumberOfBlocks
;
2780 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2783 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2786 if (!ScsiDiskDevice
->Cdb16Byte
) {
2789 MaxBlock
= 0xFFFFFFFF;
2794 while (BlocksRemaining
> 0) {
2796 if (BlocksRemaining
<= MaxBlock
) {
2797 if (!ScsiDiskDevice
->Cdb16Byte
) {
2798 SectorCount
= (UINT16
) BlocksRemaining
;
2800 SectorCount
= (UINT32
) BlocksRemaining
;
2803 SectorCount
= MaxBlock
;
2806 ByteCount
= SectorCount
* BlockSize
;
2808 // |------------------------|-----------------|------------------|-----------------|
2809 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2810 // |------------------------|-----------------|------------------|-----------------|
2811 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2812 // |------------------------|-----------------|------------------|-----------------|
2813 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2814 // |------------------------|-----------------|------------------|-----------------|
2815 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2816 // |------------------------|-----------------|------------------|-----------------|
2817 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2818 // |------------------------|-----------------|------------------|-----------------|
2819 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2820 // |------------------------|-----------------|------------------|-----------------|
2821 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2822 // |------------------------|-----------------|------------------|-----------------|
2823 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2824 // |------------------------|-----------------|------------------|-----------------|
2825 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2826 // |------------------------|-----------------|------------------|-----------------|
2827 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2828 // |------------------------|-----------------|------------------|-----------------|
2829 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2830 // |------------------------|-----------------|------------------|-----------------|
2832 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2833 // we have to use the lowest transfer rate to calculate the possible
2834 // maximum timeout value for each operation.
2835 // From the above table, we could know 2.1Mbytes per second is lowest one.
2836 // The timout value is rounded up to nearest integar and here an additional
2837 // 30s is added to follow ATA spec in which it mentioned that the device
2838 // may take up to 30s to respond commands in the Standby/Idle mode.
2840 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2842 if (!ScsiDiskDevice
->Cdb16Byte
) {
2843 Status
= ScsiDiskAsyncWrite10 (
2854 Status
= ScsiDiskAsyncWrite16 (
2865 if (EFI_ERROR (Status
)) {
2867 // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI
2868 // command fails. Otherwise, it will be freed in the callback function
2869 // ScsiDiskNotify().
2871 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2872 RemoveEntryList (&BlkIo2Req
->Link
);
2873 FreePool (BlkIo2Req
);
2875 return EFI_DEVICE_ERROR
;
2879 // Sectors submitted for transfer
2881 SectorCount
= ByteCount
/ BlockSize
;
2884 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2885 BlocksRemaining
-= SectorCount
;
2893 Submit Read(10) command.
2895 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2896 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2897 @param Timeout The time to complete the command
2898 @param DataBuffer The buffer to fill with the read out data
2899 @param DataLength The length of buffer
2900 @param StartLba The start logic block address
2901 @param SectorCount The number of blocks to read
2903 @return EFI_STATUS is returned by calling ScsiRead10Command().
2907 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2908 OUT BOOLEAN
*NeedRetry
,
2910 OUT UINT8
*DataBuffer
,
2911 IN OUT UINT32
*DataLength
,
2913 IN UINT32 SectorCount
2916 UINT8 SenseDataLength
;
2918 EFI_STATUS ReturnStatus
;
2919 UINT8 HostAdapterStatus
;
2924 // Implement a backoff algorithem to resolve some compatibility issues that
2925 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2926 // big data in a single operation.
2927 // This algorithem will at first try to execute original request. If the request fails
2928 // with media error sense data or else, it will reduce the transfer length to half and
2929 // try again till the operation succeeds or fails with one sector transfer length.
2933 Action
= ACTION_NO_ACTION
;
2934 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2935 ReturnStatus
= ScsiRead10Command (
2936 ScsiDiskDevice
->ScsiIo
,
2938 ScsiDiskDevice
->SenseData
,
2948 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
2950 return EFI_DEVICE_ERROR
;
2951 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
2953 return ReturnStatus
;
2957 // go ahead to check HostAdapterStatus and TargetStatus
2958 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2960 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2961 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2963 return EFI_DEVICE_ERROR
;
2964 } else if (Status
== EFI_DEVICE_ERROR
) {
2966 // reset the scsi channel
2968 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2970 return EFI_DEVICE_ERROR
;
2973 Status
= CheckTargetStatus (TargetStatus
);
2974 if (Status
== EFI_NOT_READY
) {
2976 // reset the scsi device
2978 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2980 return EFI_DEVICE_ERROR
;
2981 } else if (Status
== EFI_DEVICE_ERROR
) {
2983 return EFI_DEVICE_ERROR
;
2986 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
2987 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
2988 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
2989 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2991 return EFI_DEVICE_ERROR
;
2992 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
2993 if (SectorCount
<= 1) {
2995 // Jump out if the operation still fails with one sector transfer length.
2998 return EFI_DEVICE_ERROR
;
3001 // Try again with half length if the sense data shows we need to retry.
3004 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3008 return EFI_DEVICE_ERROR
;
3012 return ReturnStatus
;
3017 Submit Write(10) Command.
3019 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3020 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3021 @param Timeout The time to complete the command
3022 @param DataBuffer The buffer to fill with the read out data
3023 @param DataLength The length of buffer
3024 @param StartLba The start logic block address
3025 @param SectorCount The number of blocks to write
3027 @return EFI_STATUS is returned by calling ScsiWrite10Command().
3032 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3033 OUT BOOLEAN
*NeedRetry
,
3035 IN UINT8
*DataBuffer
,
3036 IN OUT UINT32
*DataLength
,
3038 IN UINT32 SectorCount
3042 EFI_STATUS ReturnStatus
;
3043 UINT8 SenseDataLength
;
3044 UINT8 HostAdapterStatus
;
3049 // Implement a backoff algorithem to resolve some compatibility issues that
3050 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3051 // big data in a single operation.
3052 // This algorithem will at first try to execute original request. If the request fails
3053 // with media error sense data or else, it will reduce the transfer length to half and
3054 // try again till the operation succeeds or fails with one sector transfer length.
3058 Action
= ACTION_NO_ACTION
;
3059 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3060 ReturnStatus
= ScsiWrite10Command (
3061 ScsiDiskDevice
->ScsiIo
,
3063 ScsiDiskDevice
->SenseData
,
3072 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3074 return EFI_DEVICE_ERROR
;
3075 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3077 return ReturnStatus
;
3081 // go ahead to check HostAdapterStatus and TargetStatus
3082 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3084 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3085 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3087 return EFI_DEVICE_ERROR
;
3088 } else if (Status
== EFI_DEVICE_ERROR
) {
3090 // reset the scsi channel
3092 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3094 return EFI_DEVICE_ERROR
;
3097 Status
= CheckTargetStatus (TargetStatus
);
3098 if (Status
== EFI_NOT_READY
) {
3100 // reset the scsi device
3102 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3104 return EFI_DEVICE_ERROR
;
3105 } else if (Status
== EFI_DEVICE_ERROR
) {
3107 return EFI_DEVICE_ERROR
;
3110 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3111 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
3112 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3113 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3115 return EFI_DEVICE_ERROR
;
3116 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3117 if (SectorCount
<= 1) {
3119 // Jump out if the operation still fails with one sector transfer length.
3122 return EFI_DEVICE_ERROR
;
3125 // Try again with half length if the sense data shows we need to retry.
3128 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3132 return EFI_DEVICE_ERROR
;
3136 return ReturnStatus
;
3141 Submit Read(16) command.
3143 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3144 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3145 @param Timeout The time to complete the command
3146 @param DataBuffer The buffer to fill with the read out data
3147 @param DataLength The length of buffer
3148 @param StartLba The start logic block address
3149 @param SectorCount The number of blocks to read
3151 @return EFI_STATUS is returned by calling ScsiRead16Command().
3155 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3156 OUT BOOLEAN
*NeedRetry
,
3158 OUT UINT8
*DataBuffer
,
3159 IN OUT UINT32
*DataLength
,
3161 IN UINT32 SectorCount
3164 UINT8 SenseDataLength
;
3166 EFI_STATUS ReturnStatus
;
3167 UINT8 HostAdapterStatus
;
3172 // Implement a backoff algorithem to resolve some compatibility issues that
3173 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3174 // big data in a single operation.
3175 // This algorithem will at first try to execute original request. If the request fails
3176 // with media error sense data or else, it will reduce the transfer length to half and
3177 // try again till the operation succeeds or fails with one sector transfer length.
3181 Action
= ACTION_NO_ACTION
;
3182 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3183 ReturnStatus
= ScsiRead16Command (
3184 ScsiDiskDevice
->ScsiIo
,
3186 ScsiDiskDevice
->SenseData
,
3195 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3197 return EFI_DEVICE_ERROR
;
3198 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3200 return ReturnStatus
;
3204 // go ahead to check HostAdapterStatus and TargetStatus
3205 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3207 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3208 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3210 return EFI_DEVICE_ERROR
;
3211 } else if (Status
== EFI_DEVICE_ERROR
) {
3213 // reset the scsi channel
3215 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3217 return EFI_DEVICE_ERROR
;
3220 Status
= CheckTargetStatus (TargetStatus
);
3221 if (Status
== EFI_NOT_READY
) {
3223 // reset the scsi device
3225 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3227 return EFI_DEVICE_ERROR
;
3228 } else if (Status
== EFI_DEVICE_ERROR
) {
3230 return EFI_DEVICE_ERROR
;
3233 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3234 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
3235 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3236 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3238 return EFI_DEVICE_ERROR
;
3239 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3240 if (SectorCount
<= 1) {
3242 // Jump out if the operation still fails with one sector transfer length.
3245 return EFI_DEVICE_ERROR
;
3248 // Try again with half length if the sense data shows we need to retry.
3251 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3255 return EFI_DEVICE_ERROR
;
3259 return ReturnStatus
;
3264 Submit Write(16) Command.
3266 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3267 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3268 @param Timeout The time to complete the command
3269 @param DataBuffer The buffer to fill with the read out data
3270 @param DataLength The length of buffer
3271 @param StartLba The start logic block address
3272 @param SectorCount The number of blocks to write
3274 @return EFI_STATUS is returned by calling ScsiWrite16Command().
3279 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3280 OUT BOOLEAN
*NeedRetry
,
3282 IN UINT8
*DataBuffer
,
3283 IN OUT UINT32
*DataLength
,
3285 IN UINT32 SectorCount
3289 EFI_STATUS ReturnStatus
;
3290 UINT8 SenseDataLength
;
3291 UINT8 HostAdapterStatus
;
3296 // Implement a backoff algorithem to resolve some compatibility issues that
3297 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3298 // big data in a single operation.
3299 // This algorithem will at first try to execute original request. If the request fails
3300 // with media error sense data or else, it will reduce the transfer length to half and
3301 // try again till the operation succeeds or fails with one sector transfer length.
3305 Action
= ACTION_NO_ACTION
;
3306 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3307 ReturnStatus
= ScsiWrite16Command (
3308 ScsiDiskDevice
->ScsiIo
,
3310 ScsiDiskDevice
->SenseData
,
3319 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3321 return EFI_DEVICE_ERROR
;
3322 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3324 return ReturnStatus
;
3328 // go ahead to check HostAdapterStatus and TargetStatus
3329 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3331 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3332 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3334 return EFI_DEVICE_ERROR
;
3335 } else if (Status
== EFI_DEVICE_ERROR
) {
3337 // reset the scsi channel
3339 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3341 return EFI_DEVICE_ERROR
;
3344 Status
= CheckTargetStatus (TargetStatus
);
3345 if (Status
== EFI_NOT_READY
) {
3347 // reset the scsi device
3349 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3351 return EFI_DEVICE_ERROR
;
3352 } else if (Status
== EFI_DEVICE_ERROR
) {
3354 return EFI_DEVICE_ERROR
;
3357 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3358 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
3359 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3360 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3362 return EFI_DEVICE_ERROR
;
3363 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3364 if (SectorCount
<= 1) {
3366 // Jump out if the operation still fails with one sector transfer length.
3369 return EFI_DEVICE_ERROR
;
3372 // Try again with half length if the sense data shows we need to retry.
3375 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3379 return EFI_DEVICE_ERROR
;
3383 return ReturnStatus
;
3388 Internal helper notify function in which determine whether retry of a SCSI
3389 Read/Write command is needed and signal the event passed from Block I/O(2) if
3390 the SCSI I/O operation completes.
3392 @param Event The instance of EFI_EVENT.
3393 @param Context The parameter passed in.
3404 SCSI_ASYNC_RW_REQUEST
*Request
;
3405 SCSI_DISK_DEV
*ScsiDiskDevice
;
3406 EFI_BLOCK_IO2_TOKEN
*Token
;
3408 UINT32 OldDataLength
;
3409 UINT32 OldSectorCount
;
3412 gBS
->CloseEvent (Event
);
3414 Request
= (SCSI_ASYNC_RW_REQUEST
*) Context
;
3415 ScsiDiskDevice
= Request
->ScsiDiskDevice
;
3416 Token
= Request
->BlkIo2Req
->Token
;
3417 OldDataLength
= Request
->DataLength
;
3418 OldSectorCount
= Request
->SectorCount
;
3422 // If previous sub-tasks already fails, no need to process this sub-task.
3424 if (Token
->TransactionStatus
!= EFI_SUCCESS
) {
3429 // Check HostAdapterStatus and TargetStatus
3430 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3432 Status
= CheckHostAdapterStatus (Request
->HostAdapterStatus
);
3433 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3434 if (++Request
->TimesRetry
> MaxRetry
) {
3435 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3440 } else if (Status
== EFI_DEVICE_ERROR
) {
3442 // reset the scsi channel
3444 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3445 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3449 Status
= CheckTargetStatus (Request
->TargetStatus
);
3450 if (Status
== EFI_NOT_READY
) {
3452 // reset the scsi device
3454 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3455 if (++Request
->TimesRetry
> MaxRetry
) {
3456 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3461 } else if (Status
== EFI_DEVICE_ERROR
) {
3462 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3466 if (Request
->TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) {
3467 DEBUG ((EFI_D_ERROR
, "ScsiDiskNotify: Check Condition happened!\n"));
3469 Status
= DetectMediaParsingSenseKeys (
3472 Request
->SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
),
3475 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3476 if (++Request
->TimesRetry
> MaxRetry
) {
3477 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3482 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3483 if (Request
->SectorCount
<= 1) {
3485 // Jump out if the operation still fails with one sector transfer
3488 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3492 // Try again with two half length request if the sense data shows we need
3495 Request
->SectorCount
>>= 1;
3496 Request
->DataLength
= Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3497 Request
->TimesRetry
= 0;
3501 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3507 // This sub-task succeeds, no need to retry.
3512 if (Request
->InBuffer
!= NULL
) {
3514 // SCSI read command
3516 if (!ScsiDiskDevice
->Cdb16Byte
) {
3517 Status
= ScsiDiskAsyncRead10 (
3521 Request
->DataLength
,
3522 (UINT32
) Request
->StartLba
,
3523 Request
->SectorCount
,
3528 Status
= ScsiDiskAsyncRead16 (
3532 Request
->DataLength
,
3534 Request
->SectorCount
,
3540 if (EFI_ERROR (Status
)) {
3541 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3543 } else if (OldSectorCount
!= Request
->SectorCount
) {
3545 // Original sub-task will be split into two new sub-tasks with smaller
3548 if (!ScsiDiskDevice
->Cdb16Byte
) {
3549 Status
= ScsiDiskAsyncRead10 (
3552 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3553 OldDataLength
- Request
->DataLength
,
3554 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
3555 OldSectorCount
- Request
->SectorCount
,
3560 Status
= ScsiDiskAsyncRead16 (
3563 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3564 OldDataLength
- Request
->DataLength
,
3565 Request
->StartLba
+ Request
->SectorCount
,
3566 OldSectorCount
- Request
->SectorCount
,
3571 if (EFI_ERROR (Status
)) {
3572 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3578 // SCSI write command
3580 if (!ScsiDiskDevice
->Cdb16Byte
) {
3581 Status
= ScsiDiskAsyncWrite10 (
3585 Request
->DataLength
,
3586 (UINT32
) Request
->StartLba
,
3587 Request
->SectorCount
,
3592 Status
= ScsiDiskAsyncWrite16 (
3596 Request
->DataLength
,
3598 Request
->SectorCount
,
3604 if (EFI_ERROR (Status
)) {
3605 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3607 } else if (OldSectorCount
!= Request
->SectorCount
) {
3609 // Original sub-task will be split into two new sub-tasks with smaller
3612 if (!ScsiDiskDevice
->Cdb16Byte
) {
3613 Status
= ScsiDiskAsyncWrite10 (
3616 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3617 OldDataLength
- Request
->DataLength
,
3618 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
3619 OldSectorCount
- Request
->SectorCount
,
3624 Status
= ScsiDiskAsyncWrite16 (
3627 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3628 OldDataLength
- Request
->DataLength
,
3629 Request
->StartLba
+ Request
->SectorCount
,
3630 OldSectorCount
- Request
->SectorCount
,
3635 if (EFI_ERROR (Status
)) {
3636 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3643 RemoveEntryList (&Request
->Link
);
3644 if (IsListEmpty (&Request
->BlkIo2Req
->ScsiRWQueue
)) {
3646 // The last SCSI R/W command of a BlockIo2 request completes
3648 RemoveEntryList (&Request
->BlkIo2Req
->Link
);
3649 FreePool (Request
->BlkIo2Req
); // Should be freed only once
3650 gBS
->SignalEvent (Token
->Event
);
3653 FreePool (Request
->SenseData
);
3659 Submit Async Read(10) command.
3661 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3662 @param Timeout The time to complete the command.
3663 @param DataBuffer The buffer to fill with the read out data.
3664 @param DataLength The length of buffer.
3665 @param StartLba The start logic block address.
3666 @param SectorCount The number of blocks to read.
3667 @param BlkIo2Req The upstream BlockIo2 request.
3668 @param Token The pointer to the token associated with the
3669 non-blocking read request.
3671 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3673 @return others Status returned by calling
3674 ScsiRead10CommandEx().
3678 ScsiDiskAsyncRead10 (
3679 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3681 OUT UINT8
*DataBuffer
,
3682 IN UINT32 DataLength
,
3684 IN UINT32 SectorCount
,
3685 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3686 IN EFI_BLOCK_IO2_TOKEN
*Token
3690 SCSI_ASYNC_RW_REQUEST
*Request
;
3691 EFI_EVENT AsyncIoEvent
;
3693 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3694 if (Request
== NULL
) {
3695 return EFI_OUT_OF_RESOURCES
;
3697 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3699 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3700 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3701 if (Request
->SenseData
== NULL
) {
3702 Status
= EFI_OUT_OF_RESOURCES
;
3706 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3707 Request
->Timeout
= Timeout
;
3708 Request
->InBuffer
= DataBuffer
;
3709 Request
->DataLength
= DataLength
;
3710 Request
->StartLba
= StartLba
;
3711 Request
->SectorCount
= SectorCount
;
3712 Request
->BlkIo2Req
= BlkIo2Req
;
3717 Status
= gBS
->CreateEvent (
3724 if (EFI_ERROR(Status
)) {
3728 Status
= ScsiRead10CommandEx (
3729 ScsiDiskDevice
->ScsiIo
,
3732 &Request
->SenseDataLength
,
3733 &Request
->HostAdapterStatus
,
3734 &Request
->TargetStatus
,
3736 &Request
->DataLength
,
3737 (UINT32
) Request
->StartLba
,
3738 Request
->SectorCount
,
3741 if (EFI_ERROR(Status
)) {
3748 if (Request
!= NULL
) {
3749 if (Request
->SenseData
!= NULL
) {
3750 FreePool (Request
->SenseData
);
3753 RemoveEntryList (&Request
->Link
);
3762 Submit Async Write(10) command.
3764 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3765 @param Timeout The time to complete the command.
3766 @param DataBuffer The buffer contains the data to write.
3767 @param DataLength The length of buffer.
3768 @param StartLba The start logic block address.
3769 @param SectorCount The number of blocks to write.
3770 @param BlkIo2Req The upstream BlockIo2 request.
3771 @param Token The pointer to the token associated with the
3772 non-blocking read request.
3774 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3776 @return others Status returned by calling
3777 ScsiWrite10CommandEx().
3781 ScsiDiskAsyncWrite10 (
3782 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3784 IN UINT8
*DataBuffer
,
3785 IN UINT32 DataLength
,
3787 IN UINT32 SectorCount
,
3788 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3789 IN EFI_BLOCK_IO2_TOKEN
*Token
3793 SCSI_ASYNC_RW_REQUEST
*Request
;
3794 EFI_EVENT AsyncIoEvent
;
3796 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3797 if (Request
== NULL
) {
3798 return EFI_OUT_OF_RESOURCES
;
3800 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3802 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3803 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3804 if (Request
->SenseData
== NULL
) {
3805 Status
= EFI_OUT_OF_RESOURCES
;
3809 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3810 Request
->Timeout
= Timeout
;
3811 Request
->OutBuffer
= DataBuffer
;
3812 Request
->DataLength
= DataLength
;
3813 Request
->StartLba
= StartLba
;
3814 Request
->SectorCount
= SectorCount
;
3815 Request
->BlkIo2Req
= BlkIo2Req
;
3820 Status
= gBS
->CreateEvent (
3827 if (EFI_ERROR(Status
)) {
3831 Status
= ScsiWrite10CommandEx (
3832 ScsiDiskDevice
->ScsiIo
,
3835 &Request
->SenseDataLength
,
3836 &Request
->HostAdapterStatus
,
3837 &Request
->TargetStatus
,
3839 &Request
->DataLength
,
3840 (UINT32
) Request
->StartLba
,
3841 Request
->SectorCount
,
3844 if (EFI_ERROR(Status
)) {
3851 if (Request
!= NULL
) {
3852 if (Request
->SenseData
!= NULL
) {
3853 FreePool (Request
->SenseData
);
3856 RemoveEntryList (&Request
->Link
);
3865 Submit Async Read(16) command.
3867 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3868 @param Timeout The time to complete the command.
3869 @param DataBuffer The buffer to fill with the read out data.
3870 @param DataLength The length of buffer.
3871 @param StartLba The start logic block address.
3872 @param SectorCount The number of blocks to read.
3873 @param BlkIo2Req The upstream BlockIo2 request.
3874 @param Token The pointer to the token associated with the
3875 non-blocking read request.
3877 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3879 @return others Status returned by calling
3880 ScsiRead16CommandEx().
3884 ScsiDiskAsyncRead16 (
3885 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3887 OUT UINT8
*DataBuffer
,
3888 IN UINT32 DataLength
,
3890 IN UINT32 SectorCount
,
3891 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3892 IN EFI_BLOCK_IO2_TOKEN
*Token
3896 SCSI_ASYNC_RW_REQUEST
*Request
;
3897 EFI_EVENT AsyncIoEvent
;
3899 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3900 if (Request
== NULL
) {
3901 return EFI_OUT_OF_RESOURCES
;
3903 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3905 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3906 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3907 if (Request
->SenseData
== NULL
) {
3908 Status
= EFI_OUT_OF_RESOURCES
;
3912 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3913 Request
->Timeout
= Timeout
;
3914 Request
->InBuffer
= DataBuffer
;
3915 Request
->DataLength
= DataLength
;
3916 Request
->StartLba
= StartLba
;
3917 Request
->SectorCount
= SectorCount
;
3918 Request
->BlkIo2Req
= BlkIo2Req
;
3923 Status
= gBS
->CreateEvent (
3930 if (EFI_ERROR(Status
)) {
3934 Status
= ScsiRead16CommandEx (
3935 ScsiDiskDevice
->ScsiIo
,
3938 &Request
->SenseDataLength
,
3939 &Request
->HostAdapterStatus
,
3940 &Request
->TargetStatus
,
3942 &Request
->DataLength
,
3944 Request
->SectorCount
,
3947 if (EFI_ERROR(Status
)) {
3954 if (Request
!= NULL
) {
3955 if (Request
->SenseData
!= NULL
) {
3956 FreePool (Request
->SenseData
);
3959 RemoveEntryList (&Request
->Link
);
3968 Submit Async Write(16) command.
3970 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3971 @param Timeout The time to complete the command.
3972 @param DataBuffer The buffer contains the data to write.
3973 @param DataLength The length of buffer.
3974 @param StartLba The start logic block address.
3975 @param SectorCount The number of blocks to write.
3976 @param BlkIo2Req The upstream BlockIo2 request.
3977 @param Token The pointer to the token associated with the
3978 non-blocking read request.
3980 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3982 @return others Status returned by calling
3983 ScsiWrite16CommandEx().
3987 ScsiDiskAsyncWrite16 (
3988 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3990 IN UINT8
*DataBuffer
,
3991 IN UINT32 DataLength
,
3993 IN UINT32 SectorCount
,
3994 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3995 IN EFI_BLOCK_IO2_TOKEN
*Token
3999 SCSI_ASYNC_RW_REQUEST
*Request
;
4000 EFI_EVENT AsyncIoEvent
;
4002 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4003 if (Request
== NULL
) {
4004 return EFI_OUT_OF_RESOURCES
;
4006 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4008 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4009 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4010 if (Request
->SenseData
== NULL
) {
4011 Status
= EFI_OUT_OF_RESOURCES
;
4015 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4016 Request
->Timeout
= Timeout
;
4017 Request
->OutBuffer
= DataBuffer
;
4018 Request
->DataLength
= DataLength
;
4019 Request
->StartLba
= StartLba
;
4020 Request
->SectorCount
= SectorCount
;
4021 Request
->BlkIo2Req
= BlkIo2Req
;
4026 Status
= gBS
->CreateEvent (
4033 if (EFI_ERROR(Status
)) {
4037 Status
= ScsiWrite16CommandEx (
4038 ScsiDiskDevice
->ScsiIo
,
4041 &Request
->SenseDataLength
,
4042 &Request
->HostAdapterStatus
,
4043 &Request
->TargetStatus
,
4045 &Request
->DataLength
,
4047 Request
->SectorCount
,
4050 if (EFI_ERROR(Status
)) {
4057 if (Request
!= NULL
) {
4058 if (Request
->SenseData
!= NULL
) {
4059 FreePool (Request
->SenseData
);
4062 RemoveEntryList (&Request
->Link
);
4071 Check sense key to find if media presents.
4073 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4074 @param SenseCounts The number of sense key
4076 @retval TRUE NOT any media
4077 @retval FALSE Media presents
4081 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4082 IN UINTN SenseCounts
4085 EFI_SCSI_SENSE_DATA
*SensePtr
;
4090 SensePtr
= SenseData
;
4092 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4094 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
4095 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
4097 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
4098 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
4111 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4112 @param SenseCounts The number of sense key
4115 @retval FALSE NOT error
4119 ScsiDiskIsMediaError (
4120 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4121 IN UINTN SenseCounts
4124 EFI_SCSI_SENSE_DATA
*SensePtr
;
4129 SensePtr
= SenseData
;
4131 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4133 switch (SensePtr
->Sense_Key
) {
4135 case EFI_SCSI_SK_MEDIUM_ERROR
:
4137 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
4139 switch (SensePtr
->Addnl_Sense_Code
) {
4144 case EFI_SCSI_ASC_MEDIA_ERR1
:
4149 case EFI_SCSI_ASC_MEDIA_ERR2
:
4154 case EFI_SCSI_ASC_MEDIA_ERR3
:
4155 case EFI_SCSI_ASC_MEDIA_ERR4
:
4165 case EFI_SCSI_SK_NOT_READY
:
4167 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4169 switch (SensePtr
->Addnl_Sense_Code
) {
4171 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
4173 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
4194 Check sense key to find if hardware error happens.
4196 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4197 @param SenseCounts The number of sense key
4199 @retval TRUE Hardware error exits.
4200 @retval FALSE NO error.
4204 ScsiDiskIsHardwareError (
4205 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4206 IN UINTN SenseCounts
4209 EFI_SCSI_SENSE_DATA
*SensePtr
;
4214 SensePtr
= SenseData
;
4216 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4219 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
4221 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
4233 Check sense key to find if media has changed.
4235 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4236 @param SenseCounts The number of sense key
4238 @retval TRUE Media is changed.
4239 @retval FALSE Media is NOT changed.
4242 ScsiDiskIsMediaChange (
4243 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4244 IN UINTN SenseCounts
4247 EFI_SCSI_SENSE_DATA
*SensePtr
;
4249 BOOLEAN IsMediaChanged
;
4251 IsMediaChanged
= FALSE
;
4252 SensePtr
= SenseData
;
4254 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4256 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
4257 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
4259 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
4260 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
4261 IsMediaChanged
= TRUE
;
4267 return IsMediaChanged
;
4271 Check sense key to find if reset happens.
4273 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4274 @param SenseCounts The number of sense key
4276 @retval TRUE It is reset before.
4277 @retval FALSE It is NOT reset before.
4281 ScsiDiskIsResetBefore (
4282 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4283 IN UINTN SenseCounts
4286 EFI_SCSI_SENSE_DATA
*SensePtr
;
4288 BOOLEAN IsResetBefore
;
4290 IsResetBefore
= FALSE
;
4291 SensePtr
= SenseData
;
4293 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4296 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
4297 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
4299 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
4300 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
4301 IsResetBefore
= TRUE
;
4307 return IsResetBefore
;
4311 Check sense key to find if the drive is ready.
4313 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4314 @param SenseCounts The number of sense key
4315 @param RetryLater The flag means if need a retry
4317 @retval TRUE Drive is ready.
4318 @retval FALSE Drive is NOT ready.
4322 ScsiDiskIsDriveReady (
4323 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4324 IN UINTN SenseCounts
,
4325 OUT BOOLEAN
*RetryLater
4328 EFI_SCSI_SENSE_DATA
*SensePtr
;
4333 *RetryLater
= FALSE
;
4334 SensePtr
= SenseData
;
4336 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4338 switch (SensePtr
->Sense_Key
) {
4340 case EFI_SCSI_SK_NOT_READY
:
4342 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4344 switch (SensePtr
->Addnl_Sense_Code
) {
4345 case EFI_SCSI_ASC_NOT_READY
:
4347 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
4349 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
4350 case EFI_SCSI_ASCQ_IN_PROGRESS
:
4352 // Additional Sense Code Qualifier is
4353 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
4361 *RetryLater
= FALSE
;
4382 Check sense key to find if it has sense key.
4384 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
4385 @param SenseCounts - The number of sense key
4387 @retval TRUE It has sense key.
4388 @retval FALSE It has NOT any sense key.
4392 ScsiDiskHaveSenseKey (
4393 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4394 IN UINTN SenseCounts
4397 EFI_SCSI_SENSE_DATA
*SensePtr
;
4399 BOOLEAN HaveSenseKey
;
4401 if (SenseCounts
== 0) {
4402 HaveSenseKey
= FALSE
;
4404 HaveSenseKey
= TRUE
;
4407 SensePtr
= SenseData
;
4409 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4412 // Sense Key is SK_NO_SENSE (0x0)
4414 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
4416 HaveSenseKey
= FALSE
;
4422 return HaveSenseKey
;
4426 Release resource about disk device.
4428 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4432 ReleaseScsiDiskDeviceResources (
4433 IN SCSI_DISK_DEV
*ScsiDiskDevice
4436 if (ScsiDiskDevice
== NULL
) {
4440 if (ScsiDiskDevice
->SenseData
!= NULL
) {
4441 FreePool (ScsiDiskDevice
->SenseData
);
4442 ScsiDiskDevice
->SenseData
= NULL
;
4445 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
4446 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
4447 ScsiDiskDevice
->ControllerNameTable
= NULL
;
4450 FreePool (ScsiDiskDevice
);
4452 ScsiDiskDevice
= NULL
;
4456 Determine if Block Io & Block Io2 should be produced.
4459 @param ChildHandle Child Handle to retrieve Parent information.
4461 @retval TRUE Should produce Block Io & Block Io2.
4462 @retval FALSE Should not produce Block Io & Block Io2.
4466 DetermineInstallBlockIo (
4467 IN EFI_HANDLE ChildHandle
4470 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
4471 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
4474 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
4475 // check its attribute, logic or physical.
4477 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
4478 if (ExtScsiPassThru
!= NULL
) {
4479 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
4485 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
4486 // check its attribute, logic or physical.
4488 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
4489 if (ScsiPassThru
!= NULL
) {
4490 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
4499 Search protocol database and check to see if the protocol
4500 specified by ProtocolGuid is present on a ControllerHandle and opened by
4501 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
4502 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
4503 will be opened on it.
4506 @param ProtocolGuid ProtocolGuid pointer.
4507 @param ChildHandle Child Handle to retrieve Parent information.
4513 IN EFI_GUID
*ProtocolGuid
,
4514 IN EFI_HANDLE ChildHandle
4521 EFI_HANDLE
*HandleBuffer
;
4524 // Retrieve the list of all handles from the handle database
4526 Status
= gBS
->LocateHandleBuffer (
4534 if (EFI_ERROR (Status
)) {
4539 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
4541 for (Index
= 0; Index
< HandleCount
; Index
++) {
4542 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
4543 if (!EFI_ERROR (Status
)) {
4544 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
4545 if (!EFI_ERROR (Status
)) {
4546 gBS
->FreePool (HandleBuffer
);
4552 gBS
->FreePool (HandleBuffer
);
4557 Provides inquiry information for the controller type.
4559 This function is used by the IDE bus driver to get inquiry data. Data format
4560 of Identify data is defined by the Interface GUID.
4562 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4563 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
4564 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
4566 @retval EFI_SUCCESS The command was accepted without any errors.
4567 @retval EFI_NOT_FOUND Device does not support this data class
4568 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
4569 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
4574 ScsiDiskInfoInquiry (
4575 IN EFI_DISK_INFO_PROTOCOL
*This
,
4576 IN OUT VOID
*InquiryData
,
4577 IN OUT UINT32
*InquiryDataSize
4581 SCSI_DISK_DEV
*ScsiDiskDevice
;
4583 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4585 Status
= EFI_BUFFER_TOO_SMALL
;
4586 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
4587 Status
= EFI_SUCCESS
;
4588 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
4590 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
4596 Provides identify information for the controller type.
4598 This function is used by the IDE bus driver to get identify data. Data format
4599 of Identify data is defined by the Interface GUID.
4601 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
4603 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
4604 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
4607 @retval EFI_SUCCESS The command was accepted without any errors.
4608 @retval EFI_NOT_FOUND Device does not support this data class
4609 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
4610 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
4615 ScsiDiskInfoIdentify (
4616 IN EFI_DISK_INFO_PROTOCOL
*This
,
4617 IN OUT VOID
*IdentifyData
,
4618 IN OUT UINT32
*IdentifyDataSize
4622 SCSI_DISK_DEV
*ScsiDiskDevice
;
4624 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
4626 // Physical SCSI bus does not support this data class.
4628 return EFI_NOT_FOUND
;
4631 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4633 Status
= EFI_BUFFER_TOO_SMALL
;
4634 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
4635 Status
= EFI_SUCCESS
;
4636 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
4638 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
4643 Provides sense data information for the controller type.
4645 This function is used by the IDE bus driver to get sense data.
4646 Data format of Sense data is defined by the Interface GUID.
4648 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4649 @param[in, out] SenseData Pointer to the SenseData.
4650 @param[in, out] SenseDataSize Size of SenseData in bytes.
4651 @param[out] SenseDataNumber Pointer to the value for the sense data size.
4653 @retval EFI_SUCCESS The command was accepted without any errors.
4654 @retval EFI_NOT_FOUND Device does not support this data class.
4655 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
4656 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
4661 ScsiDiskInfoSenseData (
4662 IN EFI_DISK_INFO_PROTOCOL
*This
,
4663 IN OUT VOID
*SenseData
,
4664 IN OUT UINT32
*SenseDataSize
,
4665 OUT UINT8
*SenseDataNumber
4668 return EFI_NOT_FOUND
;
4673 This function is used by the IDE bus driver to get controller information.
4675 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4676 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
4677 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
4679 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
4680 @retval EFI_UNSUPPORTED This is not an IDE device.
4685 ScsiDiskInfoWhichIde (
4686 IN EFI_DISK_INFO_PROTOCOL
*This
,
4687 OUT UINT32
*IdeChannel
,
4688 OUT UINT32
*IdeDevice
4691 SCSI_DISK_DEV
*ScsiDiskDevice
;
4693 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
4695 // This is not an IDE physical device.
4697 return EFI_UNSUPPORTED
;
4700 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4701 *IdeChannel
= ScsiDiskDevice
->Channel
;
4702 *IdeDevice
= ScsiDiskDevice
->Device
;
4709 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
4711 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
4712 implement Identify() interface for DiskInfo protocol. The ATA command is sent
4713 via SCSI Request Packet.
4715 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4717 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
4718 @retval others Some error occurred during the identification that ATAPI device.
4722 AtapiIdentifyDevice (
4723 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
4726 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
4730 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
4732 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
4733 ZeroMem (Cdb
, sizeof (Cdb
));
4735 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
4736 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
4737 CommandPacket
.Cdb
= Cdb
;
4738 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
4739 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
4740 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
4742 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
4747 Initialize the installation of DiskInfo protocol.
4749 This function prepares for the installation of DiskInfo protocol on the child handle.
4750 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
4751 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
4752 to be IDE/AHCI interface GUID.
4754 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
4755 @param ChildHandle Child handle to install DiskInfo protocol.
4759 InitializeInstallDiskInfo (
4760 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4761 IN EFI_HANDLE ChildHandle
4765 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
4766 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
4767 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
4768 SATA_DEVICE_PATH
*SataDevicePath
;
4769 UINTN IdentifyRetry
;
4771 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
4773 // Device Path protocol must be installed on the device handle.
4775 ASSERT_EFI_ERROR (Status
);
4777 // Copy the DiskInfo protocol template.
4779 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
4781 while (!IsDevicePathEnd (DevicePathNode
)) {
4782 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
4783 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
4784 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
4785 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
4786 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
4787 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
4792 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
4793 // with IDE/AHCI interface GUID.
4795 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
4796 if (!EFI_ERROR (Status
)) {
4797 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
4799 // We find the valid ATAPI device path
4801 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
4802 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
4803 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
4805 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
4807 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
4810 // We find the valid SATA device path
4812 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
4813 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
4814 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
4816 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
4818 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
4822 } while (--IdentifyRetry
> 0);
4823 } else if ((DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
4824 (DevicePathSubType (ChildDevicePathNode
) == MSG_UFS_DP
)) {
4825 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoUfsInterfaceGuid
);
4828 DevicePathNode
= ChildDevicePathNode
;