2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2016, 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 if (Status
== EFI_UNSUPPORTED
) {
470 Status
= EFI_SUCCESS
;
472 Status
= EFI_DEVICE_ERROR
;
477 if (!ExtendedVerification
) {
481 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
483 if (EFI_ERROR (Status
)) {
484 Status
= EFI_DEVICE_ERROR
;
489 gBS
->RestoreTPL (OldTpl
);
494 The function is to Read Block from SCSI Disk.
496 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
497 @param MediaId The Id of Media detected
498 @param Lba The logic block address
499 @param BufferSize The size of Buffer
500 @param Buffer The buffer to fill the read out data
502 @retval EFI_SUCCESS Successfully to read out block.
503 @retval EFI_DEVICE_ERROR Fail to detect media.
504 @retval EFI_NO_MEDIA Media is not present.
505 @retval EFI_MEDIA_CHANGED Media has changed.
506 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
507 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
513 IN EFI_BLOCK_IO_PROTOCOL
*This
,
520 SCSI_DISK_DEV
*ScsiDiskDevice
;
521 EFI_BLOCK_IO_MEDIA
*Media
;
524 UINTN NumberOfBlocks
;
529 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
530 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
532 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
534 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
535 if (EFI_ERROR (Status
)) {
536 Status
= EFI_DEVICE_ERROR
;
541 gBS
->ReinstallProtocolInterface (
542 ScsiDiskDevice
->Handle
,
543 &gEfiBlockIoProtocolGuid
,
544 &ScsiDiskDevice
->BlkIo
,
545 &ScsiDiskDevice
->BlkIo
547 gBS
->ReinstallProtocolInterface (
548 ScsiDiskDevice
->Handle
,
549 &gEfiBlockIo2ProtocolGuid
,
550 &ScsiDiskDevice
->BlkIo2
,
551 &ScsiDiskDevice
->BlkIo2
553 Status
= EFI_MEDIA_CHANGED
;
558 // Get the intrinsic block size
560 Media
= ScsiDiskDevice
->BlkIo
.Media
;
561 BlockSize
= Media
->BlockSize
;
563 NumberOfBlocks
= BufferSize
/ BlockSize
;
565 if (!(Media
->MediaPresent
)) {
566 Status
= EFI_NO_MEDIA
;
570 if (MediaId
!= Media
->MediaId
) {
571 Status
= EFI_MEDIA_CHANGED
;
575 if (Buffer
== NULL
) {
576 Status
= EFI_INVALID_PARAMETER
;
580 if (BufferSize
== 0) {
581 Status
= EFI_SUCCESS
;
585 if (BufferSize
% BlockSize
!= 0) {
586 Status
= EFI_BAD_BUFFER_SIZE
;
590 if (Lba
> Media
->LastBlock
) {
591 Status
= EFI_INVALID_PARAMETER
;
595 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
596 Status
= EFI_INVALID_PARAMETER
;
600 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
601 Status
= EFI_INVALID_PARAMETER
;
606 // If all the parameters are valid, then perform read sectors command
607 // to transfer data from device to host.
609 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
612 gBS
->RestoreTPL (OldTpl
);
617 The function is to Write Block to SCSI Disk.
619 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
620 @param MediaId The Id of Media detected
621 @param Lba The logic block address
622 @param BufferSize The size of Buffer
623 @param Buffer The buffer to fill the read out data
625 @retval EFI_SUCCESS Successfully to read out block.
626 @retval EFI_WRITE_PROTECTED The device can not be written to.
627 @retval EFI_DEVICE_ERROR Fail to detect media.
628 @retval EFI_NO_MEDIA Media is not present.
629 @retval EFI_MEDIA_CHNAGED Media has changed.
630 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
631 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
636 ScsiDiskWriteBlocks (
637 IN EFI_BLOCK_IO_PROTOCOL
*This
,
644 SCSI_DISK_DEV
*ScsiDiskDevice
;
645 EFI_BLOCK_IO_MEDIA
*Media
;
648 UINTN NumberOfBlocks
;
653 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
654 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
656 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
658 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
659 if (EFI_ERROR (Status
)) {
660 Status
= EFI_DEVICE_ERROR
;
665 gBS
->ReinstallProtocolInterface (
666 ScsiDiskDevice
->Handle
,
667 &gEfiBlockIoProtocolGuid
,
668 &ScsiDiskDevice
->BlkIo
,
669 &ScsiDiskDevice
->BlkIo
671 gBS
->ReinstallProtocolInterface (
672 ScsiDiskDevice
->Handle
,
673 &gEfiBlockIo2ProtocolGuid
,
674 &ScsiDiskDevice
->BlkIo2
,
675 &ScsiDiskDevice
->BlkIo2
677 Status
= EFI_MEDIA_CHANGED
;
682 // Get the intrinsic block size
684 Media
= ScsiDiskDevice
->BlkIo
.Media
;
685 BlockSize
= Media
->BlockSize
;
687 NumberOfBlocks
= BufferSize
/ BlockSize
;
689 if (!(Media
->MediaPresent
)) {
690 Status
= EFI_NO_MEDIA
;
694 if (MediaId
!= Media
->MediaId
) {
695 Status
= EFI_MEDIA_CHANGED
;
699 if (Media
->ReadOnly
) {
700 Status
= EFI_WRITE_PROTECTED
;
704 if (BufferSize
== 0) {
705 Status
= EFI_SUCCESS
;
709 if (Buffer
== NULL
) {
710 Status
= EFI_INVALID_PARAMETER
;
714 if (BufferSize
% BlockSize
!= 0) {
715 Status
= EFI_BAD_BUFFER_SIZE
;
719 if (Lba
> Media
->LastBlock
) {
720 Status
= EFI_INVALID_PARAMETER
;
724 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
725 Status
= EFI_INVALID_PARAMETER
;
729 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
730 Status
= EFI_INVALID_PARAMETER
;
734 // if all the parameters are valid, then perform read sectors command
735 // to transfer data from device to host.
737 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
740 gBS
->RestoreTPL (OldTpl
);
747 EFI_SUCCESS is returned directly.
749 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
751 @retval EFI_SUCCESS All outstanding data was written to the device
756 ScsiDiskFlushBlocks (
757 IN EFI_BLOCK_IO_PROTOCOL
*This
770 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
771 @param ExtendedVerification The flag about if extend verificate.
773 @retval EFI_SUCCESS The device was reset.
774 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
776 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
782 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
783 IN BOOLEAN ExtendedVerification
787 SCSI_DISK_DEV
*ScsiDiskDevice
;
790 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
792 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
794 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
796 if (EFI_ERROR (Status
)) {
797 if (Status
== EFI_UNSUPPORTED
) {
798 Status
= EFI_SUCCESS
;
800 Status
= EFI_DEVICE_ERROR
;
805 if (!ExtendedVerification
) {
809 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
811 if (EFI_ERROR (Status
)) {
812 Status
= EFI_DEVICE_ERROR
;
817 gBS
->RestoreTPL (OldTpl
);
822 The function is to Read Block from SCSI Disk.
824 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
825 @param MediaId The Id of Media detected.
826 @param Lba The logic block address.
827 @param Token A pointer to the token associated with the transaction.
828 @param BufferSize The size of Buffer.
829 @param Buffer The buffer to fill the read out data.
831 @retval EFI_SUCCESS The read request was queued if Token-> Event is
832 not NULL. The data was read correctly from the
833 device if theToken-> Event is NULL.
834 @retval EFI_DEVICE_ERROR The device reported an error while attempting
835 to perform the read operation.
836 @retval EFI_NO_MEDIA There is no media in the device.
837 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
838 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
839 the intrinsic block size of the device.
840 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
841 valid, or the buffer is not on proper
843 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
849 ScsiDiskReadBlocksEx (
850 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
853 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
858 SCSI_DISK_DEV
*ScsiDiskDevice
;
859 EFI_BLOCK_IO_MEDIA
*Media
;
862 UINTN NumberOfBlocks
;
867 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
868 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
870 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
872 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
873 if (EFI_ERROR (Status
)) {
874 Status
= EFI_DEVICE_ERROR
;
879 gBS
->ReinstallProtocolInterface (
880 ScsiDiskDevice
->Handle
,
881 &gEfiBlockIoProtocolGuid
,
882 &ScsiDiskDevice
->BlkIo
,
883 &ScsiDiskDevice
->BlkIo
885 gBS
->ReinstallProtocolInterface (
886 ScsiDiskDevice
->Handle
,
887 &gEfiBlockIo2ProtocolGuid
,
888 &ScsiDiskDevice
->BlkIo2
,
889 &ScsiDiskDevice
->BlkIo2
891 Status
= EFI_MEDIA_CHANGED
;
896 // Get the intrinsic block size
898 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
899 BlockSize
= Media
->BlockSize
;
901 NumberOfBlocks
= BufferSize
/ BlockSize
;
903 if (!(Media
->MediaPresent
)) {
904 Status
= EFI_NO_MEDIA
;
908 if (MediaId
!= Media
->MediaId
) {
909 Status
= EFI_MEDIA_CHANGED
;
913 if (Buffer
== NULL
) {
914 Status
= EFI_INVALID_PARAMETER
;
918 if (BufferSize
== 0) {
919 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
920 Token
->TransactionStatus
= EFI_SUCCESS
;
921 gBS
->SignalEvent (Token
->Event
);
924 Status
= EFI_SUCCESS
;
928 if (BufferSize
% BlockSize
!= 0) {
929 Status
= EFI_BAD_BUFFER_SIZE
;
933 if (Lba
> Media
->LastBlock
) {
934 Status
= EFI_INVALID_PARAMETER
;
938 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
939 Status
= EFI_INVALID_PARAMETER
;
943 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
944 Status
= EFI_INVALID_PARAMETER
;
949 // If all the parameters are valid, then perform read sectors command
950 // to transfer data from device to host.
952 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
953 Token
->TransactionStatus
= EFI_SUCCESS
;
954 Status
= ScsiDiskAsyncReadSectors (
962 Status
= ScsiDiskReadSectors (
971 gBS
->RestoreTPL (OldTpl
);
976 The function is to Write Block to SCSI Disk.
978 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
979 @param MediaId The Id of Media detected.
980 @param Lba The logic block address.
981 @param Token A pointer to the token associated with the transaction.
982 @param BufferSize The size of Buffer.
983 @param Buffer The buffer to fill the read out data.
985 @retval EFI_SUCCESS The data were written correctly to the device.
986 @retval EFI_WRITE_PROTECTED The device cannot be written to.
987 @retval EFI_NO_MEDIA There is no media in the device.
988 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
989 @retval EFI_DEVICE_ERROR The device reported an error while attempting
990 to perform the write operation.
991 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
992 the intrinsic block size of the device.
993 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
994 valid, or the buffer is not on proper
1000 ScsiDiskWriteBlocksEx (
1001 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1004 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1005 IN UINTN BufferSize
,
1009 SCSI_DISK_DEV
*ScsiDiskDevice
;
1010 EFI_BLOCK_IO_MEDIA
*Media
;
1013 UINTN NumberOfBlocks
;
1014 BOOLEAN MediaChange
;
1017 MediaChange
= FALSE
;
1018 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1019 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1021 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1023 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1024 if (EFI_ERROR (Status
)) {
1025 Status
= EFI_DEVICE_ERROR
;
1030 gBS
->ReinstallProtocolInterface (
1031 ScsiDiskDevice
->Handle
,
1032 &gEfiBlockIoProtocolGuid
,
1033 &ScsiDiskDevice
->BlkIo
,
1034 &ScsiDiskDevice
->BlkIo
1036 gBS
->ReinstallProtocolInterface (
1037 ScsiDiskDevice
->Handle
,
1038 &gEfiBlockIo2ProtocolGuid
,
1039 &ScsiDiskDevice
->BlkIo2
,
1040 &ScsiDiskDevice
->BlkIo2
1042 Status
= EFI_MEDIA_CHANGED
;
1047 // Get the intrinsic block size
1049 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
1050 BlockSize
= Media
->BlockSize
;
1052 NumberOfBlocks
= BufferSize
/ BlockSize
;
1054 if (!(Media
->MediaPresent
)) {
1055 Status
= EFI_NO_MEDIA
;
1059 if (MediaId
!= Media
->MediaId
) {
1060 Status
= EFI_MEDIA_CHANGED
;
1064 if (Media
->ReadOnly
) {
1065 Status
= EFI_WRITE_PROTECTED
;
1069 if (BufferSize
== 0) {
1070 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1071 Token
->TransactionStatus
= EFI_SUCCESS
;
1072 gBS
->SignalEvent (Token
->Event
);
1075 Status
= EFI_SUCCESS
;
1079 if (Buffer
== NULL
) {
1080 Status
= EFI_INVALID_PARAMETER
;
1084 if (BufferSize
% BlockSize
!= 0) {
1085 Status
= EFI_BAD_BUFFER_SIZE
;
1089 if (Lba
> Media
->LastBlock
) {
1090 Status
= EFI_INVALID_PARAMETER
;
1094 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1095 Status
= EFI_INVALID_PARAMETER
;
1099 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1100 Status
= EFI_INVALID_PARAMETER
;
1105 // if all the parameters are valid, then perform write sectors command
1106 // to transfer data from device to host.
1108 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1109 Token
->TransactionStatus
= EFI_SUCCESS
;
1110 Status
= ScsiDiskAsyncWriteSectors (
1118 Status
= ScsiDiskWriteSectors (
1127 gBS
->RestoreTPL (OldTpl
);
1132 Flush the Block Device.
1134 @param This Indicates a pointer to the calling context.
1135 @param Token A pointer to the token associated with the transaction.
1137 @retval EFI_SUCCESS All outstanding data was written to the device.
1138 @retval EFI_DEVICE_ERROR The device reported an error while attempting to
1140 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1141 @retval EFI_NO_MEDIA There is no media in the device.
1142 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1147 ScsiDiskFlushBlocksEx (
1148 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1149 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1152 SCSI_DISK_DEV
*ScsiDiskDevice
;
1153 EFI_BLOCK_IO_MEDIA
*Media
;
1155 BOOLEAN MediaChange
;
1158 MediaChange
= FALSE
;
1159 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1160 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1162 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1164 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1165 if (EFI_ERROR (Status
)) {
1166 Status
= EFI_DEVICE_ERROR
;
1171 gBS
->ReinstallProtocolInterface (
1172 ScsiDiskDevice
->Handle
,
1173 &gEfiBlockIoProtocolGuid
,
1174 &ScsiDiskDevice
->BlkIo
,
1175 &ScsiDiskDevice
->BlkIo
1177 gBS
->ReinstallProtocolInterface (
1178 ScsiDiskDevice
->Handle
,
1179 &gEfiBlockIo2ProtocolGuid
,
1180 &ScsiDiskDevice
->BlkIo2
,
1181 &ScsiDiskDevice
->BlkIo2
1183 Status
= EFI_MEDIA_CHANGED
;
1188 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
1190 if (!(Media
->MediaPresent
)) {
1191 Status
= EFI_NO_MEDIA
;
1195 if (Media
->ReadOnly
) {
1196 Status
= EFI_WRITE_PROTECTED
;
1201 // Wait for the BlockIo2 requests queue to become empty
1203 while (!IsListEmpty (&ScsiDiskDevice
->BlkIo2Queue
));
1205 Status
= EFI_SUCCESS
;
1208 // Signal caller event
1210 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1211 Token
->TransactionStatus
= EFI_SUCCESS
;
1212 gBS
->SignalEvent (Token
->Event
);
1216 gBS
->RestoreTPL (OldTpl
);
1222 Detect Device and read out capacity ,if error occurs, parse the sense key.
1224 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1225 @param MustReadCapacity The flag about reading device capacity
1226 @param MediaChange The pointer of flag indicates if media has changed
1228 @retval EFI_DEVICE_ERROR Indicates that error occurs
1229 @retval EFI_SUCCESS Successfully to detect media
1233 ScsiDiskDetectMedia (
1234 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1235 IN BOOLEAN MustReadCapacity
,
1236 OUT BOOLEAN
*MediaChange
1240 EFI_SCSI_SENSE_DATA
*SenseData
;
1241 UINTN NumberOfSenseKeys
;
1243 BOOLEAN NeedReadCapacity
;
1246 EFI_BLOCK_IO_MEDIA OldMedia
;
1248 EFI_EVENT TimeoutEvt
;
1250 Status
= EFI_SUCCESS
;
1252 NumberOfSenseKeys
= 0;
1255 Action
= ACTION_NO_ACTION
;
1256 NeedReadCapacity
= FALSE
;
1257 *MediaChange
= FALSE
;
1260 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
1262 Status
= gBS
->CreateEvent (
1269 if (EFI_ERROR (Status
)) {
1273 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
1274 if (EFI_ERROR (Status
)) {
1279 // Sending Test_Unit cmd to poll device status.
1280 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
1281 // We limit the upper boundary to 120 seconds.
1283 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
1284 Status
= ScsiDiskTestUnitReady (
1290 if (!EFI_ERROR (Status
)) {
1291 Status
= DetectMediaParsingSenseKeys (
1297 if (EFI_ERROR (Status
)) {
1299 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1306 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1312 if (EFI_ERROR (Status
)) {
1317 // ACTION_NO_ACTION: need not read capacity
1318 // other action code: need read capacity
1320 if (Action
== ACTION_READ_CAPACITY
) {
1321 NeedReadCapacity
= TRUE
;
1325 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
1326 // retrieve capacity via Read Capacity command
1328 if (NeedReadCapacity
|| MustReadCapacity
) {
1330 // retrieve media information
1332 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
1333 Status
= ScsiDiskReadCapacity (
1339 if (!EFI_ERROR (Status
)) {
1341 // analyze sense key to action
1343 Status
= DetectMediaParsingSenseKeys (
1349 if (EFI_ERROR (Status
)) {
1351 // if Status is error, it may indicate crisis error,
1352 // so return without retry.
1355 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1363 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1369 if (EFI_ERROR (Status
)) {
1374 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
1376 // Media change information got from the device
1378 *MediaChange
= TRUE
;
1381 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
1382 *MediaChange
= TRUE
;
1383 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1386 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
1387 *MediaChange
= TRUE
;
1388 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1391 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
1392 *MediaChange
= TRUE
;
1393 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1396 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
1397 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
1399 // when change from no media to media present, reset the MediaId to 1.
1401 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
1404 // when no media, reset the MediaId to zero.
1406 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
1409 *MediaChange
= TRUE
;
1413 if (TimeoutEvt
!= NULL
) {
1414 gBS
->CloseEvent (TimeoutEvt
);
1421 Send out Inquiry command to Device.
1423 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1424 @param NeedRetry Indicates if needs try again when error happens
1426 @retval EFI_DEVICE_ERROR Indicates that error occurs
1427 @retval EFI_SUCCESS Successfully to detect media
1431 ScsiDiskInquiryDevice (
1432 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1433 OUT BOOLEAN
*NeedRetry
1436 UINT32 InquiryDataLength
;
1437 UINT8 SenseDataLength
;
1438 UINT8 HostAdapterStatus
;
1440 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
1441 UINTN NumberOfSenseKeys
;
1445 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
1446 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
1449 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1450 SenseDataLength
= 0;
1452 Status
= ScsiInquiryCommand (
1453 ScsiDiskDevice
->ScsiIo
,
1459 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
1464 // no need to check HostAdapterStatus and TargetStatus
1466 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1467 ParseInquiryData (ScsiDiskDevice
);
1469 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1471 // Check whether the device supports Block Limits VPD page (0xB0)
1473 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1474 if (SupportedVpdPages
== NULL
) {
1476 return EFI_DEVICE_ERROR
;
1478 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1479 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
1480 SenseDataLength
= 0;
1481 Status
= ScsiInquiryCommandEx (
1482 ScsiDiskDevice
->ScsiIo
,
1488 (VOID
*) SupportedVpdPages
,
1491 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
1493 if (!EFI_ERROR (Status
)) {
1494 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
1495 | SupportedVpdPages
->PageLength1
;
1496 for (Index
= 0; Index
< PageLength
; Index
++) {
1497 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
1503 // Query the Block Limits VPD page
1505 if (Index
< PageLength
) {
1506 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1507 if (BlockLimits
== NULL
) {
1508 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1510 return EFI_DEVICE_ERROR
;
1512 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1513 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
1514 SenseDataLength
= 0;
1515 Status
= ScsiInquiryCommandEx (
1516 ScsiDiskDevice
->ScsiIo
,
1522 (VOID
*) BlockLimits
,
1525 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
1527 if (!EFI_ERROR (Status
)) {
1528 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
1529 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
1530 BlockLimits
->OptimalTransferLengthGranularity1
;
1533 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1537 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1541 if (!EFI_ERROR (Status
)) {
1544 } else if (Status
== EFI_NOT_READY
) {
1546 return EFI_DEVICE_ERROR
;
1548 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1550 return EFI_DEVICE_ERROR
;
1553 // go ahead to check HostAdapterStatus and TargetStatus
1554 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1557 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1558 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1560 return EFI_DEVICE_ERROR
;
1561 } else if (Status
== EFI_DEVICE_ERROR
) {
1563 // reset the scsi channel
1565 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1567 return EFI_DEVICE_ERROR
;
1570 Status
= CheckTargetStatus (TargetStatus
);
1571 if (Status
== EFI_NOT_READY
) {
1573 // reset the scsi device
1575 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1577 return EFI_DEVICE_ERROR
;
1579 } else if (Status
== EFI_DEVICE_ERROR
) {
1581 return EFI_DEVICE_ERROR
;
1585 // if goes here, meant ScsiInquiryCommand() failed.
1586 // if ScsiDiskRequestSenseKeys() succeeds at last,
1587 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1590 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1591 Status
= ScsiDiskRequestSenseKeys (
1598 if (!EFI_ERROR (Status
)) {
1600 return EFI_DEVICE_ERROR
;
1604 return EFI_DEVICE_ERROR
;
1608 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1609 // set *NeedRetry = FALSE to avoid the outside caller try again.
1612 return EFI_DEVICE_ERROR
;
1618 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1619 When Test Unit Ready command encounters any error caused by host adapter or
1620 target, return error without retrieving Sense Keys.
1622 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1623 @param NeedRetry The pointer of flag indicates try again
1624 @param SenseDataArray The pointer of an array of sense data
1625 @param NumberOfSenseKeys The pointer of the number of sense data array
1627 @retval EFI_DEVICE_ERROR Indicates that error occurs
1628 @retval EFI_SUCCESS Successfully to test unit
1632 ScsiDiskTestUnitReady (
1633 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1634 OUT BOOLEAN
*NeedRetry
,
1635 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1636 OUT UINTN
*NumberOfSenseKeys
1640 UINT8 SenseDataLength
;
1641 UINT8 HostAdapterStatus
;
1646 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
1647 *NumberOfSenseKeys
= 0;
1650 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1652 Status
= ScsiTestUnitReadyCommand (
1653 ScsiDiskDevice
->ScsiIo
,
1655 ScsiDiskDevice
->SenseData
,
1661 // no need to check HostAdapterStatus and TargetStatus
1663 if (Status
== EFI_NOT_READY
) {
1665 return EFI_DEVICE_ERROR
;
1667 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1669 return EFI_DEVICE_ERROR
;
1672 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1675 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1676 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1678 return EFI_DEVICE_ERROR
;
1680 } else if (Status
== EFI_DEVICE_ERROR
) {
1682 // reset the scsi channel
1684 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1686 return EFI_DEVICE_ERROR
;
1689 Status
= CheckTargetStatus (TargetStatus
);
1690 if (Status
== EFI_NOT_READY
) {
1692 // reset the scsi device
1694 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1696 return EFI_DEVICE_ERROR
;
1698 } else if (Status
== EFI_DEVICE_ERROR
) {
1700 return EFI_DEVICE_ERROR
;
1703 if (SenseDataLength
!= 0) {
1704 *NumberOfSenseKeys
= SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
);
1705 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1710 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1711 Status
= ScsiDiskRequestSenseKeys (
1718 if (!EFI_ERROR (Status
)) {
1723 return EFI_DEVICE_ERROR
;
1727 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1728 // set *NeedRetry = FALSE to avoid the outside caller try again.
1731 return EFI_DEVICE_ERROR
;
1735 Parsing Sense Keys which got from request sense command.
1737 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1738 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1739 @param NumberOfSenseKeys The number of sense key
1740 @param Action The pointer of action which indicates what is need to do next
1742 @retval EFI_DEVICE_ERROR Indicates that error occurs
1743 @retval EFI_SUCCESS Successfully to complete the parsing
1747 DetectMediaParsingSenseKeys (
1748 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1749 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1750 IN UINTN NumberOfSenseKeys
,
1757 // Default is to read capacity, unless..
1759 *Action
= ACTION_READ_CAPACITY
;
1761 if (NumberOfSenseKeys
== 0) {
1762 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1763 *Action
= ACTION_NO_ACTION
;
1768 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1770 // No Sense Key returned from last submitted command
1772 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1773 *Action
= ACTION_NO_ACTION
;
1778 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1779 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1780 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1781 *Action
= ACTION_NO_ACTION
;
1782 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
1786 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1787 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1788 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
1792 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
1793 *Action
= ACTION_RETRY_COMMAND_LATER
;
1794 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
1798 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1799 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
1800 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1801 return EFI_DEVICE_ERROR
;
1804 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1805 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
1806 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1807 return EFI_DEVICE_ERROR
;
1810 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1812 *Action
= ACTION_RETRY_COMMAND_LATER
;
1813 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
1816 *Action
= ACTION_NO_ACTION
;
1817 return EFI_DEVICE_ERROR
;
1820 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1821 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
1827 Send read capacity command to device and get the device parameter.
1829 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1830 @param NeedRetry The pointer of flag indicates if need a retry
1831 @param SenseDataArray The pointer of an array of sense data
1832 @param NumberOfSenseKeys The number of sense key
1834 @retval EFI_DEVICE_ERROR Indicates that error occurs
1835 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1839 ScsiDiskReadCapacity (
1840 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1841 OUT BOOLEAN
*NeedRetry
,
1842 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1843 OUT UINTN
*NumberOfSenseKeys
1846 UINT8 HostAdapterStatus
;
1848 EFI_STATUS CommandStatus
;
1852 UINT8 SenseDataLength
;
1853 UINT32 DataLength10
;
1854 UINT32 DataLength16
;
1855 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
1856 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
1858 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1859 if (CapacityData10
== NULL
) {
1861 return EFI_DEVICE_ERROR
;
1863 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1864 if (CapacityData16
== NULL
) {
1865 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1867 return EFI_DEVICE_ERROR
;
1870 SenseDataLength
= 0;
1871 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1872 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1873 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1874 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1876 *NumberOfSenseKeys
= 0;
1880 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1881 // 16 byte command should be used to access large hard disk >2TB
1883 CommandStatus
= ScsiReadCapacityCommand (
1884 ScsiDiskDevice
->ScsiIo
,
1890 (VOID
*) CapacityData10
,
1895 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1896 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
1897 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff)) {
1899 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1901 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1903 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1904 // and LowestAlignedLba
1906 CommandStatus
= ScsiReadCapacity16Command (
1907 ScsiDiskDevice
->ScsiIo
,
1913 (VOID
*) CapacityData16
,
1920 // no need to check HostAdapterStatus and TargetStatus
1922 if (CommandStatus
== EFI_SUCCESS
) {
1923 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
1924 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1925 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1929 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1930 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1932 if (CommandStatus
== EFI_NOT_READY
) {
1934 return EFI_DEVICE_ERROR
;
1935 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1937 return EFI_DEVICE_ERROR
;
1941 // go ahead to check HostAdapterStatus and TargetStatus
1942 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1945 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1946 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1948 return EFI_DEVICE_ERROR
;
1950 } else if (Status
== EFI_DEVICE_ERROR
) {
1952 // reset the scsi channel
1954 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1956 return EFI_DEVICE_ERROR
;
1959 Status
= CheckTargetStatus (TargetStatus
);
1960 if (Status
== EFI_NOT_READY
) {
1962 // reset the scsi device
1964 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1966 return EFI_DEVICE_ERROR
;
1968 } else if (Status
== EFI_DEVICE_ERROR
) {
1970 return EFI_DEVICE_ERROR
;
1974 // if goes here, meant ScsiReadCapacityCommand() failed.
1975 // if ScsiDiskRequestSenseKeys() succeeds at last,
1976 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1979 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1981 Status
= ScsiDiskRequestSenseKeys (
1988 if (!EFI_ERROR (Status
)) {
1993 return EFI_DEVICE_ERROR
;
1997 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1998 // set *NeedRetry = FALSE to avoid the outside caller try again.
2001 return EFI_DEVICE_ERROR
;
2005 Check the HostAdapter status and re-interpret it in EFI_STATUS.
2007 @param HostAdapterStatus Host Adapter status
2009 @retval EFI_SUCCESS Host adapter is OK.
2010 @retval EFI_TIMEOUT Timeout.
2011 @retval EFI_NOT_READY Adapter NOT ready.
2012 @retval EFI_DEVICE_ERROR Adapter device error.
2016 CheckHostAdapterStatus (
2017 IN UINT8 HostAdapterStatus
2020 switch (HostAdapterStatus
) {
2021 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
2024 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
2025 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
2026 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
2029 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
2030 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
2031 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
2032 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
2033 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
2034 return EFI_NOT_READY
;
2036 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
2037 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
2038 return EFI_DEVICE_ERROR
;
2047 Check the target status and re-interpret it in EFI_STATUS.
2049 @param TargetStatus Target status
2051 @retval EFI_NOT_READY Device is NOT ready.
2052 @retval EFI_DEVICE_ERROR
2058 IN UINT8 TargetStatus
2061 switch (TargetStatus
) {
2062 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
2063 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
2064 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
2067 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
2068 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
2069 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
2070 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
2071 return EFI_NOT_READY
;
2073 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
2074 return EFI_DEVICE_ERROR
;
2083 Retrieve all sense keys from the device.
2085 When encountering error during the process, if retrieve sense keys before
2086 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
2087 and NeedRetry set to FALSE; otherwize, return the proper return status.
2089 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2090 @param NeedRetry The pointer of flag indicates if need a retry
2091 @param SenseDataArray The pointer of an array of sense data
2092 @param NumberOfSenseKeys The number of sense key
2093 @param AskResetIfError The flag indicates if need reset when error occurs
2095 @retval EFI_DEVICE_ERROR Indicates that error occurs
2096 @retval EFI_SUCCESS Successfully to request sense key
2100 ScsiDiskRequestSenseKeys (
2101 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2102 OUT BOOLEAN
*NeedRetry
,
2103 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2104 OUT UINTN
*NumberOfSenseKeys
,
2105 IN BOOLEAN AskResetIfError
2108 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
2109 UINT8 SenseDataLength
;
2112 EFI_STATUS FallStatus
;
2113 UINT8 HostAdapterStatus
;
2116 FallStatus
= EFI_SUCCESS
;
2117 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
2120 ScsiDiskDevice
->SenseData
,
2121 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
2124 *NumberOfSenseKeys
= 0;
2125 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2126 Status
= EFI_SUCCESS
;
2127 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
2128 if (PtrSenseData
== NULL
) {
2129 return EFI_DEVICE_ERROR
;
2132 for (SenseReq
= TRUE
; SenseReq
;) {
2133 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2134 Status
= ScsiRequestSenseCommand (
2135 ScsiDiskDevice
->ScsiIo
,
2142 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
2143 FallStatus
= EFI_SUCCESS
;
2145 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2147 FallStatus
= EFI_DEVICE_ERROR
;
2149 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2151 FallStatus
= EFI_DEVICE_ERROR
;
2153 } else if (Status
== EFI_DEVICE_ERROR
) {
2154 if (AskResetIfError
) {
2155 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2158 FallStatus
= EFI_DEVICE_ERROR
;
2161 if (EFI_ERROR (FallStatus
)) {
2162 if (*NumberOfSenseKeys
!= 0) {
2164 Status
= EFI_SUCCESS
;
2167 Status
= EFI_DEVICE_ERROR
;
2172 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
2173 (*NumberOfSenseKeys
) += 1;
2176 // no more sense key or number of sense keys exceeds predefined,
2179 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
2180 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
2186 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2192 Get information from media read capacity command.
2194 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2195 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
2196 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
2201 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2202 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
2203 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
2208 if (!ScsiDiskDevice
->Cdb16Byte
) {
2209 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
2210 (Capacity10
->LastLba2
<< 16) |
2211 (Capacity10
->LastLba1
<< 8) |
2212 Capacity10
->LastLba0
;
2214 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
2215 (Capacity10
->BlockSize2
<< 16) |
2216 (Capacity10
->BlockSize1
<< 8) |
2217 Capacity10
->BlockSize0
;
2218 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
2219 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
2221 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2222 *Ptr
++ = Capacity16
->LastLba0
;
2223 *Ptr
++ = Capacity16
->LastLba1
;
2224 *Ptr
++ = Capacity16
->LastLba2
;
2225 *Ptr
++ = Capacity16
->LastLba3
;
2226 *Ptr
++ = Capacity16
->LastLba4
;
2227 *Ptr
++ = Capacity16
->LastLba5
;
2228 *Ptr
++ = Capacity16
->LastLba6
;
2229 *Ptr
= Capacity16
->LastLba7
;
2231 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
2232 (Capacity16
->BlockSize2
<< 16) |
2233 (Capacity16
->BlockSize1
<< 8) |
2234 Capacity16
->BlockSize0
;
2236 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
2237 Capacity16
->LowestAlignLogic1
;
2238 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
2241 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
2247 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2252 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2255 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
2256 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
2260 Read sector from SCSI Disk.
2262 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2263 @param Buffer The buffer to fill in the read out data
2264 @param Lba Logic block address
2265 @param NumberOfBlocks The number of blocks to read
2267 @retval EFI_DEVICE_ERROR Indicates a device error.
2268 @retval EFI_SUCCESS Operation is successful.
2272 ScsiDiskReadSectors (
2273 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2276 IN UINTN NumberOfBlocks
2279 UINTN BlocksRemaining
;
2285 UINT32 NextSectorCount
;
2292 Status
= EFI_SUCCESS
;
2294 BlocksRemaining
= NumberOfBlocks
;
2295 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2298 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2300 if (!ScsiDiskDevice
->Cdb16Byte
) {
2303 MaxBlock
= 0xFFFFFFFF;
2308 while (BlocksRemaining
> 0) {
2310 if (BlocksRemaining
<= MaxBlock
) {
2311 if (!ScsiDiskDevice
->Cdb16Byte
) {
2312 SectorCount
= (UINT16
) BlocksRemaining
;
2314 SectorCount
= (UINT32
) BlocksRemaining
;
2317 SectorCount
= MaxBlock
;
2320 ByteCount
= SectorCount
* BlockSize
;
2322 // |------------------------|-----------------|------------------|-----------------|
2323 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2324 // |------------------------|-----------------|------------------|-----------------|
2325 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2326 // |------------------------|-----------------|------------------|-----------------|
2327 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2328 // |------------------------|-----------------|------------------|-----------------|
2329 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2330 // |------------------------|-----------------|------------------|-----------------|
2331 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2332 // |------------------------|-----------------|------------------|-----------------|
2333 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2334 // |------------------------|-----------------|------------------|-----------------|
2335 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2336 // |------------------------|-----------------|------------------|-----------------|
2337 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2338 // |------------------------|-----------------|------------------|-----------------|
2339 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2340 // |------------------------|-----------------|------------------|-----------------|
2341 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2342 // |------------------------|-----------------|------------------|-----------------|
2343 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2344 // |------------------------|-----------------|------------------|-----------------|
2346 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2347 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2348 // From the above table, we could know 2.1Mbytes per second is lowest one.
2349 // The timout value is rounded up to nearest integar and here an additional 30s is added
2350 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2351 // commands in the Standby/Idle mode.
2353 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2356 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2357 if (!ScsiDiskDevice
->Cdb16Byte
) {
2358 Status
= ScsiDiskRead10 (
2368 Status
= ScsiDiskRead16 (
2378 if (!EFI_ERROR (Status
)) {
2383 return EFI_DEVICE_ERROR
;
2387 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
2388 // lowered ByteCount on output, we must make sure that we lower
2389 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2390 // it is invalid to request more sectors in the CDB than the entire
2391 // transfer (ie. ByteCount) can carry.
2393 // In addition, ByteCount is only expected to go down, or stay unchaged.
2394 // Therefore we don't need to update Timeout: the original timeout should
2395 // accommodate shorter transfers too.
2397 NextSectorCount
= ByteCount
/ BlockSize
;
2398 if (NextSectorCount
< SectorCount
) {
2399 SectorCount
= NextSectorCount
;
2401 // Account for any rounding down.
2403 ByteCount
= SectorCount
* BlockSize
;
2407 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2408 return EFI_DEVICE_ERROR
;
2412 // actual transferred sectors
2414 SectorCount
= ByteCount
/ BlockSize
;
2417 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2418 BlocksRemaining
-= SectorCount
;
2425 Write sector to SCSI Disk.
2427 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2428 @param Buffer The buffer of data to be written into SCSI Disk
2429 @param Lba Logic block address
2430 @param NumberOfBlocks The number of blocks to read
2432 @retval EFI_DEVICE_ERROR Indicates a device error.
2433 @retval EFI_SUCCESS Operation is successful.
2437 ScsiDiskWriteSectors (
2438 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2441 IN UINTN NumberOfBlocks
2444 UINTN BlocksRemaining
;
2450 UINT32 NextSectorCount
;
2457 Status
= EFI_SUCCESS
;
2459 BlocksRemaining
= NumberOfBlocks
;
2460 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2463 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2465 if (!ScsiDiskDevice
->Cdb16Byte
) {
2468 MaxBlock
= 0xFFFFFFFF;
2473 while (BlocksRemaining
> 0) {
2475 if (BlocksRemaining
<= MaxBlock
) {
2476 if (!ScsiDiskDevice
->Cdb16Byte
) {
2477 SectorCount
= (UINT16
) BlocksRemaining
;
2479 SectorCount
= (UINT32
) BlocksRemaining
;
2482 SectorCount
= MaxBlock
;
2485 ByteCount
= SectorCount
* BlockSize
;
2487 // |------------------------|-----------------|------------------|-----------------|
2488 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2489 // |------------------------|-----------------|------------------|-----------------|
2490 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2491 // |------------------------|-----------------|------------------|-----------------|
2492 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2493 // |------------------------|-----------------|------------------|-----------------|
2494 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2495 // |------------------------|-----------------|------------------|-----------------|
2496 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2497 // |------------------------|-----------------|------------------|-----------------|
2498 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2499 // |------------------------|-----------------|------------------|-----------------|
2500 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2501 // |------------------------|-----------------|------------------|-----------------|
2502 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2503 // |------------------------|-----------------|------------------|-----------------|
2504 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2505 // |------------------------|-----------------|------------------|-----------------|
2506 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2507 // |------------------------|-----------------|------------------|-----------------|
2508 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2509 // |------------------------|-----------------|------------------|-----------------|
2511 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2512 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2513 // From the above table, we could know 2.1Mbytes per second is lowest one.
2514 // The timout value is rounded up to nearest integar and here an additional 30s is added
2515 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2516 // commands in the Standby/Idle mode.
2518 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2520 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2521 if (!ScsiDiskDevice
->Cdb16Byte
) {
2522 Status
= ScsiDiskWrite10 (
2532 Status
= ScsiDiskWrite16 (
2542 if (!EFI_ERROR (Status
)) {
2547 return EFI_DEVICE_ERROR
;
2551 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
2552 // has lowered ByteCount on output, we must make sure that we lower
2553 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2554 // it is invalid to request more sectors in the CDB than the entire
2555 // transfer (ie. ByteCount) can carry.
2557 // In addition, ByteCount is only expected to go down, or stay unchaged.
2558 // Therefore we don't need to update Timeout: the original timeout should
2559 // accommodate shorter transfers too.
2561 NextSectorCount
= ByteCount
/ BlockSize
;
2562 if (NextSectorCount
< SectorCount
) {
2563 SectorCount
= NextSectorCount
;
2565 // Account for any rounding down.
2567 ByteCount
= SectorCount
* BlockSize
;
2571 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2572 return EFI_DEVICE_ERROR
;
2575 // actual transferred sectors
2577 SectorCount
= ByteCount
/ BlockSize
;
2580 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2581 BlocksRemaining
-= SectorCount
;
2588 Asynchronously read sector from SCSI Disk.
2590 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2591 @param Buffer The buffer to fill in the read out data.
2592 @param Lba Logic block address.
2593 @param NumberOfBlocks The number of blocks to read.
2594 @param Token A pointer to the token associated with the
2595 non-blocking read request.
2597 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
2598 @retval EFI_DEVICE_ERROR Indicates a device error.
2599 @retval EFI_SUCCESS Operation is successful.
2603 ScsiDiskAsyncReadSectors (
2604 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2607 IN UINTN NumberOfBlocks
,
2608 IN EFI_BLOCK_IO2_TOKEN
*Token
2611 UINTN BlocksRemaining
;
2618 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
2622 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
2623 return EFI_INVALID_PARAMETER
;
2626 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
2627 if (BlkIo2Req
== NULL
) {
2628 return EFI_OUT_OF_RESOURCES
;
2631 BlkIo2Req
->Token
= Token
;
2633 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2634 InsertTailList (&ScsiDiskDevice
->BlkIo2Queue
, &BlkIo2Req
->Link
);
2635 gBS
->RestoreTPL (OldTpl
);
2637 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
2639 Status
= EFI_SUCCESS
;
2641 BlocksRemaining
= NumberOfBlocks
;
2642 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2645 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2648 if (!ScsiDiskDevice
->Cdb16Byte
) {
2651 MaxBlock
= 0xFFFFFFFF;
2656 while (BlocksRemaining
> 0) {
2658 if (BlocksRemaining
<= MaxBlock
) {
2659 if (!ScsiDiskDevice
->Cdb16Byte
) {
2660 SectorCount
= (UINT16
) BlocksRemaining
;
2662 SectorCount
= (UINT32
) BlocksRemaining
;
2665 SectorCount
= MaxBlock
;
2668 ByteCount
= SectorCount
* BlockSize
;
2670 // |------------------------|-----------------|------------------|-----------------|
2671 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2672 // |------------------------|-----------------|------------------|-----------------|
2673 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2674 // |------------------------|-----------------|------------------|-----------------|
2675 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2676 // |------------------------|-----------------|------------------|-----------------|
2677 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2678 // |------------------------|-----------------|------------------|-----------------|
2679 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2680 // |------------------------|-----------------|------------------|-----------------|
2681 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2682 // |------------------------|-----------------|------------------|-----------------|
2683 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2684 // |------------------------|-----------------|------------------|-----------------|
2685 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2686 // |------------------------|-----------------|------------------|-----------------|
2687 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2688 // |------------------------|-----------------|------------------|-----------------|
2689 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2690 // |------------------------|-----------------|------------------|-----------------|
2691 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2692 // |------------------------|-----------------|------------------|-----------------|
2694 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2695 // we have to use the lowest transfer rate to calculate the possible
2696 // maximum timeout value for each operation.
2697 // From the above table, we could know 2.1Mbytes per second is lowest one.
2698 // The timout value is rounded up to nearest integar and here an additional
2699 // 30s is added to follow ATA spec in which it mentioned that the device
2700 // may take up to 30s to respond commands in the Standby/Idle mode.
2702 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2704 if (!ScsiDiskDevice
->Cdb16Byte
) {
2705 Status
= ScsiDiskAsyncRead10 (
2717 Status
= ScsiDiskAsyncRead16 (
2729 if (EFI_ERROR (Status
)) {
2731 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
2732 // length of a SCSI I/O command is too large.
2733 // In this case, we retry sending the SCSI command with a data length
2734 // half of its previous value.
2736 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
2737 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
2738 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
2743 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2744 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2746 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
2747 // SCSI sub-task running. Otherwise, it will be freed in the callback
2748 // function ScsiDiskNotify().
2750 RemoveEntryList (&BlkIo2Req
->Link
);
2751 FreePool (BlkIo2Req
);
2753 gBS
->RestoreTPL (OldTpl
);
2756 // It is safe to return error status to the caller, since there is no
2757 // previous SCSI sub-task executing.
2759 Status
= EFI_DEVICE_ERROR
;
2762 gBS
->RestoreTPL (OldTpl
);
2765 // There are previous SCSI commands still running, EFI_SUCCESS should
2766 // be returned to make sure that the caller does not free resources
2767 // still using by these SCSI commands.
2769 Status
= EFI_SUCCESS
;
2775 // Sectors submitted for transfer
2777 SectorCount
= ByteCount
/ BlockSize
;
2780 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2781 BlocksRemaining
-= SectorCount
;
2784 Status
= EFI_SUCCESS
;
2787 if (BlkIo2Req
!= NULL
) {
2788 BlkIo2Req
->LastScsiRW
= TRUE
;
2790 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2791 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2792 RemoveEntryList (&BlkIo2Req
->Link
);
2793 FreePool (BlkIo2Req
);
2796 gBS
->SignalEvent (Token
->Event
);
2798 gBS
->RestoreTPL (OldTpl
);
2805 Asynchronously write sector to SCSI Disk.
2807 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2808 @param Buffer The buffer of data to be written into SCSI Disk.
2809 @param Lba Logic block address.
2810 @param NumberOfBlocks The number of blocks to read.
2811 @param Token A pointer to the token associated with the
2812 non-blocking read request.
2814 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
2815 @retval EFI_DEVICE_ERROR Indicates a device error.
2816 @retval EFI_SUCCESS Operation is successful.
2820 ScsiDiskAsyncWriteSectors (
2821 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2824 IN UINTN NumberOfBlocks
,
2825 IN EFI_BLOCK_IO2_TOKEN
*Token
2828 UINTN BlocksRemaining
;
2835 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
2839 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
2840 return EFI_INVALID_PARAMETER
;
2843 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
2844 if (BlkIo2Req
== NULL
) {
2845 return EFI_OUT_OF_RESOURCES
;
2848 BlkIo2Req
->Token
= Token
;
2850 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2851 InsertTailList (&ScsiDiskDevice
->BlkIo2Queue
, &BlkIo2Req
->Link
);
2852 gBS
->RestoreTPL (OldTpl
);
2854 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
2856 Status
= EFI_SUCCESS
;
2858 BlocksRemaining
= NumberOfBlocks
;
2859 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2862 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2865 if (!ScsiDiskDevice
->Cdb16Byte
) {
2868 MaxBlock
= 0xFFFFFFFF;
2873 while (BlocksRemaining
> 0) {
2875 if (BlocksRemaining
<= MaxBlock
) {
2876 if (!ScsiDiskDevice
->Cdb16Byte
) {
2877 SectorCount
= (UINT16
) BlocksRemaining
;
2879 SectorCount
= (UINT32
) BlocksRemaining
;
2882 SectorCount
= MaxBlock
;
2885 ByteCount
= SectorCount
* BlockSize
;
2887 // |------------------------|-----------------|------------------|-----------------|
2888 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2889 // |------------------------|-----------------|------------------|-----------------|
2890 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2891 // |------------------------|-----------------|------------------|-----------------|
2892 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2893 // |------------------------|-----------------|------------------|-----------------|
2894 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2895 // |------------------------|-----------------|------------------|-----------------|
2896 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2897 // |------------------------|-----------------|------------------|-----------------|
2898 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2899 // |------------------------|-----------------|------------------|-----------------|
2900 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2901 // |------------------------|-----------------|------------------|-----------------|
2902 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2903 // |------------------------|-----------------|------------------|-----------------|
2904 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2905 // |------------------------|-----------------|------------------|-----------------|
2906 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2907 // |------------------------|-----------------|------------------|-----------------|
2908 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2909 // |------------------------|-----------------|------------------|-----------------|
2911 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2912 // we have to use the lowest transfer rate to calculate the possible
2913 // maximum timeout value for each operation.
2914 // From the above table, we could know 2.1Mbytes per second is lowest one.
2915 // The timout value is rounded up to nearest integar and here an additional
2916 // 30s is added to follow ATA spec in which it mentioned that the device
2917 // may take up to 30s to respond commands in the Standby/Idle mode.
2919 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2921 if (!ScsiDiskDevice
->Cdb16Byte
) {
2922 Status
= ScsiDiskAsyncWrite10 (
2934 Status
= ScsiDiskAsyncWrite16 (
2946 if (EFI_ERROR (Status
)) {
2948 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
2949 // length of a SCSI I/O command is too large.
2950 // In this case, we retry sending the SCSI command with a data length
2951 // half of its previous value.
2953 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
2954 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
2955 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
2960 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2961 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2963 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
2964 // SCSI sub-task running. Otherwise, it will be freed in the callback
2965 // function ScsiDiskNotify().
2967 RemoveEntryList (&BlkIo2Req
->Link
);
2968 FreePool (BlkIo2Req
);
2970 gBS
->RestoreTPL (OldTpl
);
2973 // It is safe to return error status to the caller, since there is no
2974 // previous SCSI sub-task executing.
2976 Status
= EFI_DEVICE_ERROR
;
2979 gBS
->RestoreTPL (OldTpl
);
2982 // There are previous SCSI commands still running, EFI_SUCCESS should
2983 // be returned to make sure that the caller does not free resources
2984 // still using by these SCSI commands.
2986 Status
= EFI_SUCCESS
;
2992 // Sectors submitted for transfer
2994 SectorCount
= ByteCount
/ BlockSize
;
2997 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2998 BlocksRemaining
-= SectorCount
;
3001 Status
= EFI_SUCCESS
;
3004 if (BlkIo2Req
!= NULL
) {
3005 BlkIo2Req
->LastScsiRW
= TRUE
;
3007 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3008 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3009 RemoveEntryList (&BlkIo2Req
->Link
);
3010 FreePool (BlkIo2Req
);
3013 gBS
->SignalEvent (Token
->Event
);
3015 gBS
->RestoreTPL (OldTpl
);
3023 Submit Read(10) command.
3025 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3026 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3027 @param Timeout The time to complete the command
3028 @param DataBuffer The buffer to fill with the read out data
3029 @param DataLength The length of buffer
3030 @param StartLba The start logic block address
3031 @param SectorCount The number of blocks to read
3033 @return EFI_STATUS is returned by calling ScsiRead10Command().
3037 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3038 OUT BOOLEAN
*NeedRetry
,
3040 OUT UINT8
*DataBuffer
,
3041 IN OUT UINT32
*DataLength
,
3043 IN UINT32 SectorCount
3046 UINT8 SenseDataLength
;
3048 EFI_STATUS ReturnStatus
;
3049 UINT8 HostAdapterStatus
;
3054 // Implement a backoff algorithem to resolve some compatibility issues that
3055 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3056 // big data in a single operation.
3057 // This algorithem will at first try to execute original request. If the request fails
3058 // with media error sense data or else, it will reduce the transfer length to half and
3059 // try again till the operation succeeds or fails with one sector transfer length.
3063 Action
= ACTION_NO_ACTION
;
3064 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3065 ReturnStatus
= ScsiRead10Command (
3066 ScsiDiskDevice
->ScsiIo
,
3068 ScsiDiskDevice
->SenseData
,
3078 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3080 return EFI_DEVICE_ERROR
;
3081 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3083 return ReturnStatus
;
3087 // go ahead to check HostAdapterStatus and TargetStatus
3088 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3090 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3091 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3093 return EFI_DEVICE_ERROR
;
3094 } else if (Status
== EFI_DEVICE_ERROR
) {
3096 // reset the scsi channel
3098 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3100 return EFI_DEVICE_ERROR
;
3103 Status
= CheckTargetStatus (TargetStatus
);
3104 if (Status
== EFI_NOT_READY
) {
3106 // reset the scsi device
3108 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3110 return EFI_DEVICE_ERROR
;
3111 } else if (Status
== EFI_DEVICE_ERROR
) {
3113 return EFI_DEVICE_ERROR
;
3116 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3117 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
3118 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3119 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3121 return EFI_DEVICE_ERROR
;
3122 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3123 if (SectorCount
<= 1) {
3125 // Jump out if the operation still fails with one sector transfer length.
3128 return EFI_DEVICE_ERROR
;
3131 // Try again with half length if the sense data shows we need to retry.
3134 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3138 return EFI_DEVICE_ERROR
;
3142 return ReturnStatus
;
3147 Submit Write(10) Command.
3149 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3150 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3151 @param Timeout The time to complete the command
3152 @param DataBuffer The buffer to fill with the read out data
3153 @param DataLength The length of buffer
3154 @param StartLba The start logic block address
3155 @param SectorCount The number of blocks to write
3157 @return EFI_STATUS is returned by calling ScsiWrite10Command().
3162 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3163 OUT BOOLEAN
*NeedRetry
,
3165 IN UINT8
*DataBuffer
,
3166 IN OUT UINT32
*DataLength
,
3168 IN UINT32 SectorCount
3172 EFI_STATUS ReturnStatus
;
3173 UINT8 SenseDataLength
;
3174 UINT8 HostAdapterStatus
;
3179 // Implement a backoff algorithem to resolve some compatibility issues that
3180 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3181 // big data in a single operation.
3182 // This algorithem will at first try to execute original request. If the request fails
3183 // with media error sense data or else, it will reduce the transfer length to half and
3184 // try again till the operation succeeds or fails with one sector transfer length.
3188 Action
= ACTION_NO_ACTION
;
3189 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3190 ReturnStatus
= ScsiWrite10Command (
3191 ScsiDiskDevice
->ScsiIo
,
3193 ScsiDiskDevice
->SenseData
,
3202 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3204 return EFI_DEVICE_ERROR
;
3205 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3207 return ReturnStatus
;
3211 // go ahead to check HostAdapterStatus and TargetStatus
3212 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3214 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3215 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3217 return EFI_DEVICE_ERROR
;
3218 } else if (Status
== EFI_DEVICE_ERROR
) {
3220 // reset the scsi channel
3222 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3224 return EFI_DEVICE_ERROR
;
3227 Status
= CheckTargetStatus (TargetStatus
);
3228 if (Status
== EFI_NOT_READY
) {
3230 // reset the scsi device
3232 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3234 return EFI_DEVICE_ERROR
;
3235 } else if (Status
== EFI_DEVICE_ERROR
) {
3237 return EFI_DEVICE_ERROR
;
3240 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3241 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
3242 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3243 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3245 return EFI_DEVICE_ERROR
;
3246 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3247 if (SectorCount
<= 1) {
3249 // Jump out if the operation still fails with one sector transfer length.
3252 return EFI_DEVICE_ERROR
;
3255 // Try again with half length if the sense data shows we need to retry.
3258 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3262 return EFI_DEVICE_ERROR
;
3266 return ReturnStatus
;
3271 Submit Read(16) command.
3273 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3274 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3275 @param Timeout The time to complete the command
3276 @param DataBuffer The buffer to fill with the read out data
3277 @param DataLength The length of buffer
3278 @param StartLba The start logic block address
3279 @param SectorCount The number of blocks to read
3281 @return EFI_STATUS is returned by calling ScsiRead16Command().
3285 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3286 OUT BOOLEAN
*NeedRetry
,
3288 OUT UINT8
*DataBuffer
,
3289 IN OUT UINT32
*DataLength
,
3291 IN UINT32 SectorCount
3294 UINT8 SenseDataLength
;
3296 EFI_STATUS ReturnStatus
;
3297 UINT8 HostAdapterStatus
;
3302 // Implement a backoff algorithem to resolve some compatibility issues that
3303 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3304 // big data in a single operation.
3305 // This algorithem will at first try to execute original request. If the request fails
3306 // with media error sense data or else, it will reduce the transfer length to half and
3307 // try again till the operation succeeds or fails with one sector transfer length.
3311 Action
= ACTION_NO_ACTION
;
3312 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3313 ReturnStatus
= ScsiRead16Command (
3314 ScsiDiskDevice
->ScsiIo
,
3316 ScsiDiskDevice
->SenseData
,
3325 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3327 return EFI_DEVICE_ERROR
;
3328 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3330 return ReturnStatus
;
3334 // go ahead to check HostAdapterStatus and TargetStatus
3335 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3337 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3338 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3340 return EFI_DEVICE_ERROR
;
3341 } else if (Status
== EFI_DEVICE_ERROR
) {
3343 // reset the scsi channel
3345 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3347 return EFI_DEVICE_ERROR
;
3350 Status
= CheckTargetStatus (TargetStatus
);
3351 if (Status
== EFI_NOT_READY
) {
3353 // reset the scsi device
3355 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3357 return EFI_DEVICE_ERROR
;
3358 } else if (Status
== EFI_DEVICE_ERROR
) {
3360 return EFI_DEVICE_ERROR
;
3363 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3364 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
3365 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3366 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3368 return EFI_DEVICE_ERROR
;
3369 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3370 if (SectorCount
<= 1) {
3372 // Jump out if the operation still fails with one sector transfer length.
3375 return EFI_DEVICE_ERROR
;
3378 // Try again with half length if the sense data shows we need to retry.
3381 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3385 return EFI_DEVICE_ERROR
;
3389 return ReturnStatus
;
3394 Submit Write(16) Command.
3396 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3397 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3398 @param Timeout The time to complete the command
3399 @param DataBuffer The buffer to fill with the read out data
3400 @param DataLength The length of buffer
3401 @param StartLba The start logic block address
3402 @param SectorCount The number of blocks to write
3404 @return EFI_STATUS is returned by calling ScsiWrite16Command().
3409 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3410 OUT BOOLEAN
*NeedRetry
,
3412 IN UINT8
*DataBuffer
,
3413 IN OUT UINT32
*DataLength
,
3415 IN UINT32 SectorCount
3419 EFI_STATUS ReturnStatus
;
3420 UINT8 SenseDataLength
;
3421 UINT8 HostAdapterStatus
;
3426 // Implement a backoff algorithem to resolve some compatibility issues that
3427 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3428 // big data in a single operation.
3429 // This algorithem will at first try to execute original request. If the request fails
3430 // with media error sense data or else, it will reduce the transfer length to half and
3431 // try again till the operation succeeds or fails with one sector transfer length.
3435 Action
= ACTION_NO_ACTION
;
3436 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3437 ReturnStatus
= ScsiWrite16Command (
3438 ScsiDiskDevice
->ScsiIo
,
3440 ScsiDiskDevice
->SenseData
,
3449 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3451 return EFI_DEVICE_ERROR
;
3452 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3454 return ReturnStatus
;
3458 // go ahead to check HostAdapterStatus and TargetStatus
3459 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3461 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3462 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3464 return EFI_DEVICE_ERROR
;
3465 } else if (Status
== EFI_DEVICE_ERROR
) {
3467 // reset the scsi channel
3469 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3471 return EFI_DEVICE_ERROR
;
3474 Status
= CheckTargetStatus (TargetStatus
);
3475 if (Status
== EFI_NOT_READY
) {
3477 // reset the scsi device
3479 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3481 return EFI_DEVICE_ERROR
;
3482 } else if (Status
== EFI_DEVICE_ERROR
) {
3484 return EFI_DEVICE_ERROR
;
3487 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3488 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
3489 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3490 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3492 return EFI_DEVICE_ERROR
;
3493 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3494 if (SectorCount
<= 1) {
3496 // Jump out if the operation still fails with one sector transfer length.
3499 return EFI_DEVICE_ERROR
;
3502 // Try again with half length if the sense data shows we need to retry.
3505 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3509 return EFI_DEVICE_ERROR
;
3513 return ReturnStatus
;
3518 Internal helper notify function in which determine whether retry of a SCSI
3519 Read/Write command is needed and signal the event passed from Block I/O(2) if
3520 the SCSI I/O operation completes.
3522 @param Event The instance of EFI_EVENT.
3523 @param Context The parameter passed in.
3534 SCSI_ASYNC_RW_REQUEST
*Request
;
3535 SCSI_DISK_DEV
*ScsiDiskDevice
;
3536 EFI_BLOCK_IO2_TOKEN
*Token
;
3538 UINT32 OldDataLength
;
3539 UINT32 OldSectorCount
;
3542 gBS
->CloseEvent (Event
);
3544 Request
= (SCSI_ASYNC_RW_REQUEST
*) Context
;
3545 ScsiDiskDevice
= Request
->ScsiDiskDevice
;
3546 Token
= Request
->BlkIo2Req
->Token
;
3547 OldDataLength
= Request
->DataLength
;
3548 OldSectorCount
= Request
->SectorCount
;
3552 // If previous sub-tasks already fails, no need to process this sub-task.
3554 if (Token
->TransactionStatus
!= EFI_SUCCESS
) {
3559 // Check HostAdapterStatus and TargetStatus
3560 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3562 Status
= CheckHostAdapterStatus (Request
->HostAdapterStatus
);
3563 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3564 if (++Request
->TimesRetry
> MaxRetry
) {
3565 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3570 } else if (Status
== EFI_DEVICE_ERROR
) {
3572 // reset the scsi channel
3574 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3575 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3579 Status
= CheckTargetStatus (Request
->TargetStatus
);
3580 if (Status
== EFI_NOT_READY
) {
3582 // reset the scsi device
3584 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3585 if (++Request
->TimesRetry
> MaxRetry
) {
3586 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3591 } else if (Status
== EFI_DEVICE_ERROR
) {
3592 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3596 if (Request
->TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) {
3597 DEBUG ((EFI_D_ERROR
, "ScsiDiskNotify: Check Condition happened!\n"));
3599 Status
= DetectMediaParsingSenseKeys (
3602 Request
->SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
),
3605 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3606 if (++Request
->TimesRetry
> MaxRetry
) {
3607 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3612 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3613 if (Request
->SectorCount
<= 1) {
3615 // Jump out if the operation still fails with one sector transfer
3618 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3622 // Try again with two half length request if the sense data shows we need
3625 Request
->SectorCount
>>= 1;
3626 Request
->DataLength
= Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3627 Request
->TimesRetry
= 0;
3631 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3637 // This sub-task succeeds, no need to retry.
3642 if (Request
->InBuffer
!= NULL
) {
3644 // SCSI read command
3646 if (!ScsiDiskDevice
->Cdb16Byte
) {
3647 Status
= ScsiDiskAsyncRead10 (
3650 Request
->TimesRetry
,
3652 Request
->DataLength
,
3653 (UINT32
) Request
->StartLba
,
3654 Request
->SectorCount
,
3659 Status
= ScsiDiskAsyncRead16 (
3662 Request
->TimesRetry
,
3664 Request
->DataLength
,
3666 Request
->SectorCount
,
3672 if (EFI_ERROR (Status
)) {
3673 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3675 } else if (OldSectorCount
!= Request
->SectorCount
) {
3677 // Original sub-task will be split into two new sub-tasks with smaller
3680 if (!ScsiDiskDevice
->Cdb16Byte
) {
3681 Status
= ScsiDiskAsyncRead10 (
3685 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3686 OldDataLength
- Request
->DataLength
,
3687 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
3688 OldSectorCount
- Request
->SectorCount
,
3693 Status
= ScsiDiskAsyncRead16 (
3697 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3698 OldDataLength
- Request
->DataLength
,
3699 Request
->StartLba
+ Request
->SectorCount
,
3700 OldSectorCount
- Request
->SectorCount
,
3705 if (EFI_ERROR (Status
)) {
3706 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3712 // SCSI write command
3714 if (!ScsiDiskDevice
->Cdb16Byte
) {
3715 Status
= ScsiDiskAsyncWrite10 (
3718 Request
->TimesRetry
,
3720 Request
->DataLength
,
3721 (UINT32
) Request
->StartLba
,
3722 Request
->SectorCount
,
3727 Status
= ScsiDiskAsyncWrite16 (
3730 Request
->TimesRetry
,
3732 Request
->DataLength
,
3734 Request
->SectorCount
,
3740 if (EFI_ERROR (Status
)) {
3741 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3743 } else if (OldSectorCount
!= Request
->SectorCount
) {
3745 // Original sub-task will be split into two new sub-tasks with smaller
3748 if (!ScsiDiskDevice
->Cdb16Byte
) {
3749 Status
= ScsiDiskAsyncWrite10 (
3753 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3754 OldDataLength
- Request
->DataLength
,
3755 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
3756 OldSectorCount
- Request
->SectorCount
,
3761 Status
= ScsiDiskAsyncWrite16 (
3765 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3766 OldDataLength
- Request
->DataLength
,
3767 Request
->StartLba
+ Request
->SectorCount
,
3768 OldSectorCount
- Request
->SectorCount
,
3773 if (EFI_ERROR (Status
)) {
3774 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3781 RemoveEntryList (&Request
->Link
);
3782 if ((IsListEmpty (&Request
->BlkIo2Req
->ScsiRWQueue
)) &&
3783 (Request
->BlkIo2Req
->LastScsiRW
)) {
3785 // The last SCSI R/W command of a BlockIo2 request completes
3787 RemoveEntryList (&Request
->BlkIo2Req
->Link
);
3788 FreePool (Request
->BlkIo2Req
); // Should be freed only once
3789 gBS
->SignalEvent (Token
->Event
);
3792 FreePool (Request
->SenseData
);
3798 Submit Async Read(10) command.
3800 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3801 @param Timeout The time to complete the command.
3802 @param TimesRetry The number of times the command has been retried.
3803 @param DataBuffer The buffer to fill with the read out data.
3804 @param DataLength The length of buffer.
3805 @param StartLba The start logic block address.
3806 @param SectorCount The number of blocks to read.
3807 @param BlkIo2Req The upstream BlockIo2 request.
3808 @param Token The pointer to the token associated with the
3809 non-blocking read request.
3811 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3813 @return others Status returned by calling
3814 ScsiRead10CommandEx().
3818 ScsiDiskAsyncRead10 (
3819 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3821 IN UINT8 TimesRetry
,
3822 OUT UINT8
*DataBuffer
,
3823 IN UINT32 DataLength
,
3825 IN UINT32 SectorCount
,
3826 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3827 IN EFI_BLOCK_IO2_TOKEN
*Token
3831 SCSI_ASYNC_RW_REQUEST
*Request
;
3832 EFI_EVENT AsyncIoEvent
;
3835 AsyncIoEvent
= NULL
;
3837 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3838 if (Request
== NULL
) {
3839 return EFI_OUT_OF_RESOURCES
;
3842 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3843 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3844 gBS
->RestoreTPL (OldTpl
);
3846 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3847 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3848 if (Request
->SenseData
== NULL
) {
3849 Status
= EFI_OUT_OF_RESOURCES
;
3853 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3854 Request
->Timeout
= Timeout
;
3855 Request
->TimesRetry
= TimesRetry
;
3856 Request
->InBuffer
= DataBuffer
;
3857 Request
->DataLength
= DataLength
;
3858 Request
->StartLba
= StartLba
;
3859 Request
->SectorCount
= SectorCount
;
3860 Request
->BlkIo2Req
= BlkIo2Req
;
3865 Status
= gBS
->CreateEvent (
3872 if (EFI_ERROR(Status
)) {
3876 Status
= ScsiRead10CommandEx (
3877 ScsiDiskDevice
->ScsiIo
,
3880 &Request
->SenseDataLength
,
3881 &Request
->HostAdapterStatus
,
3882 &Request
->TargetStatus
,
3884 &Request
->DataLength
,
3885 (UINT32
) Request
->StartLba
,
3886 Request
->SectorCount
,
3889 if (EFI_ERROR(Status
)) {
3896 if (AsyncIoEvent
!= NULL
) {
3897 gBS
->CloseEvent (AsyncIoEvent
);
3900 if (Request
!= NULL
) {
3901 if (Request
->SenseData
!= NULL
) {
3902 FreePool (Request
->SenseData
);
3905 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3906 RemoveEntryList (&Request
->Link
);
3907 gBS
->RestoreTPL (OldTpl
);
3917 Submit Async Write(10) command.
3919 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3920 @param Timeout The time to complete the command.
3921 @param TimesRetry The number of times the command has been retried.
3922 @param DataBuffer The buffer contains the data to write.
3923 @param DataLength The length of buffer.
3924 @param StartLba The start logic block address.
3925 @param SectorCount The number of blocks to write.
3926 @param BlkIo2Req The upstream BlockIo2 request.
3927 @param Token The pointer to the token associated with the
3928 non-blocking read request.
3930 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3932 @return others Status returned by calling
3933 ScsiWrite10CommandEx().
3937 ScsiDiskAsyncWrite10 (
3938 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3940 IN UINT8 TimesRetry
,
3941 IN UINT8
*DataBuffer
,
3942 IN UINT32 DataLength
,
3944 IN UINT32 SectorCount
,
3945 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3946 IN EFI_BLOCK_IO2_TOKEN
*Token
3950 SCSI_ASYNC_RW_REQUEST
*Request
;
3951 EFI_EVENT AsyncIoEvent
;
3954 AsyncIoEvent
= NULL
;
3956 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3957 if (Request
== NULL
) {
3958 return EFI_OUT_OF_RESOURCES
;
3961 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3962 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3963 gBS
->RestoreTPL (OldTpl
);
3965 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3966 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3967 if (Request
->SenseData
== NULL
) {
3968 Status
= EFI_OUT_OF_RESOURCES
;
3972 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3973 Request
->Timeout
= Timeout
;
3974 Request
->TimesRetry
= TimesRetry
;
3975 Request
->OutBuffer
= DataBuffer
;
3976 Request
->DataLength
= DataLength
;
3977 Request
->StartLba
= StartLba
;
3978 Request
->SectorCount
= SectorCount
;
3979 Request
->BlkIo2Req
= BlkIo2Req
;
3984 Status
= gBS
->CreateEvent (
3991 if (EFI_ERROR(Status
)) {
3995 Status
= ScsiWrite10CommandEx (
3996 ScsiDiskDevice
->ScsiIo
,
3999 &Request
->SenseDataLength
,
4000 &Request
->HostAdapterStatus
,
4001 &Request
->TargetStatus
,
4003 &Request
->DataLength
,
4004 (UINT32
) Request
->StartLba
,
4005 Request
->SectorCount
,
4008 if (EFI_ERROR(Status
)) {
4015 if (AsyncIoEvent
!= NULL
) {
4016 gBS
->CloseEvent (AsyncIoEvent
);
4019 if (Request
!= NULL
) {
4020 if (Request
->SenseData
!= NULL
) {
4021 FreePool (Request
->SenseData
);
4024 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4025 RemoveEntryList (&Request
->Link
);
4026 gBS
->RestoreTPL (OldTpl
);
4036 Submit Async Read(16) command.
4038 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4039 @param Timeout The time to complete the command.
4040 @param TimesRetry The number of times the command has been retried.
4041 @param DataBuffer The buffer to fill with the read out data.
4042 @param DataLength The length of buffer.
4043 @param StartLba The start logic block address.
4044 @param SectorCount The number of blocks to read.
4045 @param BlkIo2Req The upstream BlockIo2 request.
4046 @param Token The pointer to the token associated with the
4047 non-blocking read request.
4049 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4051 @return others Status returned by calling
4052 ScsiRead16CommandEx().
4056 ScsiDiskAsyncRead16 (
4057 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4059 IN UINT8 TimesRetry
,
4060 OUT UINT8
*DataBuffer
,
4061 IN UINT32 DataLength
,
4063 IN UINT32 SectorCount
,
4064 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4065 IN EFI_BLOCK_IO2_TOKEN
*Token
4069 SCSI_ASYNC_RW_REQUEST
*Request
;
4070 EFI_EVENT AsyncIoEvent
;
4073 AsyncIoEvent
= NULL
;
4075 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4076 if (Request
== NULL
) {
4077 return EFI_OUT_OF_RESOURCES
;
4080 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4081 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4082 gBS
->RestoreTPL (OldTpl
);
4084 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4085 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4086 if (Request
->SenseData
== NULL
) {
4087 Status
= EFI_OUT_OF_RESOURCES
;
4091 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4092 Request
->Timeout
= Timeout
;
4093 Request
->TimesRetry
= TimesRetry
;
4094 Request
->InBuffer
= DataBuffer
;
4095 Request
->DataLength
= DataLength
;
4096 Request
->StartLba
= StartLba
;
4097 Request
->SectorCount
= SectorCount
;
4098 Request
->BlkIo2Req
= BlkIo2Req
;
4103 Status
= gBS
->CreateEvent (
4110 if (EFI_ERROR(Status
)) {
4114 Status
= ScsiRead16CommandEx (
4115 ScsiDiskDevice
->ScsiIo
,
4118 &Request
->SenseDataLength
,
4119 &Request
->HostAdapterStatus
,
4120 &Request
->TargetStatus
,
4122 &Request
->DataLength
,
4124 Request
->SectorCount
,
4127 if (EFI_ERROR(Status
)) {
4134 if (AsyncIoEvent
!= NULL
) {
4135 gBS
->CloseEvent (AsyncIoEvent
);
4138 if (Request
!= NULL
) {
4139 if (Request
->SenseData
!= NULL
) {
4140 FreePool (Request
->SenseData
);
4143 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4144 RemoveEntryList (&Request
->Link
);
4145 gBS
->RestoreTPL (OldTpl
);
4155 Submit Async Write(16) command.
4157 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4158 @param Timeout The time to complete the command.
4159 @param TimesRetry The number of times the command has been retried.
4160 @param DataBuffer The buffer contains the data to write.
4161 @param DataLength The length of buffer.
4162 @param StartLba The start logic block address.
4163 @param SectorCount The number of blocks to write.
4164 @param BlkIo2Req The upstream BlockIo2 request.
4165 @param Token The pointer to the token associated with the
4166 non-blocking read request.
4168 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4170 @return others Status returned by calling
4171 ScsiWrite16CommandEx().
4175 ScsiDiskAsyncWrite16 (
4176 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4178 IN UINT8 TimesRetry
,
4179 IN UINT8
*DataBuffer
,
4180 IN UINT32 DataLength
,
4182 IN UINT32 SectorCount
,
4183 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4184 IN EFI_BLOCK_IO2_TOKEN
*Token
4188 SCSI_ASYNC_RW_REQUEST
*Request
;
4189 EFI_EVENT AsyncIoEvent
;
4192 AsyncIoEvent
= NULL
;
4194 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4195 if (Request
== NULL
) {
4196 return EFI_OUT_OF_RESOURCES
;
4199 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4200 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4201 gBS
->RestoreTPL (OldTpl
);
4203 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4204 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4205 if (Request
->SenseData
== NULL
) {
4206 Status
= EFI_OUT_OF_RESOURCES
;
4210 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4211 Request
->Timeout
= Timeout
;
4212 Request
->TimesRetry
= TimesRetry
;
4213 Request
->OutBuffer
= DataBuffer
;
4214 Request
->DataLength
= DataLength
;
4215 Request
->StartLba
= StartLba
;
4216 Request
->SectorCount
= SectorCount
;
4217 Request
->BlkIo2Req
= BlkIo2Req
;
4222 Status
= gBS
->CreateEvent (
4229 if (EFI_ERROR(Status
)) {
4233 Status
= ScsiWrite16CommandEx (
4234 ScsiDiskDevice
->ScsiIo
,
4237 &Request
->SenseDataLength
,
4238 &Request
->HostAdapterStatus
,
4239 &Request
->TargetStatus
,
4241 &Request
->DataLength
,
4243 Request
->SectorCount
,
4246 if (EFI_ERROR(Status
)) {
4253 if (AsyncIoEvent
!= NULL
) {
4254 gBS
->CloseEvent (AsyncIoEvent
);
4257 if (Request
!= NULL
) {
4258 if (Request
->SenseData
!= NULL
) {
4259 FreePool (Request
->SenseData
);
4262 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4263 RemoveEntryList (&Request
->Link
);
4264 gBS
->RestoreTPL (OldTpl
);
4274 Check sense key to find if media presents.
4276 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4277 @param SenseCounts The number of sense key
4279 @retval TRUE NOT any media
4280 @retval FALSE Media presents
4284 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4285 IN UINTN SenseCounts
4288 EFI_SCSI_SENSE_DATA
*SensePtr
;
4293 SensePtr
= SenseData
;
4295 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4297 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
4298 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
4300 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
4301 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
4314 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4315 @param SenseCounts The number of sense key
4318 @retval FALSE NOT error
4322 ScsiDiskIsMediaError (
4323 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4324 IN UINTN SenseCounts
4327 EFI_SCSI_SENSE_DATA
*SensePtr
;
4332 SensePtr
= SenseData
;
4334 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4336 switch (SensePtr
->Sense_Key
) {
4338 case EFI_SCSI_SK_MEDIUM_ERROR
:
4340 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
4342 switch (SensePtr
->Addnl_Sense_Code
) {
4347 case EFI_SCSI_ASC_MEDIA_ERR1
:
4352 case EFI_SCSI_ASC_MEDIA_ERR2
:
4357 case EFI_SCSI_ASC_MEDIA_ERR3
:
4358 case EFI_SCSI_ASC_MEDIA_ERR4
:
4368 case EFI_SCSI_SK_NOT_READY
:
4370 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4372 switch (SensePtr
->Addnl_Sense_Code
) {
4374 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
4376 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
4397 Check sense key to find if hardware error happens.
4399 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4400 @param SenseCounts The number of sense key
4402 @retval TRUE Hardware error exits.
4403 @retval FALSE NO error.
4407 ScsiDiskIsHardwareError (
4408 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4409 IN UINTN SenseCounts
4412 EFI_SCSI_SENSE_DATA
*SensePtr
;
4417 SensePtr
= SenseData
;
4419 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4422 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
4424 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
4436 Check sense key to find if media has changed.
4438 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4439 @param SenseCounts The number of sense key
4441 @retval TRUE Media is changed.
4442 @retval FALSE Media is NOT changed.
4445 ScsiDiskIsMediaChange (
4446 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4447 IN UINTN SenseCounts
4450 EFI_SCSI_SENSE_DATA
*SensePtr
;
4452 BOOLEAN IsMediaChanged
;
4454 IsMediaChanged
= FALSE
;
4455 SensePtr
= SenseData
;
4457 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4459 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
4460 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
4462 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
4463 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
4464 IsMediaChanged
= TRUE
;
4470 return IsMediaChanged
;
4474 Check sense key to find if reset happens.
4476 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4477 @param SenseCounts The number of sense key
4479 @retval TRUE It is reset before.
4480 @retval FALSE It is NOT reset before.
4484 ScsiDiskIsResetBefore (
4485 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4486 IN UINTN SenseCounts
4489 EFI_SCSI_SENSE_DATA
*SensePtr
;
4491 BOOLEAN IsResetBefore
;
4493 IsResetBefore
= FALSE
;
4494 SensePtr
= SenseData
;
4496 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4499 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
4500 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
4502 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
4503 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
4504 IsResetBefore
= TRUE
;
4510 return IsResetBefore
;
4514 Check sense key to find if the drive is ready.
4516 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4517 @param SenseCounts The number of sense key
4518 @param RetryLater The flag means if need a retry
4520 @retval TRUE Drive is ready.
4521 @retval FALSE Drive is NOT ready.
4525 ScsiDiskIsDriveReady (
4526 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4527 IN UINTN SenseCounts
,
4528 OUT BOOLEAN
*RetryLater
4531 EFI_SCSI_SENSE_DATA
*SensePtr
;
4536 *RetryLater
= FALSE
;
4537 SensePtr
= SenseData
;
4539 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4541 switch (SensePtr
->Sense_Key
) {
4543 case EFI_SCSI_SK_NOT_READY
:
4545 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4547 switch (SensePtr
->Addnl_Sense_Code
) {
4548 case EFI_SCSI_ASC_NOT_READY
:
4550 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
4552 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
4553 case EFI_SCSI_ASCQ_IN_PROGRESS
:
4555 // Additional Sense Code Qualifier is
4556 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
4564 *RetryLater
= FALSE
;
4585 Check sense key to find if it has sense key.
4587 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
4588 @param SenseCounts - The number of sense key
4590 @retval TRUE It has sense key.
4591 @retval FALSE It has NOT any sense key.
4595 ScsiDiskHaveSenseKey (
4596 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4597 IN UINTN SenseCounts
4600 EFI_SCSI_SENSE_DATA
*SensePtr
;
4602 BOOLEAN HaveSenseKey
;
4604 if (SenseCounts
== 0) {
4605 HaveSenseKey
= FALSE
;
4607 HaveSenseKey
= TRUE
;
4610 SensePtr
= SenseData
;
4612 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4615 // Sense Key is SK_NO_SENSE (0x0)
4617 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
4619 HaveSenseKey
= FALSE
;
4625 return HaveSenseKey
;
4629 Release resource about disk device.
4631 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4635 ReleaseScsiDiskDeviceResources (
4636 IN SCSI_DISK_DEV
*ScsiDiskDevice
4639 if (ScsiDiskDevice
== NULL
) {
4643 if (ScsiDiskDevice
->SenseData
!= NULL
) {
4644 FreePool (ScsiDiskDevice
->SenseData
);
4645 ScsiDiskDevice
->SenseData
= NULL
;
4648 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
4649 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
4650 ScsiDiskDevice
->ControllerNameTable
= NULL
;
4653 FreePool (ScsiDiskDevice
);
4655 ScsiDiskDevice
= NULL
;
4659 Determine if Block Io & Block Io2 should be produced.
4662 @param ChildHandle Child Handle to retrieve Parent information.
4664 @retval TRUE Should produce Block Io & Block Io2.
4665 @retval FALSE Should not produce Block Io & Block Io2.
4669 DetermineInstallBlockIo (
4670 IN EFI_HANDLE ChildHandle
4673 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
4674 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
4677 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
4678 // check its attribute, logic or physical.
4680 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
4681 if (ExtScsiPassThru
!= NULL
) {
4682 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
4688 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
4689 // check its attribute, logic or physical.
4691 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
4692 if (ScsiPassThru
!= NULL
) {
4693 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
4702 Search protocol database and check to see if the protocol
4703 specified by ProtocolGuid is present on a ControllerHandle and opened by
4704 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
4705 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
4706 will be opened on it.
4709 @param ProtocolGuid ProtocolGuid pointer.
4710 @param ChildHandle Child Handle to retrieve Parent information.
4716 IN EFI_GUID
*ProtocolGuid
,
4717 IN EFI_HANDLE ChildHandle
4724 EFI_HANDLE
*HandleBuffer
;
4727 // Retrieve the list of all handles from the handle database
4729 Status
= gBS
->LocateHandleBuffer (
4737 if (EFI_ERROR (Status
)) {
4742 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
4744 for (Index
= 0; Index
< HandleCount
; Index
++) {
4745 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
4746 if (!EFI_ERROR (Status
)) {
4747 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
4748 if (!EFI_ERROR (Status
)) {
4749 gBS
->FreePool (HandleBuffer
);
4755 gBS
->FreePool (HandleBuffer
);
4760 Provides inquiry information for the controller type.
4762 This function is used by the IDE bus driver to get inquiry data. Data format
4763 of Identify data is defined by the Interface GUID.
4765 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4766 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
4767 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
4769 @retval EFI_SUCCESS The command was accepted without any errors.
4770 @retval EFI_NOT_FOUND Device does not support this data class
4771 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
4772 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
4777 ScsiDiskInfoInquiry (
4778 IN EFI_DISK_INFO_PROTOCOL
*This
,
4779 IN OUT VOID
*InquiryData
,
4780 IN OUT UINT32
*InquiryDataSize
4784 SCSI_DISK_DEV
*ScsiDiskDevice
;
4786 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4788 Status
= EFI_BUFFER_TOO_SMALL
;
4789 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
4790 Status
= EFI_SUCCESS
;
4791 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
4793 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
4799 Provides identify information for the controller type.
4801 This function is used by the IDE bus driver to get identify data. Data format
4802 of Identify data is defined by the Interface GUID.
4804 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
4806 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
4807 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
4810 @retval EFI_SUCCESS The command was accepted without any errors.
4811 @retval EFI_NOT_FOUND Device does not support this data class
4812 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
4813 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
4818 ScsiDiskInfoIdentify (
4819 IN EFI_DISK_INFO_PROTOCOL
*This
,
4820 IN OUT VOID
*IdentifyData
,
4821 IN OUT UINT32
*IdentifyDataSize
4825 SCSI_DISK_DEV
*ScsiDiskDevice
;
4827 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
4829 // Physical SCSI bus does not support this data class.
4831 return EFI_NOT_FOUND
;
4834 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4836 Status
= EFI_BUFFER_TOO_SMALL
;
4837 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
4838 Status
= EFI_SUCCESS
;
4839 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
4841 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
4846 Provides sense data information for the controller type.
4848 This function is used by the IDE bus driver to get sense data.
4849 Data format of Sense data is defined by the Interface GUID.
4851 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4852 @param[in, out] SenseData Pointer to the SenseData.
4853 @param[in, out] SenseDataSize Size of SenseData in bytes.
4854 @param[out] SenseDataNumber Pointer to the value for the sense data size.
4856 @retval EFI_SUCCESS The command was accepted without any errors.
4857 @retval EFI_NOT_FOUND Device does not support this data class.
4858 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
4859 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
4864 ScsiDiskInfoSenseData (
4865 IN EFI_DISK_INFO_PROTOCOL
*This
,
4866 IN OUT VOID
*SenseData
,
4867 IN OUT UINT32
*SenseDataSize
,
4868 OUT UINT8
*SenseDataNumber
4871 return EFI_NOT_FOUND
;
4876 This function is used by the IDE bus driver to get controller information.
4878 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4879 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
4880 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
4882 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
4883 @retval EFI_UNSUPPORTED This is not an IDE device.
4888 ScsiDiskInfoWhichIde (
4889 IN EFI_DISK_INFO_PROTOCOL
*This
,
4890 OUT UINT32
*IdeChannel
,
4891 OUT UINT32
*IdeDevice
4894 SCSI_DISK_DEV
*ScsiDiskDevice
;
4896 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
4898 // This is not an IDE physical device.
4900 return EFI_UNSUPPORTED
;
4903 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4904 *IdeChannel
= ScsiDiskDevice
->Channel
;
4905 *IdeDevice
= ScsiDiskDevice
->Device
;
4912 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
4914 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
4915 implement Identify() interface for DiskInfo protocol. The ATA command is sent
4916 via SCSI Request Packet.
4918 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4920 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
4921 @retval others Some error occurred during the identification that ATAPI device.
4925 AtapiIdentifyDevice (
4926 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
4929 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
4933 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
4935 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
4936 ZeroMem (Cdb
, sizeof (Cdb
));
4938 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
4939 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
4940 CommandPacket
.Cdb
= Cdb
;
4941 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
4942 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
4943 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
4945 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
4950 Initialize the installation of DiskInfo protocol.
4952 This function prepares for the installation of DiskInfo protocol on the child handle.
4953 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
4954 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
4955 to be IDE/AHCI interface GUID.
4957 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
4958 @param ChildHandle Child handle to install DiskInfo protocol.
4962 InitializeInstallDiskInfo (
4963 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4964 IN EFI_HANDLE ChildHandle
4968 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
4969 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
4970 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
4971 SATA_DEVICE_PATH
*SataDevicePath
;
4972 UINTN IdentifyRetry
;
4974 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
4976 // Device Path protocol must be installed on the device handle.
4978 ASSERT_EFI_ERROR (Status
);
4980 // Copy the DiskInfo protocol template.
4982 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
4984 while (!IsDevicePathEnd (DevicePathNode
)) {
4985 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
4986 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
4987 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
4988 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
4989 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
4990 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
4995 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
4996 // with IDE/AHCI interface GUID.
4998 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
4999 if (!EFI_ERROR (Status
)) {
5000 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
5002 // We find the valid ATAPI device path
5004 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
5005 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
5006 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
5008 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
5010 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
5013 // We find the valid SATA device path
5015 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
5016 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
5017 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
5019 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
5021 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
5025 } while (--IdentifyRetry
> 0);
5026 } else if ((DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
5027 (DevicePathSubType (ChildDevicePathNode
) == MSG_UFS_DP
)) {
5028 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoUfsInterfaceGuid
);
5031 DevicePathNode
= ChildDevicePathNode
;