2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding
= {
19 ScsiDiskDriverBindingSupported
,
20 ScsiDiskDriverBindingStart
,
21 ScsiDiskDriverBindingStop
,
27 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate
= {
28 EFI_DISK_INFO_SCSI_INTERFACE_GUID
,
31 ScsiDiskInfoSenseData
,
36 Allocates an aligned buffer for SCSI disk.
38 This function allocates an aligned buffer for the SCSI disk to perform
39 SCSI IO operations. The alignment requirement is from SCSI IO interface.
41 @param ScsiDiskDevice The SCSI disk involved for the operation.
42 @param BufferSize The request buffer size.
44 @return A pointer to the aligned buffer or NULL if the allocation fails.
48 AllocateAlignedBuffer (
49 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
53 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), ScsiDiskDevice
->ScsiIo
->IoAlign
);
57 Frees an aligned buffer for SCSI disk.
59 This function frees an aligned buffer for the SCSI disk to perform
62 @param Buffer The aligned buffer to be freed.
63 @param BufferSize The request buffer size.
73 FreeAlignedPages (Buffer
, EFI_SIZE_TO_PAGES (BufferSize
));
78 The user Entry Point for module ScsiDisk.
80 The user code starts with this function.
82 @param ImageHandle The firmware allocated handle for the EFI image.
83 @param SystemTable A pointer to the EFI System Table.
85 @retval EFI_SUCCESS The entry point is executed successfully.
86 @retval other Some error occurs when executing this entry point.
92 IN EFI_HANDLE ImageHandle
,
93 IN EFI_SYSTEM_TABLE
*SystemTable
99 // Install driver model protocol(s).
101 Status
= EfiLibInstallDriverBindingComponentName2 (
104 &gScsiDiskDriverBinding
,
106 &gScsiDiskComponentName
,
107 &gScsiDiskComponentName2
109 ASSERT_EFI_ERROR (Status
);
116 Test to see if this driver supports ControllerHandle.
118 This service is called by the EFI boot service ConnectController(). In order
119 to make drivers as small as possible, there are a few calling restrictions for
120 this service. ConnectController() must follow these calling restrictions.
121 If any other agent wishes to call Supported() it must also follow these
122 calling restrictions.
124 @param This Protocol instance pointer.
125 @param ControllerHandle Handle of device to test
126 @param RemainingDevicePath Optional parameter use to pick a specific child
129 @retval EFI_SUCCESS This driver supports this device
130 @retval EFI_ALREADY_STARTED This driver is already running on this device
131 @retval other This driver does not support this device
136 ScsiDiskDriverBindingSupported (
137 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
138 IN EFI_HANDLE Controller
,
139 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
143 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
146 Status
= gBS
->OpenProtocol (
148 &gEfiScsiIoProtocolGuid
,
150 This
->DriverBindingHandle
,
152 EFI_OPEN_PROTOCOL_BY_DRIVER
154 if (EFI_ERROR (Status
)) {
158 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
159 if (!EFI_ERROR (Status
)) {
160 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) || (DeviceType
== EFI_SCSI_TYPE_CDROM
)) {
161 Status
= EFI_SUCCESS
;
163 Status
= EFI_UNSUPPORTED
;
169 &gEfiScsiIoProtocolGuid
,
170 This
->DriverBindingHandle
,
178 Start this driver on ControllerHandle.
180 This service is called by the EFI boot service ConnectController(). In order
181 to make drivers as small as possible, there are a few calling restrictions for
182 this service. ConnectController() must follow these calling restrictions. If
183 any other agent wishes to call Start() it must also follow these calling
186 @param This Protocol instance pointer.
187 @param ControllerHandle Handle of device to bind driver to
188 @param RemainingDevicePath Optional parameter use to pick a specific child
191 @retval EFI_SUCCESS This driver is added to ControllerHandle
192 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
193 @retval other This driver does not support this device
198 ScsiDiskDriverBindingStart (
199 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
200 IN EFI_HANDLE Controller
,
201 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
205 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
206 SCSI_DISK_DEV
*ScsiDiskDevice
;
211 BOOLEAN MustReadCapacity
;
213 MustReadCapacity
= TRUE
;
215 ScsiDiskDevice
= (SCSI_DISK_DEV
*) AllocateZeroPool (sizeof (SCSI_DISK_DEV
));
216 if (ScsiDiskDevice
== NULL
) {
217 return EFI_OUT_OF_RESOURCES
;
220 Status
= gBS
->OpenProtocol (
222 &gEfiScsiIoProtocolGuid
,
224 This
->DriverBindingHandle
,
226 EFI_OPEN_PROTOCOL_BY_DRIVER
228 if (EFI_ERROR (Status
)) {
229 FreePool (ScsiDiskDevice
);
233 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
234 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
235 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION3
;
236 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
237 ScsiDiskDevice
->BlkIo
.Media
->IoAlign
= ScsiIo
->IoAlign
;
238 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
239 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
240 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
241 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
242 ScsiDiskDevice
->BlkIo2
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
243 ScsiDiskDevice
->BlkIo2
.Reset
= ScsiDiskResetEx
;
244 ScsiDiskDevice
->BlkIo2
.ReadBlocksEx
= ScsiDiskReadBlocksEx
;
245 ScsiDiskDevice
->BlkIo2
.WriteBlocksEx
= ScsiDiskWriteBlocksEx
;
246 ScsiDiskDevice
->BlkIo2
.FlushBlocksEx
= ScsiDiskFlushBlocksEx
;
247 ScsiDiskDevice
->Handle
= Controller
;
248 InitializeListHead (&ScsiDiskDevice
->BlkIo2Queue
);
250 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
251 switch (ScsiDiskDevice
->DeviceType
) {
252 case EFI_SCSI_TYPE_DISK
:
253 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
254 MustReadCapacity
= TRUE
;
257 case EFI_SCSI_TYPE_CDROM
:
258 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
259 ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
= TRUE
;
260 MustReadCapacity
= FALSE
;
264 // The Sense Data Array's initial size is 6
266 ScsiDiskDevice
->SenseDataNumber
= 6;
267 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
268 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
270 if (ScsiDiskDevice
->SenseData
== NULL
) {
273 &gEfiScsiIoProtocolGuid
,
274 This
->DriverBindingHandle
,
277 FreePool (ScsiDiskDevice
);
278 return EFI_OUT_OF_RESOURCES
;
282 // Retrieve device information
285 for (Index
= 0; Index
< MaxRetry
; Index
++) {
286 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
287 if (!EFI_ERROR (Status
)) {
292 FreePool (ScsiDiskDevice
->SenseData
);
295 &gEfiScsiIoProtocolGuid
,
296 This
->DriverBindingHandle
,
299 FreePool (ScsiDiskDevice
);
300 return EFI_DEVICE_ERROR
;
304 // The second parameter "TRUE" means must
305 // retrieve media capacity
307 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, MustReadCapacity
, &Temp
);
308 if (!EFI_ERROR (Status
)) {
310 // Determine if Block IO & Block IO2 should be produced on this controller
313 if (DetermineInstallBlockIo(Controller
)) {
314 InitializeInstallDiskInfo(ScsiDiskDevice
, Controller
);
315 Status
= gBS
->InstallMultipleProtocolInterfaces (
317 &gEfiBlockIoProtocolGuid
,
318 &ScsiDiskDevice
->BlkIo
,
319 &gEfiBlockIo2ProtocolGuid
,
320 &ScsiDiskDevice
->BlkIo2
,
321 &gEfiDiskInfoProtocolGuid
,
322 &ScsiDiskDevice
->DiskInfo
,
325 if (!EFI_ERROR(Status
)) {
326 ScsiDiskDevice
->ControllerNameTable
= NULL
;
329 gScsiDiskComponentName
.SupportedLanguages
,
330 &ScsiDiskDevice
->ControllerNameTable
,
336 gScsiDiskComponentName2
.SupportedLanguages
,
337 &ScsiDiskDevice
->ControllerNameTable
,
346 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
347 gBS
->FreePool (ScsiDiskDevice
);
350 &gEfiScsiIoProtocolGuid
,
351 This
->DriverBindingHandle
,
360 Stop this driver on ControllerHandle.
362 This service is called by the EFI boot service DisconnectController().
363 In order to make drivers as small as possible, there are a few calling
364 restrictions for this service. DisconnectController() must follow these
365 calling restrictions. If any other agent wishes to call Stop() it must
366 also follow these calling restrictions.
368 @param This Protocol instance pointer.
369 @param ControllerHandle Handle of device to stop driver on
370 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
371 children is zero stop the entire bus driver.
372 @param ChildHandleBuffer List of Child Handles to Stop.
374 @retval EFI_SUCCESS This driver is removed ControllerHandle
375 @retval other This driver was not removed from this device
380 ScsiDiskDriverBindingStop (
381 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
382 IN EFI_HANDLE Controller
,
383 IN UINTN NumberOfChildren
,
384 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
387 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
388 SCSI_DISK_DEV
*ScsiDiskDevice
;
391 Status
= gBS
->OpenProtocol (
393 &gEfiBlockIoProtocolGuid
,
395 This
->DriverBindingHandle
,
397 EFI_OPEN_PROTOCOL_GET_PROTOCOL
399 if (EFI_ERROR (Status
)) {
403 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (BlkIo
);
406 // Wait for the BlockIo2 requests queue to become empty
408 while (!IsListEmpty (&ScsiDiskDevice
->BlkIo2Queue
));
410 Status
= gBS
->UninstallMultipleProtocolInterfaces (
412 &gEfiBlockIoProtocolGuid
,
413 &ScsiDiskDevice
->BlkIo
,
414 &gEfiBlockIo2ProtocolGuid
,
415 &ScsiDiskDevice
->BlkIo2
,
416 &gEfiDiskInfoProtocolGuid
,
417 &ScsiDiskDevice
->DiskInfo
,
420 if (!EFI_ERROR (Status
)) {
423 &gEfiScsiIoProtocolGuid
,
424 This
->DriverBindingHandle
,
428 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
442 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
443 @param ExtendedVerification The flag about if extend verificate
445 @retval EFI_SUCCESS The device was reset.
446 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
448 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
454 IN EFI_BLOCK_IO_PROTOCOL
*This
,
455 IN BOOLEAN ExtendedVerification
459 SCSI_DISK_DEV
*ScsiDiskDevice
;
462 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
464 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
466 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
468 if (EFI_ERROR (Status
)) {
469 Status
= EFI_DEVICE_ERROR
;
473 if (!ExtendedVerification
) {
477 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
479 if (EFI_ERROR (Status
)) {
480 Status
= EFI_DEVICE_ERROR
;
485 gBS
->RestoreTPL (OldTpl
);
490 The function is to Read Block from SCSI Disk.
492 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
493 @param MediaId The Id of Media detected
494 @param Lba The logic block address
495 @param BufferSize The size of Buffer
496 @param Buffer The buffer to fill the read out data
498 @retval EFI_SUCCESS Successfully to read out block.
499 @retval EFI_DEVICE_ERROR Fail to detect media.
500 @retval EFI_NO_MEDIA Media is not present.
501 @retval EFI_MEDIA_CHANGED Media has changed.
502 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
503 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
509 IN EFI_BLOCK_IO_PROTOCOL
*This
,
516 SCSI_DISK_DEV
*ScsiDiskDevice
;
517 EFI_BLOCK_IO_MEDIA
*Media
;
520 UINTN NumberOfBlocks
;
525 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
526 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
528 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
530 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
531 if (EFI_ERROR (Status
)) {
532 Status
= EFI_DEVICE_ERROR
;
537 gBS
->ReinstallProtocolInterface (
538 ScsiDiskDevice
->Handle
,
539 &gEfiBlockIoProtocolGuid
,
540 &ScsiDiskDevice
->BlkIo
,
541 &ScsiDiskDevice
->BlkIo
543 gBS
->ReinstallProtocolInterface (
544 ScsiDiskDevice
->Handle
,
545 &gEfiBlockIo2ProtocolGuid
,
546 &ScsiDiskDevice
->BlkIo2
,
547 &ScsiDiskDevice
->BlkIo2
549 Status
= EFI_MEDIA_CHANGED
;
554 // Get the intrinsic block size
556 Media
= ScsiDiskDevice
->BlkIo
.Media
;
557 BlockSize
= Media
->BlockSize
;
559 NumberOfBlocks
= BufferSize
/ BlockSize
;
561 if (!(Media
->MediaPresent
)) {
562 Status
= EFI_NO_MEDIA
;
566 if (MediaId
!= Media
->MediaId
) {
567 Status
= EFI_MEDIA_CHANGED
;
571 if (Buffer
== NULL
) {
572 Status
= EFI_INVALID_PARAMETER
;
576 if (BufferSize
== 0) {
577 Status
= EFI_SUCCESS
;
581 if (BufferSize
% BlockSize
!= 0) {
582 Status
= EFI_BAD_BUFFER_SIZE
;
586 if (Lba
> Media
->LastBlock
) {
587 Status
= EFI_INVALID_PARAMETER
;
591 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
592 Status
= EFI_INVALID_PARAMETER
;
596 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
597 Status
= EFI_INVALID_PARAMETER
;
602 // If all the parameters are valid, then perform read sectors command
603 // to transfer data from device to host.
605 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
608 gBS
->RestoreTPL (OldTpl
);
613 The function is to Write Block to SCSI Disk.
615 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
616 @param MediaId The Id of Media detected
617 @param Lba The logic block address
618 @param BufferSize The size of Buffer
619 @param Buffer The buffer to fill the read out data
621 @retval EFI_SUCCESS Successfully to read out block.
622 @retval EFI_WRITE_PROTECTED The device can not be written to.
623 @retval EFI_DEVICE_ERROR Fail to detect media.
624 @retval EFI_NO_MEDIA Media is not present.
625 @retval EFI_MEDIA_CHNAGED Media has changed.
626 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
627 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
632 ScsiDiskWriteBlocks (
633 IN EFI_BLOCK_IO_PROTOCOL
*This
,
640 SCSI_DISK_DEV
*ScsiDiskDevice
;
641 EFI_BLOCK_IO_MEDIA
*Media
;
644 UINTN NumberOfBlocks
;
649 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
650 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
652 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
654 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
655 if (EFI_ERROR (Status
)) {
656 Status
= EFI_DEVICE_ERROR
;
661 gBS
->ReinstallProtocolInterface (
662 ScsiDiskDevice
->Handle
,
663 &gEfiBlockIoProtocolGuid
,
664 &ScsiDiskDevice
->BlkIo
,
665 &ScsiDiskDevice
->BlkIo
667 gBS
->ReinstallProtocolInterface (
668 ScsiDiskDevice
->Handle
,
669 &gEfiBlockIo2ProtocolGuid
,
670 &ScsiDiskDevice
->BlkIo2
,
671 &ScsiDiskDevice
->BlkIo2
673 Status
= EFI_MEDIA_CHANGED
;
678 // Get the intrinsic block size
680 Media
= ScsiDiskDevice
->BlkIo
.Media
;
681 BlockSize
= Media
->BlockSize
;
683 NumberOfBlocks
= BufferSize
/ BlockSize
;
685 if (!(Media
->MediaPresent
)) {
686 Status
= EFI_NO_MEDIA
;
690 if (MediaId
!= Media
->MediaId
) {
691 Status
= EFI_MEDIA_CHANGED
;
695 if (Media
->ReadOnly
) {
696 Status
= EFI_WRITE_PROTECTED
;
700 if (BufferSize
== 0) {
701 Status
= EFI_SUCCESS
;
705 if (Buffer
== NULL
) {
706 Status
= EFI_INVALID_PARAMETER
;
710 if (BufferSize
% BlockSize
!= 0) {
711 Status
= EFI_BAD_BUFFER_SIZE
;
715 if (Lba
> Media
->LastBlock
) {
716 Status
= EFI_INVALID_PARAMETER
;
720 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
721 Status
= EFI_INVALID_PARAMETER
;
725 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
726 Status
= EFI_INVALID_PARAMETER
;
730 // if all the parameters are valid, then perform read sectors command
731 // to transfer data from device to host.
733 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
736 gBS
->RestoreTPL (OldTpl
);
743 EFI_SUCCESS is returned directly.
745 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
747 @retval EFI_SUCCESS All outstanding data was written to the device
752 ScsiDiskFlushBlocks (
753 IN EFI_BLOCK_IO_PROTOCOL
*This
766 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
767 @param ExtendedVerification The flag about if extend verificate.
769 @retval EFI_SUCCESS The device was reset.
770 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
772 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
778 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
779 IN BOOLEAN ExtendedVerification
783 SCSI_DISK_DEV
*ScsiDiskDevice
;
786 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
788 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
790 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
792 if (EFI_ERROR (Status
)) {
793 Status
= EFI_DEVICE_ERROR
;
797 if (!ExtendedVerification
) {
801 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
803 if (EFI_ERROR (Status
)) {
804 Status
= EFI_DEVICE_ERROR
;
809 gBS
->RestoreTPL (OldTpl
);
814 The function is to Read Block from SCSI Disk.
816 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
817 @param MediaId The Id of Media detected.
818 @param Lba The logic block address.
819 @param Token A pointer to the token associated with the transaction.
820 @param BufferSize The size of Buffer.
821 @param Buffer The buffer to fill the read out data.
823 @retval EFI_SUCCESS The read request was queued if Token-> Event is
824 not NULL. The data was read correctly from the
825 device if theToken-> Event is NULL.
826 @retval EFI_DEVICE_ERROR The device reported an error while attempting
827 to perform the read operation.
828 @retval EFI_NO_MEDIA There is no media in the device.
829 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
830 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
831 the intrinsic block size of the device.
832 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
833 valid, or the buffer is not on proper
835 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
841 ScsiDiskReadBlocksEx (
842 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
845 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
850 SCSI_DISK_DEV
*ScsiDiskDevice
;
851 EFI_BLOCK_IO_MEDIA
*Media
;
854 UINTN NumberOfBlocks
;
859 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
860 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
862 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
864 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
865 if (EFI_ERROR (Status
)) {
866 Status
= EFI_DEVICE_ERROR
;
871 gBS
->ReinstallProtocolInterface (
872 ScsiDiskDevice
->Handle
,
873 &gEfiBlockIoProtocolGuid
,
874 &ScsiDiskDevice
->BlkIo
,
875 &ScsiDiskDevice
->BlkIo
877 gBS
->ReinstallProtocolInterface (
878 ScsiDiskDevice
->Handle
,
879 &gEfiBlockIo2ProtocolGuid
,
880 &ScsiDiskDevice
->BlkIo2
,
881 &ScsiDiskDevice
->BlkIo2
883 Status
= EFI_MEDIA_CHANGED
;
888 // Get the intrinsic block size
890 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
891 BlockSize
= Media
->BlockSize
;
893 NumberOfBlocks
= BufferSize
/ BlockSize
;
895 if (!(Media
->MediaPresent
)) {
896 Status
= EFI_NO_MEDIA
;
900 if (MediaId
!= Media
->MediaId
) {
901 Status
= EFI_MEDIA_CHANGED
;
905 if (Buffer
== NULL
) {
906 Status
= EFI_INVALID_PARAMETER
;
910 if (BufferSize
== 0) {
911 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
912 Token
->TransactionStatus
= EFI_SUCCESS
;
913 gBS
->SignalEvent (Token
->Event
);
916 Status
= EFI_SUCCESS
;
920 if (BufferSize
% BlockSize
!= 0) {
921 Status
= EFI_BAD_BUFFER_SIZE
;
925 if (Lba
> Media
->LastBlock
) {
926 Status
= EFI_INVALID_PARAMETER
;
930 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
931 Status
= EFI_INVALID_PARAMETER
;
935 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
936 Status
= EFI_INVALID_PARAMETER
;
941 // If all the parameters are valid, then perform read sectors command
942 // to transfer data from device to host.
944 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
945 Token
->TransactionStatus
= EFI_SUCCESS
;
946 Status
= ScsiDiskAsyncReadSectors (
954 Status
= ScsiDiskReadSectors (
963 gBS
->RestoreTPL (OldTpl
);
968 The function is to Write Block to SCSI Disk.
970 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
971 @param MediaId The Id of Media detected.
972 @param Lba The logic block address.
973 @param Token A pointer to the token associated with the transaction.
974 @param BufferSize The size of Buffer.
975 @param Buffer The buffer to fill the read out data.
977 @retval EFI_SUCCESS The data were written correctly to the device.
978 @retval EFI_WRITE_PROTECTED The device cannot be written to.
979 @retval EFI_NO_MEDIA There is no media in the device.
980 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
981 @retval EFI_DEVICE_ERROR The device reported an error while attempting
982 to perform the write operation.
983 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
984 the intrinsic block size of the device.
985 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
986 valid, or the buffer is not on proper
992 ScsiDiskWriteBlocksEx (
993 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
996 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1001 SCSI_DISK_DEV
*ScsiDiskDevice
;
1002 EFI_BLOCK_IO_MEDIA
*Media
;
1005 UINTN NumberOfBlocks
;
1006 BOOLEAN MediaChange
;
1009 MediaChange
= FALSE
;
1010 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1011 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1013 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1015 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1016 if (EFI_ERROR (Status
)) {
1017 Status
= EFI_DEVICE_ERROR
;
1022 gBS
->ReinstallProtocolInterface (
1023 ScsiDiskDevice
->Handle
,
1024 &gEfiBlockIoProtocolGuid
,
1025 &ScsiDiskDevice
->BlkIo
,
1026 &ScsiDiskDevice
->BlkIo
1028 gBS
->ReinstallProtocolInterface (
1029 ScsiDiskDevice
->Handle
,
1030 &gEfiBlockIo2ProtocolGuid
,
1031 &ScsiDiskDevice
->BlkIo2
,
1032 &ScsiDiskDevice
->BlkIo2
1034 Status
= EFI_MEDIA_CHANGED
;
1039 // Get the intrinsic block size
1041 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
1042 BlockSize
= Media
->BlockSize
;
1044 NumberOfBlocks
= BufferSize
/ BlockSize
;
1046 if (!(Media
->MediaPresent
)) {
1047 Status
= EFI_NO_MEDIA
;
1051 if (MediaId
!= Media
->MediaId
) {
1052 Status
= EFI_MEDIA_CHANGED
;
1056 if (Media
->ReadOnly
) {
1057 Status
= EFI_WRITE_PROTECTED
;
1061 if (BufferSize
== 0) {
1062 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1063 Token
->TransactionStatus
= EFI_SUCCESS
;
1064 gBS
->SignalEvent (Token
->Event
);
1067 Status
= EFI_SUCCESS
;
1071 if (Buffer
== NULL
) {
1072 Status
= EFI_INVALID_PARAMETER
;
1076 if (BufferSize
% BlockSize
!= 0) {
1077 Status
= EFI_BAD_BUFFER_SIZE
;
1081 if (Lba
> Media
->LastBlock
) {
1082 Status
= EFI_INVALID_PARAMETER
;
1086 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1087 Status
= EFI_INVALID_PARAMETER
;
1091 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1092 Status
= EFI_INVALID_PARAMETER
;
1097 // if all the parameters are valid, then perform write sectors command
1098 // to transfer data from device to host.
1100 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1101 Token
->TransactionStatus
= EFI_SUCCESS
;
1102 Status
= ScsiDiskAsyncWriteSectors (
1110 Status
= ScsiDiskWriteSectors (
1119 gBS
->RestoreTPL (OldTpl
);
1124 Flush the Block Device.
1126 @param This Indicates a pointer to the calling context.
1127 @param Token A pointer to the token associated with the transaction.
1129 @retval EFI_SUCCESS All outstanding data was written to the device.
1130 @retval EFI_DEVICE_ERROR The device reported an error while attempting to
1132 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1133 @retval EFI_NO_MEDIA There is no media in the device.
1134 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1139 ScsiDiskFlushBlocksEx (
1140 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1141 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1144 SCSI_DISK_DEV
*ScsiDiskDevice
;
1145 EFI_BLOCK_IO_MEDIA
*Media
;
1147 BOOLEAN MediaChange
;
1150 MediaChange
= FALSE
;
1151 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1152 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1154 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1156 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1157 if (EFI_ERROR (Status
)) {
1158 Status
= EFI_DEVICE_ERROR
;
1163 gBS
->ReinstallProtocolInterface (
1164 ScsiDiskDevice
->Handle
,
1165 &gEfiBlockIoProtocolGuid
,
1166 &ScsiDiskDevice
->BlkIo
,
1167 &ScsiDiskDevice
->BlkIo
1169 gBS
->ReinstallProtocolInterface (
1170 ScsiDiskDevice
->Handle
,
1171 &gEfiBlockIo2ProtocolGuid
,
1172 &ScsiDiskDevice
->BlkIo2
,
1173 &ScsiDiskDevice
->BlkIo2
1175 Status
= EFI_MEDIA_CHANGED
;
1180 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
1182 if (!(Media
->MediaPresent
)) {
1183 Status
= EFI_NO_MEDIA
;
1187 if (Media
->ReadOnly
) {
1188 Status
= EFI_WRITE_PROTECTED
;
1193 // Wait for the BlockIo2 requests queue to become empty
1195 while (!IsListEmpty (&ScsiDiskDevice
->BlkIo2Queue
));
1197 Status
= EFI_SUCCESS
;
1200 // Signal caller event
1202 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1203 Token
->TransactionStatus
= EFI_SUCCESS
;
1204 gBS
->SignalEvent (Token
->Event
);
1208 gBS
->RestoreTPL (OldTpl
);
1214 Detect Device and read out capacity ,if error occurs, parse the sense key.
1216 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1217 @param MustReadCapacity The flag about reading device capacity
1218 @param MediaChange The pointer of flag indicates if media has changed
1220 @retval EFI_DEVICE_ERROR Indicates that error occurs
1221 @retval EFI_SUCCESS Successfully to detect media
1225 ScsiDiskDetectMedia (
1226 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1227 IN BOOLEAN MustReadCapacity
,
1228 OUT BOOLEAN
*MediaChange
1232 EFI_SCSI_SENSE_DATA
*SenseData
;
1233 UINTN NumberOfSenseKeys
;
1235 BOOLEAN NeedReadCapacity
;
1238 EFI_BLOCK_IO_MEDIA OldMedia
;
1240 EFI_EVENT TimeoutEvt
;
1242 Status
= EFI_SUCCESS
;
1244 NumberOfSenseKeys
= 0;
1247 Action
= ACTION_NO_ACTION
;
1248 NeedReadCapacity
= FALSE
;
1249 *MediaChange
= FALSE
;
1252 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
1254 Status
= gBS
->CreateEvent (
1261 if (EFI_ERROR (Status
)) {
1265 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
1266 if (EFI_ERROR (Status
)) {
1271 // Sending Test_Unit cmd to poll device status.
1272 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
1273 // We limit the upper boundary to 120 seconds.
1275 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
1276 Status
= ScsiDiskTestUnitReady (
1282 if (!EFI_ERROR (Status
)) {
1283 Status
= DetectMediaParsingSenseKeys (
1289 if (EFI_ERROR (Status
)) {
1291 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1298 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1304 if (EFI_ERROR (Status
)) {
1309 // ACTION_NO_ACTION: need not read capacity
1310 // other action code: need read capacity
1312 if (Action
== ACTION_READ_CAPACITY
) {
1313 NeedReadCapacity
= TRUE
;
1317 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
1318 // retrieve capacity via Read Capacity command
1320 if (NeedReadCapacity
|| MustReadCapacity
) {
1322 // retrieve media information
1324 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
1325 Status
= ScsiDiskReadCapacity (
1331 if (!EFI_ERROR (Status
)) {
1333 // analyze sense key to action
1335 Status
= DetectMediaParsingSenseKeys (
1341 if (EFI_ERROR (Status
)) {
1343 // if Status is error, it may indicate crisis error,
1344 // so return without retry.
1347 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1355 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1361 if (EFI_ERROR (Status
)) {
1366 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
1368 // Media change information got from the device
1370 *MediaChange
= TRUE
;
1373 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
1374 *MediaChange
= TRUE
;
1375 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1378 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
1379 *MediaChange
= TRUE
;
1380 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1383 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
1384 *MediaChange
= TRUE
;
1385 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1388 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
1389 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
1391 // when change from no media to media present, reset the MediaId to 1.
1393 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
1396 // when no media, reset the MediaId to zero.
1398 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
1401 *MediaChange
= TRUE
;
1405 if (TimeoutEvt
!= NULL
) {
1406 gBS
->CloseEvent (TimeoutEvt
);
1413 Send out Inquiry command to Device.
1415 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1416 @param NeedRetry Indicates if needs try again when error happens
1418 @retval EFI_DEVICE_ERROR Indicates that error occurs
1419 @retval EFI_SUCCESS Successfully to detect media
1423 ScsiDiskInquiryDevice (
1424 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1425 OUT BOOLEAN
*NeedRetry
1428 UINT32 InquiryDataLength
;
1429 UINT8 SenseDataLength
;
1430 UINT8 HostAdapterStatus
;
1432 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
1433 UINTN NumberOfSenseKeys
;
1437 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
1438 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
1441 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1442 SenseDataLength
= 0;
1444 Status
= ScsiInquiryCommand (
1445 ScsiDiskDevice
->ScsiIo
,
1451 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
1456 // no need to check HostAdapterStatus and TargetStatus
1458 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1459 ParseInquiryData (ScsiDiskDevice
);
1461 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1463 // Check whether the device supports Block Limits VPD page (0xB0)
1465 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1466 if (SupportedVpdPages
== NULL
) {
1468 return EFI_DEVICE_ERROR
;
1470 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1471 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
1472 SenseDataLength
= 0;
1473 Status
= ScsiInquiryCommandEx (
1474 ScsiDiskDevice
->ScsiIo
,
1480 (VOID
*) SupportedVpdPages
,
1483 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
1485 if (!EFI_ERROR (Status
)) {
1486 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
1487 | SupportedVpdPages
->PageLength1
;
1488 for (Index
= 0; Index
< PageLength
; Index
++) {
1489 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
1495 // Query the Block Limits VPD page
1497 if (Index
< PageLength
) {
1498 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1499 if (BlockLimits
== NULL
) {
1500 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1502 return EFI_DEVICE_ERROR
;
1504 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1505 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
1506 SenseDataLength
= 0;
1507 Status
= ScsiInquiryCommandEx (
1508 ScsiDiskDevice
->ScsiIo
,
1514 (VOID
*) BlockLimits
,
1517 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
1519 if (!EFI_ERROR (Status
)) {
1520 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
1521 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
1522 BlockLimits
->OptimalTransferLengthGranularity1
;
1525 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1529 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1533 if (!EFI_ERROR (Status
)) {
1536 } else if (Status
== EFI_NOT_READY
) {
1538 return EFI_DEVICE_ERROR
;
1540 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1542 return EFI_DEVICE_ERROR
;
1545 // go ahead to check HostAdapterStatus and TargetStatus
1546 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1549 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1550 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1552 return EFI_DEVICE_ERROR
;
1553 } else if (Status
== EFI_DEVICE_ERROR
) {
1555 // reset the scsi channel
1557 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1559 return EFI_DEVICE_ERROR
;
1562 Status
= CheckTargetStatus (TargetStatus
);
1563 if (Status
== EFI_NOT_READY
) {
1565 // reset the scsi device
1567 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1569 return EFI_DEVICE_ERROR
;
1571 } else if (Status
== EFI_DEVICE_ERROR
) {
1573 return EFI_DEVICE_ERROR
;
1577 // if goes here, meant ScsiInquiryCommand() failed.
1578 // if ScsiDiskRequestSenseKeys() succeeds at last,
1579 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1582 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1583 Status
= ScsiDiskRequestSenseKeys (
1590 if (!EFI_ERROR (Status
)) {
1592 return EFI_DEVICE_ERROR
;
1596 return EFI_DEVICE_ERROR
;
1600 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1601 // set *NeedRetry = FALSE to avoid the outside caller try again.
1604 return EFI_DEVICE_ERROR
;
1610 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1611 When Test Unit Ready command encounters any error caused by host adapter or
1612 target, return error without retrieving Sense Keys.
1614 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1615 @param NeedRetry The pointer of flag indicates try again
1616 @param SenseDataArray The pointer of an array of sense data
1617 @param NumberOfSenseKeys The pointer of the number of sense data array
1619 @retval EFI_DEVICE_ERROR Indicates that error occurs
1620 @retval EFI_SUCCESS Successfully to test unit
1624 ScsiDiskTestUnitReady (
1625 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1626 OUT BOOLEAN
*NeedRetry
,
1627 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1628 OUT UINTN
*NumberOfSenseKeys
1632 UINT8 SenseDataLength
;
1633 UINT8 HostAdapterStatus
;
1638 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
1639 *NumberOfSenseKeys
= 0;
1642 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1644 Status
= ScsiTestUnitReadyCommand (
1645 ScsiDiskDevice
->ScsiIo
,
1647 ScsiDiskDevice
->SenseData
,
1653 // no need to check HostAdapterStatus and TargetStatus
1655 if (Status
== EFI_NOT_READY
) {
1657 return EFI_DEVICE_ERROR
;
1659 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1661 return EFI_DEVICE_ERROR
;
1664 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1667 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1668 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1670 return EFI_DEVICE_ERROR
;
1672 } else if (Status
== EFI_DEVICE_ERROR
) {
1674 // reset the scsi channel
1676 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1678 return EFI_DEVICE_ERROR
;
1681 Status
= CheckTargetStatus (TargetStatus
);
1682 if (Status
== EFI_NOT_READY
) {
1684 // reset the scsi device
1686 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1688 return EFI_DEVICE_ERROR
;
1690 } else if (Status
== EFI_DEVICE_ERROR
) {
1692 return EFI_DEVICE_ERROR
;
1695 if (SenseDataLength
!= 0) {
1696 *NumberOfSenseKeys
= SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
);
1697 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1702 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1703 Status
= ScsiDiskRequestSenseKeys (
1710 if (!EFI_ERROR (Status
)) {
1715 return EFI_DEVICE_ERROR
;
1719 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1720 // set *NeedRetry = FALSE to avoid the outside caller try again.
1723 return EFI_DEVICE_ERROR
;
1727 Parsing Sense Keys which got from request sense command.
1729 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1730 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1731 @param NumberOfSenseKeys The number of sense key
1732 @param Action The pointer of action which indicates what is need to do next
1734 @retval EFI_DEVICE_ERROR Indicates that error occurs
1735 @retval EFI_SUCCESS Successfully to complete the parsing
1739 DetectMediaParsingSenseKeys (
1740 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1741 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1742 IN UINTN NumberOfSenseKeys
,
1749 // Default is to read capacity, unless..
1751 *Action
= ACTION_READ_CAPACITY
;
1753 if (NumberOfSenseKeys
== 0) {
1754 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1755 *Action
= ACTION_NO_ACTION
;
1760 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1762 // No Sense Key returned from last submitted command
1764 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1765 *Action
= ACTION_NO_ACTION
;
1770 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1771 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1772 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1773 *Action
= ACTION_NO_ACTION
;
1774 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
1778 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1779 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1780 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
1784 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
1785 *Action
= ACTION_RETRY_COMMAND_LATER
;
1786 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
1790 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1791 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
1792 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1793 return EFI_DEVICE_ERROR
;
1796 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1797 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
1798 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1799 return EFI_DEVICE_ERROR
;
1802 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1804 *Action
= ACTION_RETRY_COMMAND_LATER
;
1805 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
1808 *Action
= ACTION_NO_ACTION
;
1809 return EFI_DEVICE_ERROR
;
1812 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1813 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
1819 Send read capacity command to device and get the device parameter.
1821 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1822 @param NeedRetry The pointer of flag indicates if need a retry
1823 @param SenseDataArray The pointer of an array of sense data
1824 @param NumberOfSenseKeys The number of sense key
1826 @retval EFI_DEVICE_ERROR Indicates that error occurs
1827 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1831 ScsiDiskReadCapacity (
1832 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1833 OUT BOOLEAN
*NeedRetry
,
1834 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1835 OUT UINTN
*NumberOfSenseKeys
1838 UINT8 HostAdapterStatus
;
1840 EFI_STATUS CommandStatus
;
1844 UINT8 SenseDataLength
;
1845 UINT32 DataLength10
;
1846 UINT32 DataLength16
;
1847 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
1848 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
1850 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1851 if (CapacityData10
== NULL
) {
1853 return EFI_DEVICE_ERROR
;
1855 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1856 if (CapacityData16
== NULL
) {
1857 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1859 return EFI_DEVICE_ERROR
;
1862 SenseDataLength
= 0;
1863 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1864 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1865 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1866 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1868 *NumberOfSenseKeys
= 0;
1872 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1873 // 16 byte command should be used to access large hard disk >2TB
1875 CommandStatus
= ScsiReadCapacityCommand (
1876 ScsiDiskDevice
->ScsiIo
,
1882 (VOID
*) CapacityData10
,
1887 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1888 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
1889 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff)) {
1891 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1893 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1895 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1896 // and LowestAlignedLba
1898 CommandStatus
= ScsiReadCapacity16Command (
1899 ScsiDiskDevice
->ScsiIo
,
1905 (VOID
*) CapacityData16
,
1912 // no need to check HostAdapterStatus and TargetStatus
1914 if (CommandStatus
== EFI_SUCCESS
) {
1915 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
1916 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1917 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1921 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1922 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1924 if (CommandStatus
== EFI_NOT_READY
) {
1926 return EFI_DEVICE_ERROR
;
1927 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1929 return EFI_DEVICE_ERROR
;
1933 // go ahead to check HostAdapterStatus and TargetStatus
1934 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1937 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1938 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1940 return EFI_DEVICE_ERROR
;
1942 } else if (Status
== EFI_DEVICE_ERROR
) {
1944 // reset the scsi channel
1946 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1948 return EFI_DEVICE_ERROR
;
1951 Status
= CheckTargetStatus (TargetStatus
);
1952 if (Status
== EFI_NOT_READY
) {
1954 // reset the scsi device
1956 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1958 return EFI_DEVICE_ERROR
;
1960 } else if (Status
== EFI_DEVICE_ERROR
) {
1962 return EFI_DEVICE_ERROR
;
1966 // if goes here, meant ScsiReadCapacityCommand() failed.
1967 // if ScsiDiskRequestSenseKeys() succeeds at last,
1968 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1971 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1973 Status
= ScsiDiskRequestSenseKeys (
1980 if (!EFI_ERROR (Status
)) {
1985 return EFI_DEVICE_ERROR
;
1989 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1990 // set *NeedRetry = FALSE to avoid the outside caller try again.
1993 return EFI_DEVICE_ERROR
;
1997 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1999 @param HostAdapterStatus Host Adapter status
2001 @retval EFI_SUCCESS Host adapter is OK.
2002 @retval EFI_TIMEOUT Timeout.
2003 @retval EFI_NOT_READY Adapter NOT ready.
2004 @retval EFI_DEVICE_ERROR Adapter device error.
2008 CheckHostAdapterStatus (
2009 IN UINT8 HostAdapterStatus
2012 switch (HostAdapterStatus
) {
2013 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
2016 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
2017 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
2018 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
2021 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
2022 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
2023 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
2024 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
2025 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
2026 return EFI_NOT_READY
;
2028 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
2029 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
2030 return EFI_DEVICE_ERROR
;
2039 Check the target status and re-interpret it in EFI_STATUS.
2041 @param TargetStatus Target status
2043 @retval EFI_NOT_READY Device is NOT ready.
2044 @retval EFI_DEVICE_ERROR
2050 IN UINT8 TargetStatus
2053 switch (TargetStatus
) {
2054 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
2055 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
2056 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
2059 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
2060 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
2061 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
2062 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
2063 return EFI_NOT_READY
;
2065 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
2066 return EFI_DEVICE_ERROR
;
2075 Retrieve all sense keys from the device.
2077 When encountering error during the process, if retrieve sense keys before
2078 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
2079 and NeedRetry set to FALSE; otherwize, return the proper return status.
2081 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2082 @param NeedRetry The pointer of flag indicates if need a retry
2083 @param SenseDataArray The pointer of an array of sense data
2084 @param NumberOfSenseKeys The number of sense key
2085 @param AskResetIfError The flag indicates if need reset when error occurs
2087 @retval EFI_DEVICE_ERROR Indicates that error occurs
2088 @retval EFI_SUCCESS Successfully to request sense key
2092 ScsiDiskRequestSenseKeys (
2093 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2094 OUT BOOLEAN
*NeedRetry
,
2095 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2096 OUT UINTN
*NumberOfSenseKeys
,
2097 IN BOOLEAN AskResetIfError
2100 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
2101 UINT8 SenseDataLength
;
2104 EFI_STATUS FallStatus
;
2105 UINT8 HostAdapterStatus
;
2108 FallStatus
= EFI_SUCCESS
;
2109 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
2112 ScsiDiskDevice
->SenseData
,
2113 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
2116 *NumberOfSenseKeys
= 0;
2117 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2118 Status
= EFI_SUCCESS
;
2119 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
2120 if (PtrSenseData
== NULL
) {
2121 return EFI_DEVICE_ERROR
;
2124 for (SenseReq
= TRUE
; SenseReq
;) {
2125 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2126 Status
= ScsiRequestSenseCommand (
2127 ScsiDiskDevice
->ScsiIo
,
2134 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
2135 FallStatus
= EFI_SUCCESS
;
2137 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2139 FallStatus
= EFI_DEVICE_ERROR
;
2141 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2143 FallStatus
= EFI_DEVICE_ERROR
;
2145 } else if (Status
== EFI_DEVICE_ERROR
) {
2146 if (AskResetIfError
) {
2147 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2150 FallStatus
= EFI_DEVICE_ERROR
;
2153 if (EFI_ERROR (FallStatus
)) {
2154 if (*NumberOfSenseKeys
!= 0) {
2156 Status
= EFI_SUCCESS
;
2159 Status
= EFI_DEVICE_ERROR
;
2164 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
2165 (*NumberOfSenseKeys
) += 1;
2168 // no more sense key or number of sense keys exceeds predefined,
2171 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
2172 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
2178 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2184 Get information from media read capacity command.
2186 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2187 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
2188 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
2193 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2194 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
2195 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
2200 if (!ScsiDiskDevice
->Cdb16Byte
) {
2201 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
2202 (Capacity10
->LastLba2
<< 16) |
2203 (Capacity10
->LastLba1
<< 8) |
2204 Capacity10
->LastLba0
;
2206 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
2207 (Capacity10
->BlockSize2
<< 16) |
2208 (Capacity10
->BlockSize1
<< 8) |
2209 Capacity10
->BlockSize0
;
2210 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
2211 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
2213 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2214 *Ptr
++ = Capacity16
->LastLba0
;
2215 *Ptr
++ = Capacity16
->LastLba1
;
2216 *Ptr
++ = Capacity16
->LastLba2
;
2217 *Ptr
++ = Capacity16
->LastLba3
;
2218 *Ptr
++ = Capacity16
->LastLba4
;
2219 *Ptr
++ = Capacity16
->LastLba5
;
2220 *Ptr
++ = Capacity16
->LastLba6
;
2221 *Ptr
= Capacity16
->LastLba7
;
2223 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
2224 (Capacity16
->BlockSize2
<< 16) |
2225 (Capacity16
->BlockSize1
<< 8) |
2226 Capacity16
->BlockSize0
;
2228 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
2229 Capacity16
->LowestAlignLogic1
;
2230 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
2233 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
2239 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2244 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2247 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
2248 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
2252 Read sector from SCSI Disk.
2254 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2255 @param Buffer The buffer to fill in the read out data
2256 @param Lba Logic block address
2257 @param NumberOfBlocks The number of blocks to read
2259 @retval EFI_DEVICE_ERROR Indicates a device error.
2260 @retval EFI_SUCCESS Operation is successful.
2264 ScsiDiskReadSectors (
2265 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2268 IN UINTN NumberOfBlocks
2271 UINTN BlocksRemaining
;
2277 UINT32 NextSectorCount
;
2284 Status
= EFI_SUCCESS
;
2286 BlocksRemaining
= NumberOfBlocks
;
2287 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2290 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2292 if (!ScsiDiskDevice
->Cdb16Byte
) {
2295 MaxBlock
= 0xFFFFFFFF;
2300 while (BlocksRemaining
> 0) {
2302 if (BlocksRemaining
<= MaxBlock
) {
2303 if (!ScsiDiskDevice
->Cdb16Byte
) {
2304 SectorCount
= (UINT16
) BlocksRemaining
;
2306 SectorCount
= (UINT32
) BlocksRemaining
;
2309 SectorCount
= MaxBlock
;
2312 ByteCount
= SectorCount
* BlockSize
;
2314 // |------------------------|-----------------|------------------|-----------------|
2315 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2316 // |------------------------|-----------------|------------------|-----------------|
2317 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2318 // |------------------------|-----------------|------------------|-----------------|
2319 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2320 // |------------------------|-----------------|------------------|-----------------|
2321 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2322 // |------------------------|-----------------|------------------|-----------------|
2323 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2324 // |------------------------|-----------------|------------------|-----------------|
2325 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2326 // |------------------------|-----------------|------------------|-----------------|
2327 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2328 // |------------------------|-----------------|------------------|-----------------|
2329 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2330 // |------------------------|-----------------|------------------|-----------------|
2331 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2332 // |------------------------|-----------------|------------------|-----------------|
2333 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2334 // |------------------------|-----------------|------------------|-----------------|
2335 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2336 // |------------------------|-----------------|------------------|-----------------|
2338 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2339 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2340 // From the above table, we could know 2.1Mbytes per second is lowest one.
2341 // The timout value is rounded up to nearest integar and here an additional 30s is added
2342 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2343 // commands in the Standby/Idle mode.
2345 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2348 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2349 if (!ScsiDiskDevice
->Cdb16Byte
) {
2350 Status
= ScsiDiskRead10 (
2360 Status
= ScsiDiskRead16 (
2370 if (!EFI_ERROR (Status
)) {
2375 return EFI_DEVICE_ERROR
;
2379 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
2380 // lowered ByteCount on output, we must make sure that we lower
2381 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2382 // it is invalid to request more sectors in the CDB than the entire
2383 // transfer (ie. ByteCount) can carry.
2385 // In addition, ByteCount is only expected to go down, or stay unchaged.
2386 // Therefore we don't need to update Timeout: the original timeout should
2387 // accommodate shorter transfers too.
2389 NextSectorCount
= ByteCount
/ BlockSize
;
2390 if (NextSectorCount
< SectorCount
) {
2391 SectorCount
= NextSectorCount
;
2393 // Account for any rounding down.
2395 ByteCount
= SectorCount
* BlockSize
;
2399 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2400 return EFI_DEVICE_ERROR
;
2404 // actual transferred sectors
2406 SectorCount
= ByteCount
/ BlockSize
;
2409 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2410 BlocksRemaining
-= SectorCount
;
2417 Write sector to SCSI Disk.
2419 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2420 @param Buffer The buffer of data to be written into SCSI Disk
2421 @param Lba Logic block address
2422 @param NumberOfBlocks The number of blocks to read
2424 @retval EFI_DEVICE_ERROR Indicates a device error.
2425 @retval EFI_SUCCESS Operation is successful.
2429 ScsiDiskWriteSectors (
2430 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2433 IN UINTN NumberOfBlocks
2436 UINTN BlocksRemaining
;
2442 UINT32 NextSectorCount
;
2449 Status
= EFI_SUCCESS
;
2451 BlocksRemaining
= NumberOfBlocks
;
2452 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2455 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2457 if (!ScsiDiskDevice
->Cdb16Byte
) {
2460 MaxBlock
= 0xFFFFFFFF;
2465 while (BlocksRemaining
> 0) {
2467 if (BlocksRemaining
<= MaxBlock
) {
2468 if (!ScsiDiskDevice
->Cdb16Byte
) {
2469 SectorCount
= (UINT16
) BlocksRemaining
;
2471 SectorCount
= (UINT32
) BlocksRemaining
;
2474 SectorCount
= MaxBlock
;
2477 ByteCount
= SectorCount
* BlockSize
;
2479 // |------------------------|-----------------|------------------|-----------------|
2480 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2481 // |------------------------|-----------------|------------------|-----------------|
2482 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2483 // |------------------------|-----------------|------------------|-----------------|
2484 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2485 // |------------------------|-----------------|------------------|-----------------|
2486 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2487 // |------------------------|-----------------|------------------|-----------------|
2488 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2489 // |------------------------|-----------------|------------------|-----------------|
2490 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2491 // |------------------------|-----------------|------------------|-----------------|
2492 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2493 // |------------------------|-----------------|------------------|-----------------|
2494 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2495 // |------------------------|-----------------|------------------|-----------------|
2496 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2497 // |------------------------|-----------------|------------------|-----------------|
2498 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2499 // |------------------------|-----------------|------------------|-----------------|
2500 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2501 // |------------------------|-----------------|------------------|-----------------|
2503 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2504 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2505 // From the above table, we could know 2.1Mbytes per second is lowest one.
2506 // The timout value is rounded up to nearest integar and here an additional 30s is added
2507 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2508 // commands in the Standby/Idle mode.
2510 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2512 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2513 if (!ScsiDiskDevice
->Cdb16Byte
) {
2514 Status
= ScsiDiskWrite10 (
2524 Status
= ScsiDiskWrite16 (
2534 if (!EFI_ERROR (Status
)) {
2539 return EFI_DEVICE_ERROR
;
2543 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
2544 // has lowered ByteCount on output, we must make sure that we lower
2545 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2546 // it is invalid to request more sectors in the CDB than the entire
2547 // transfer (ie. ByteCount) can carry.
2549 // In addition, ByteCount is only expected to go down, or stay unchaged.
2550 // Therefore we don't need to update Timeout: the original timeout should
2551 // accommodate shorter transfers too.
2553 NextSectorCount
= ByteCount
/ BlockSize
;
2554 if (NextSectorCount
< SectorCount
) {
2555 SectorCount
= NextSectorCount
;
2557 // Account for any rounding down.
2559 ByteCount
= SectorCount
* BlockSize
;
2563 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2564 return EFI_DEVICE_ERROR
;
2567 // actual transferred sectors
2569 SectorCount
= ByteCount
/ BlockSize
;
2572 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2573 BlocksRemaining
-= SectorCount
;
2580 Asynchronously read sector from SCSI Disk.
2582 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2583 @param Buffer The buffer to fill in the read out data.
2584 @param Lba Logic block address.
2585 @param NumberOfBlocks The number of blocks to read.
2586 @param Token A pointer to the token associated with the
2587 non-blocking read request.
2589 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
2590 @retval EFI_DEVICE_ERROR Indicates a device error.
2591 @retval EFI_SUCCESS Operation is successful.
2595 ScsiDiskAsyncReadSectors (
2596 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2599 IN UINTN NumberOfBlocks
,
2600 IN EFI_BLOCK_IO2_TOKEN
*Token
2603 UINTN BlocksRemaining
;
2610 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
2614 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
2615 return EFI_INVALID_PARAMETER
;
2618 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
2619 if (BlkIo2Req
== NULL
) {
2620 return EFI_OUT_OF_RESOURCES
;
2623 BlkIo2Req
->Token
= Token
;
2625 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2626 InsertTailList (&ScsiDiskDevice
->BlkIo2Queue
, &BlkIo2Req
->Link
);
2627 gBS
->RestoreTPL (OldTpl
);
2629 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
2631 Status
= EFI_SUCCESS
;
2633 BlocksRemaining
= NumberOfBlocks
;
2634 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2637 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2640 if (!ScsiDiskDevice
->Cdb16Byte
) {
2643 MaxBlock
= 0xFFFFFFFF;
2648 while (BlocksRemaining
> 0) {
2650 if (BlocksRemaining
<= MaxBlock
) {
2651 if (!ScsiDiskDevice
->Cdb16Byte
) {
2652 SectorCount
= (UINT16
) BlocksRemaining
;
2654 SectorCount
= (UINT32
) BlocksRemaining
;
2657 SectorCount
= MaxBlock
;
2660 ByteCount
= SectorCount
* BlockSize
;
2662 // |------------------------|-----------------|------------------|-----------------|
2663 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2664 // |------------------------|-----------------|------------------|-----------------|
2665 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2666 // |------------------------|-----------------|------------------|-----------------|
2667 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2668 // |------------------------|-----------------|------------------|-----------------|
2669 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2670 // |------------------------|-----------------|------------------|-----------------|
2671 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2672 // |------------------------|-----------------|------------------|-----------------|
2673 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2674 // |------------------------|-----------------|------------------|-----------------|
2675 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2676 // |------------------------|-----------------|------------------|-----------------|
2677 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2678 // |------------------------|-----------------|------------------|-----------------|
2679 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2680 // |------------------------|-----------------|------------------|-----------------|
2681 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2682 // |------------------------|-----------------|------------------|-----------------|
2683 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2684 // |------------------------|-----------------|------------------|-----------------|
2686 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2687 // we have to use the lowest transfer rate to calculate the possible
2688 // maximum timeout value for each operation.
2689 // From the above table, we could know 2.1Mbytes per second is lowest one.
2690 // The timout value is rounded up to nearest integar and here an additional
2691 // 30s is added to follow ATA spec in which it mentioned that the device
2692 // may take up to 30s to respond commands in the Standby/Idle mode.
2694 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2696 if (!ScsiDiskDevice
->Cdb16Byte
) {
2697 Status
= ScsiDiskAsyncRead10 (
2709 Status
= ScsiDiskAsyncRead16 (
2721 if (EFI_ERROR (Status
)) {
2723 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
2724 // length of a SCSI I/O command is too large.
2725 // In this case, we retry sending the SCSI command with a data length
2726 // half of its previous value.
2728 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
2729 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
2730 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
2735 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2736 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2738 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
2739 // SCSI sub-task running. Otherwise, it will be freed in the callback
2740 // function ScsiDiskNotify().
2742 RemoveEntryList (&BlkIo2Req
->Link
);
2743 FreePool (BlkIo2Req
);
2745 gBS
->RestoreTPL (OldTpl
);
2748 // It is safe to return error status to the caller, since there is no
2749 // previous SCSI sub-task executing.
2751 Status
= EFI_DEVICE_ERROR
;
2754 gBS
->RestoreTPL (OldTpl
);
2757 // There are previous SCSI commands still running, EFI_SUCCESS should
2758 // be returned to make sure that the caller does not free resources
2759 // still using by these SCSI commands.
2761 Status
= EFI_SUCCESS
;
2767 // Sectors submitted for transfer
2769 SectorCount
= ByteCount
/ BlockSize
;
2772 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2773 BlocksRemaining
-= SectorCount
;
2776 Status
= EFI_SUCCESS
;
2779 if (BlkIo2Req
!= NULL
) {
2780 BlkIo2Req
->LastScsiRW
= TRUE
;
2782 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2783 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2784 RemoveEntryList (&BlkIo2Req
->Link
);
2785 FreePool (BlkIo2Req
);
2788 gBS
->SignalEvent (Token
->Event
);
2790 gBS
->RestoreTPL (OldTpl
);
2797 Asynchronously write sector to SCSI Disk.
2799 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2800 @param Buffer The buffer of data to be written into SCSI Disk.
2801 @param Lba Logic block address.
2802 @param NumberOfBlocks The number of blocks to read.
2803 @param Token A pointer to the token associated with the
2804 non-blocking read request.
2806 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
2807 @retval EFI_DEVICE_ERROR Indicates a device error.
2808 @retval EFI_SUCCESS Operation is successful.
2812 ScsiDiskAsyncWriteSectors (
2813 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2816 IN UINTN NumberOfBlocks
,
2817 IN EFI_BLOCK_IO2_TOKEN
*Token
2820 UINTN BlocksRemaining
;
2827 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
2831 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
2832 return EFI_INVALID_PARAMETER
;
2835 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
2836 if (BlkIo2Req
== NULL
) {
2837 return EFI_OUT_OF_RESOURCES
;
2840 BlkIo2Req
->Token
= Token
;
2842 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2843 InsertTailList (&ScsiDiskDevice
->BlkIo2Queue
, &BlkIo2Req
->Link
);
2844 gBS
->RestoreTPL (OldTpl
);
2846 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
2848 Status
= EFI_SUCCESS
;
2850 BlocksRemaining
= NumberOfBlocks
;
2851 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2854 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2857 if (!ScsiDiskDevice
->Cdb16Byte
) {
2860 MaxBlock
= 0xFFFFFFFF;
2865 while (BlocksRemaining
> 0) {
2867 if (BlocksRemaining
<= MaxBlock
) {
2868 if (!ScsiDiskDevice
->Cdb16Byte
) {
2869 SectorCount
= (UINT16
) BlocksRemaining
;
2871 SectorCount
= (UINT32
) BlocksRemaining
;
2874 SectorCount
= MaxBlock
;
2877 ByteCount
= SectorCount
* BlockSize
;
2879 // |------------------------|-----------------|------------------|-----------------|
2880 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2881 // |------------------------|-----------------|------------------|-----------------|
2882 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2883 // |------------------------|-----------------|------------------|-----------------|
2884 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2885 // |------------------------|-----------------|------------------|-----------------|
2886 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2887 // |------------------------|-----------------|------------------|-----------------|
2888 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2889 // |------------------------|-----------------|------------------|-----------------|
2890 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2891 // |------------------------|-----------------|------------------|-----------------|
2892 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2893 // |------------------------|-----------------|------------------|-----------------|
2894 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2895 // |------------------------|-----------------|------------------|-----------------|
2896 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2897 // |------------------------|-----------------|------------------|-----------------|
2898 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2899 // |------------------------|-----------------|------------------|-----------------|
2900 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2901 // |------------------------|-----------------|------------------|-----------------|
2903 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2904 // we have to use the lowest transfer rate to calculate the possible
2905 // maximum timeout value for each operation.
2906 // From the above table, we could know 2.1Mbytes per second is lowest one.
2907 // The timout value is rounded up to nearest integar and here an additional
2908 // 30s is added to follow ATA spec in which it mentioned that the device
2909 // may take up to 30s to respond commands in the Standby/Idle mode.
2911 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2913 if (!ScsiDiskDevice
->Cdb16Byte
) {
2914 Status
= ScsiDiskAsyncWrite10 (
2926 Status
= ScsiDiskAsyncWrite16 (
2938 if (EFI_ERROR (Status
)) {
2940 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
2941 // length of a SCSI I/O command is too large.
2942 // In this case, we retry sending the SCSI command with a data length
2943 // half of its previous value.
2945 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
2946 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
2947 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
2952 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2953 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2955 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
2956 // SCSI sub-task running. Otherwise, it will be freed in the callback
2957 // function ScsiDiskNotify().
2959 RemoveEntryList (&BlkIo2Req
->Link
);
2960 FreePool (BlkIo2Req
);
2962 gBS
->RestoreTPL (OldTpl
);
2965 // It is safe to return error status to the caller, since there is no
2966 // previous SCSI sub-task executing.
2968 Status
= EFI_DEVICE_ERROR
;
2971 gBS
->RestoreTPL (OldTpl
);
2974 // There are previous SCSI commands still running, EFI_SUCCESS should
2975 // be returned to make sure that the caller does not free resources
2976 // still using by these SCSI commands.
2978 Status
= EFI_SUCCESS
;
2984 // Sectors submitted for transfer
2986 SectorCount
= ByteCount
/ BlockSize
;
2989 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2990 BlocksRemaining
-= SectorCount
;
2993 Status
= EFI_SUCCESS
;
2996 if (BlkIo2Req
!= NULL
) {
2997 BlkIo2Req
->LastScsiRW
= TRUE
;
2999 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3000 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3001 RemoveEntryList (&BlkIo2Req
->Link
);
3002 FreePool (BlkIo2Req
);
3005 gBS
->SignalEvent (Token
->Event
);
3007 gBS
->RestoreTPL (OldTpl
);
3015 Submit Read(10) command.
3017 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3018 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3019 @param Timeout The time to complete the command
3020 @param DataBuffer The buffer to fill with the read out data
3021 @param DataLength The length of buffer
3022 @param StartLba The start logic block address
3023 @param SectorCount The number of blocks to read
3025 @return EFI_STATUS is returned by calling ScsiRead10Command().
3029 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3030 OUT BOOLEAN
*NeedRetry
,
3032 OUT UINT8
*DataBuffer
,
3033 IN OUT UINT32
*DataLength
,
3035 IN UINT32 SectorCount
3038 UINT8 SenseDataLength
;
3040 EFI_STATUS ReturnStatus
;
3041 UINT8 HostAdapterStatus
;
3046 // Implement a backoff algorithem to resolve some compatibility issues that
3047 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3048 // big data in a single operation.
3049 // This algorithem will at first try to execute original request. If the request fails
3050 // with media error sense data or else, it will reduce the transfer length to half and
3051 // try again till the operation succeeds or fails with one sector transfer length.
3055 Action
= ACTION_NO_ACTION
;
3056 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3057 ReturnStatus
= ScsiRead10Command (
3058 ScsiDiskDevice
->ScsiIo
,
3060 ScsiDiskDevice
->SenseData
,
3070 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3072 return EFI_DEVICE_ERROR
;
3073 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3075 return ReturnStatus
;
3079 // go ahead to check HostAdapterStatus and TargetStatus
3080 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3082 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3083 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3085 return EFI_DEVICE_ERROR
;
3086 } else if (Status
== EFI_DEVICE_ERROR
) {
3088 // reset the scsi channel
3090 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3092 return EFI_DEVICE_ERROR
;
3095 Status
= CheckTargetStatus (TargetStatus
);
3096 if (Status
== EFI_NOT_READY
) {
3098 // reset the scsi device
3100 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3102 return EFI_DEVICE_ERROR
;
3103 } else if (Status
== EFI_DEVICE_ERROR
) {
3105 return EFI_DEVICE_ERROR
;
3108 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3109 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
3110 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3111 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3113 return EFI_DEVICE_ERROR
;
3114 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3115 if (SectorCount
<= 1) {
3117 // Jump out if the operation still fails with one sector transfer length.
3120 return EFI_DEVICE_ERROR
;
3123 // Try again with half length if the sense data shows we need to retry.
3126 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3130 return EFI_DEVICE_ERROR
;
3134 return ReturnStatus
;
3139 Submit Write(10) Command.
3141 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3142 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3143 @param Timeout The time to complete the command
3144 @param DataBuffer The buffer to fill with the read out data
3145 @param DataLength The length of buffer
3146 @param StartLba The start logic block address
3147 @param SectorCount The number of blocks to write
3149 @return EFI_STATUS is returned by calling ScsiWrite10Command().
3154 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3155 OUT BOOLEAN
*NeedRetry
,
3157 IN UINT8
*DataBuffer
,
3158 IN OUT UINT32
*DataLength
,
3160 IN UINT32 SectorCount
3164 EFI_STATUS ReturnStatus
;
3165 UINT8 SenseDataLength
;
3166 UINT8 HostAdapterStatus
;
3171 // Implement a backoff algorithem to resolve some compatibility issues that
3172 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3173 // big data in a single operation.
3174 // This algorithem will at first try to execute original request. If the request fails
3175 // with media error sense data or else, it will reduce the transfer length to half and
3176 // try again till the operation succeeds or fails with one sector transfer length.
3180 Action
= ACTION_NO_ACTION
;
3181 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3182 ReturnStatus
= ScsiWrite10Command (
3183 ScsiDiskDevice
->ScsiIo
,
3185 ScsiDiskDevice
->SenseData
,
3194 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3196 return EFI_DEVICE_ERROR
;
3197 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3199 return ReturnStatus
;
3203 // go ahead to check HostAdapterStatus and TargetStatus
3204 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3206 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3207 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3209 return EFI_DEVICE_ERROR
;
3210 } else if (Status
== EFI_DEVICE_ERROR
) {
3212 // reset the scsi channel
3214 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3216 return EFI_DEVICE_ERROR
;
3219 Status
= CheckTargetStatus (TargetStatus
);
3220 if (Status
== EFI_NOT_READY
) {
3222 // reset the scsi device
3224 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3226 return EFI_DEVICE_ERROR
;
3227 } else if (Status
== EFI_DEVICE_ERROR
) {
3229 return EFI_DEVICE_ERROR
;
3232 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3233 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
3234 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3235 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3237 return EFI_DEVICE_ERROR
;
3238 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3239 if (SectorCount
<= 1) {
3241 // Jump out if the operation still fails with one sector transfer length.
3244 return EFI_DEVICE_ERROR
;
3247 // Try again with half length if the sense data shows we need to retry.
3250 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3254 return EFI_DEVICE_ERROR
;
3258 return ReturnStatus
;
3263 Submit Read(16) command.
3265 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3266 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3267 @param Timeout The time to complete the command
3268 @param DataBuffer The buffer to fill with the read out data
3269 @param DataLength The length of buffer
3270 @param StartLba The start logic block address
3271 @param SectorCount The number of blocks to read
3273 @return EFI_STATUS is returned by calling ScsiRead16Command().
3277 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3278 OUT BOOLEAN
*NeedRetry
,
3280 OUT UINT8
*DataBuffer
,
3281 IN OUT UINT32
*DataLength
,
3283 IN UINT32 SectorCount
3286 UINT8 SenseDataLength
;
3288 EFI_STATUS ReturnStatus
;
3289 UINT8 HostAdapterStatus
;
3294 // Implement a backoff algorithem to resolve some compatibility issues that
3295 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3296 // big data in a single operation.
3297 // This algorithem will at first try to execute original request. If the request fails
3298 // with media error sense data or else, it will reduce the transfer length to half and
3299 // try again till the operation succeeds or fails with one sector transfer length.
3303 Action
= ACTION_NO_ACTION
;
3304 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3305 ReturnStatus
= ScsiRead16Command (
3306 ScsiDiskDevice
->ScsiIo
,
3308 ScsiDiskDevice
->SenseData
,
3317 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3319 return EFI_DEVICE_ERROR
;
3320 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3322 return ReturnStatus
;
3326 // go ahead to check HostAdapterStatus and TargetStatus
3327 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3329 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3330 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3332 return EFI_DEVICE_ERROR
;
3333 } else if (Status
== EFI_DEVICE_ERROR
) {
3335 // reset the scsi channel
3337 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3339 return EFI_DEVICE_ERROR
;
3342 Status
= CheckTargetStatus (TargetStatus
);
3343 if (Status
== EFI_NOT_READY
) {
3345 // reset the scsi device
3347 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3349 return EFI_DEVICE_ERROR
;
3350 } else if (Status
== EFI_DEVICE_ERROR
) {
3352 return EFI_DEVICE_ERROR
;
3355 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3356 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
3357 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3358 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3360 return EFI_DEVICE_ERROR
;
3361 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3362 if (SectorCount
<= 1) {
3364 // Jump out if the operation still fails with one sector transfer length.
3367 return EFI_DEVICE_ERROR
;
3370 // Try again with half length if the sense data shows we need to retry.
3373 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3377 return EFI_DEVICE_ERROR
;
3381 return ReturnStatus
;
3386 Submit Write(16) Command.
3388 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3389 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3390 @param Timeout The time to complete the command
3391 @param DataBuffer The buffer to fill with the read out data
3392 @param DataLength The length of buffer
3393 @param StartLba The start logic block address
3394 @param SectorCount The number of blocks to write
3396 @return EFI_STATUS is returned by calling ScsiWrite16Command().
3401 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3402 OUT BOOLEAN
*NeedRetry
,
3404 IN UINT8
*DataBuffer
,
3405 IN OUT UINT32
*DataLength
,
3407 IN UINT32 SectorCount
3411 EFI_STATUS ReturnStatus
;
3412 UINT8 SenseDataLength
;
3413 UINT8 HostAdapterStatus
;
3418 // Implement a backoff algorithem to resolve some compatibility issues that
3419 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3420 // big data in a single operation.
3421 // This algorithem will at first try to execute original request. If the request fails
3422 // with media error sense data or else, it will reduce the transfer length to half and
3423 // try again till the operation succeeds or fails with one sector transfer length.
3427 Action
= ACTION_NO_ACTION
;
3428 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3429 ReturnStatus
= ScsiWrite16Command (
3430 ScsiDiskDevice
->ScsiIo
,
3432 ScsiDiskDevice
->SenseData
,
3441 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3443 return EFI_DEVICE_ERROR
;
3444 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3446 return ReturnStatus
;
3450 // go ahead to check HostAdapterStatus and TargetStatus
3451 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3453 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3454 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3456 return EFI_DEVICE_ERROR
;
3457 } else if (Status
== EFI_DEVICE_ERROR
) {
3459 // reset the scsi channel
3461 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3463 return EFI_DEVICE_ERROR
;
3466 Status
= CheckTargetStatus (TargetStatus
);
3467 if (Status
== EFI_NOT_READY
) {
3469 // reset the scsi device
3471 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3473 return EFI_DEVICE_ERROR
;
3474 } else if (Status
== EFI_DEVICE_ERROR
) {
3476 return EFI_DEVICE_ERROR
;
3479 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3480 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
3481 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3482 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3484 return EFI_DEVICE_ERROR
;
3485 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3486 if (SectorCount
<= 1) {
3488 // Jump out if the operation still fails with one sector transfer length.
3491 return EFI_DEVICE_ERROR
;
3494 // Try again with half length if the sense data shows we need to retry.
3497 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3501 return EFI_DEVICE_ERROR
;
3505 return ReturnStatus
;
3510 Internal helper notify function in which determine whether retry of a SCSI
3511 Read/Write command is needed and signal the event passed from Block I/O(2) if
3512 the SCSI I/O operation completes.
3514 @param Event The instance of EFI_EVENT.
3515 @param Context The parameter passed in.
3526 SCSI_ASYNC_RW_REQUEST
*Request
;
3527 SCSI_DISK_DEV
*ScsiDiskDevice
;
3528 EFI_BLOCK_IO2_TOKEN
*Token
;
3530 UINT32 OldDataLength
;
3531 UINT32 OldSectorCount
;
3534 gBS
->CloseEvent (Event
);
3536 Request
= (SCSI_ASYNC_RW_REQUEST
*) Context
;
3537 ScsiDiskDevice
= Request
->ScsiDiskDevice
;
3538 Token
= Request
->BlkIo2Req
->Token
;
3539 OldDataLength
= Request
->DataLength
;
3540 OldSectorCount
= Request
->SectorCount
;
3544 // If previous sub-tasks already fails, no need to process this sub-task.
3546 if (Token
->TransactionStatus
!= EFI_SUCCESS
) {
3551 // Check HostAdapterStatus and TargetStatus
3552 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3554 Status
= CheckHostAdapterStatus (Request
->HostAdapterStatus
);
3555 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3556 if (++Request
->TimesRetry
> MaxRetry
) {
3557 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3562 } else if (Status
== EFI_DEVICE_ERROR
) {
3564 // reset the scsi channel
3566 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3567 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3571 Status
= CheckTargetStatus (Request
->TargetStatus
);
3572 if (Status
== EFI_NOT_READY
) {
3574 // reset the scsi device
3576 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3577 if (++Request
->TimesRetry
> MaxRetry
) {
3578 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3583 } else if (Status
== EFI_DEVICE_ERROR
) {
3584 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3588 if (Request
->TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) {
3589 DEBUG ((EFI_D_ERROR
, "ScsiDiskNotify: Check Condition happened!\n"));
3591 Status
= DetectMediaParsingSenseKeys (
3594 Request
->SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
),
3597 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3598 if (++Request
->TimesRetry
> MaxRetry
) {
3599 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3604 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3605 if (Request
->SectorCount
<= 1) {
3607 // Jump out if the operation still fails with one sector transfer
3610 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3614 // Try again with two half length request if the sense data shows we need
3617 Request
->SectorCount
>>= 1;
3618 Request
->DataLength
= Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3619 Request
->TimesRetry
= 0;
3623 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3629 // This sub-task succeeds, no need to retry.
3634 if (Request
->InBuffer
!= NULL
) {
3636 // SCSI read command
3638 if (!ScsiDiskDevice
->Cdb16Byte
) {
3639 Status
= ScsiDiskAsyncRead10 (
3642 Request
->TimesRetry
,
3644 Request
->DataLength
,
3645 (UINT32
) Request
->StartLba
,
3646 Request
->SectorCount
,
3651 Status
= ScsiDiskAsyncRead16 (
3654 Request
->TimesRetry
,
3656 Request
->DataLength
,
3658 Request
->SectorCount
,
3664 if (EFI_ERROR (Status
)) {
3665 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3667 } else if (OldSectorCount
!= Request
->SectorCount
) {
3669 // Original sub-task will be split into two new sub-tasks with smaller
3672 if (!ScsiDiskDevice
->Cdb16Byte
) {
3673 Status
= ScsiDiskAsyncRead10 (
3677 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3678 OldDataLength
- Request
->DataLength
,
3679 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
3680 OldSectorCount
- Request
->SectorCount
,
3685 Status
= ScsiDiskAsyncRead16 (
3689 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3690 OldDataLength
- Request
->DataLength
,
3691 Request
->StartLba
+ Request
->SectorCount
,
3692 OldSectorCount
- Request
->SectorCount
,
3697 if (EFI_ERROR (Status
)) {
3698 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3704 // SCSI write command
3706 if (!ScsiDiskDevice
->Cdb16Byte
) {
3707 Status
= ScsiDiskAsyncWrite10 (
3710 Request
->TimesRetry
,
3712 Request
->DataLength
,
3713 (UINT32
) Request
->StartLba
,
3714 Request
->SectorCount
,
3719 Status
= ScsiDiskAsyncWrite16 (
3722 Request
->TimesRetry
,
3724 Request
->DataLength
,
3726 Request
->SectorCount
,
3732 if (EFI_ERROR (Status
)) {
3733 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3735 } else if (OldSectorCount
!= Request
->SectorCount
) {
3737 // Original sub-task will be split into two new sub-tasks with smaller
3740 if (!ScsiDiskDevice
->Cdb16Byte
) {
3741 Status
= ScsiDiskAsyncWrite10 (
3745 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3746 OldDataLength
- Request
->DataLength
,
3747 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
3748 OldSectorCount
- Request
->SectorCount
,
3753 Status
= ScsiDiskAsyncWrite16 (
3757 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3758 OldDataLength
- Request
->DataLength
,
3759 Request
->StartLba
+ Request
->SectorCount
,
3760 OldSectorCount
- Request
->SectorCount
,
3765 if (EFI_ERROR (Status
)) {
3766 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3773 RemoveEntryList (&Request
->Link
);
3774 if ((IsListEmpty (&Request
->BlkIo2Req
->ScsiRWQueue
)) &&
3775 (Request
->BlkIo2Req
->LastScsiRW
)) {
3777 // The last SCSI R/W command of a BlockIo2 request completes
3779 RemoveEntryList (&Request
->BlkIo2Req
->Link
);
3780 FreePool (Request
->BlkIo2Req
); // Should be freed only once
3781 gBS
->SignalEvent (Token
->Event
);
3784 FreePool (Request
->SenseData
);
3790 Submit Async Read(10) command.
3792 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3793 @param Timeout The time to complete the command.
3794 @param TimesRetry The number of times the command has been retried.
3795 @param DataBuffer The buffer to fill with the read out data.
3796 @param DataLength The length of buffer.
3797 @param StartLba The start logic block address.
3798 @param SectorCount The number of blocks to read.
3799 @param BlkIo2Req The upstream BlockIo2 request.
3800 @param Token The pointer to the token associated with the
3801 non-blocking read request.
3803 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3805 @return others Status returned by calling
3806 ScsiRead10CommandEx().
3810 ScsiDiskAsyncRead10 (
3811 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3813 IN UINT8 TimesRetry
,
3814 OUT UINT8
*DataBuffer
,
3815 IN UINT32 DataLength
,
3817 IN UINT32 SectorCount
,
3818 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3819 IN EFI_BLOCK_IO2_TOKEN
*Token
3823 SCSI_ASYNC_RW_REQUEST
*Request
;
3824 EFI_EVENT AsyncIoEvent
;
3827 AsyncIoEvent
= NULL
;
3829 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3830 if (Request
== NULL
) {
3831 return EFI_OUT_OF_RESOURCES
;
3834 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3835 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3836 gBS
->RestoreTPL (OldTpl
);
3838 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3839 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3840 if (Request
->SenseData
== NULL
) {
3841 Status
= EFI_OUT_OF_RESOURCES
;
3845 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3846 Request
->Timeout
= Timeout
;
3847 Request
->TimesRetry
= TimesRetry
;
3848 Request
->InBuffer
= DataBuffer
;
3849 Request
->DataLength
= DataLength
;
3850 Request
->StartLba
= StartLba
;
3851 Request
->SectorCount
= SectorCount
;
3852 Request
->BlkIo2Req
= BlkIo2Req
;
3857 Status
= gBS
->CreateEvent (
3864 if (EFI_ERROR(Status
)) {
3868 Status
= ScsiRead10CommandEx (
3869 ScsiDiskDevice
->ScsiIo
,
3872 &Request
->SenseDataLength
,
3873 &Request
->HostAdapterStatus
,
3874 &Request
->TargetStatus
,
3876 &Request
->DataLength
,
3877 (UINT32
) Request
->StartLba
,
3878 Request
->SectorCount
,
3881 if (EFI_ERROR(Status
)) {
3888 if (AsyncIoEvent
!= NULL
) {
3889 gBS
->CloseEvent (AsyncIoEvent
);
3892 if (Request
!= NULL
) {
3893 if (Request
->SenseData
!= NULL
) {
3894 FreePool (Request
->SenseData
);
3897 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3898 RemoveEntryList (&Request
->Link
);
3899 gBS
->RestoreTPL (OldTpl
);
3909 Submit Async Write(10) command.
3911 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3912 @param Timeout The time to complete the command.
3913 @param TimesRetry The number of times the command has been retried.
3914 @param DataBuffer The buffer contains the data to write.
3915 @param DataLength The length of buffer.
3916 @param StartLba The start logic block address.
3917 @param SectorCount The number of blocks to write.
3918 @param BlkIo2Req The upstream BlockIo2 request.
3919 @param Token The pointer to the token associated with the
3920 non-blocking read request.
3922 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3924 @return others Status returned by calling
3925 ScsiWrite10CommandEx().
3929 ScsiDiskAsyncWrite10 (
3930 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3932 IN UINT8 TimesRetry
,
3933 IN UINT8
*DataBuffer
,
3934 IN UINT32 DataLength
,
3936 IN UINT32 SectorCount
,
3937 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3938 IN EFI_BLOCK_IO2_TOKEN
*Token
3942 SCSI_ASYNC_RW_REQUEST
*Request
;
3943 EFI_EVENT AsyncIoEvent
;
3946 AsyncIoEvent
= NULL
;
3948 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3949 if (Request
== NULL
) {
3950 return EFI_OUT_OF_RESOURCES
;
3953 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3954 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3955 gBS
->RestoreTPL (OldTpl
);
3957 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3958 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3959 if (Request
->SenseData
== NULL
) {
3960 Status
= EFI_OUT_OF_RESOURCES
;
3964 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3965 Request
->Timeout
= Timeout
;
3966 Request
->TimesRetry
= TimesRetry
;
3967 Request
->OutBuffer
= DataBuffer
;
3968 Request
->DataLength
= DataLength
;
3969 Request
->StartLba
= StartLba
;
3970 Request
->SectorCount
= SectorCount
;
3971 Request
->BlkIo2Req
= BlkIo2Req
;
3976 Status
= gBS
->CreateEvent (
3983 if (EFI_ERROR(Status
)) {
3987 Status
= ScsiWrite10CommandEx (
3988 ScsiDiskDevice
->ScsiIo
,
3991 &Request
->SenseDataLength
,
3992 &Request
->HostAdapterStatus
,
3993 &Request
->TargetStatus
,
3995 &Request
->DataLength
,
3996 (UINT32
) Request
->StartLba
,
3997 Request
->SectorCount
,
4000 if (EFI_ERROR(Status
)) {
4007 if (AsyncIoEvent
!= NULL
) {
4008 gBS
->CloseEvent (AsyncIoEvent
);
4011 if (Request
!= NULL
) {
4012 if (Request
->SenseData
!= NULL
) {
4013 FreePool (Request
->SenseData
);
4016 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4017 RemoveEntryList (&Request
->Link
);
4018 gBS
->RestoreTPL (OldTpl
);
4028 Submit Async Read(16) command.
4030 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4031 @param Timeout The time to complete the command.
4032 @param TimesRetry The number of times the command has been retried.
4033 @param DataBuffer The buffer to fill with the read out data.
4034 @param DataLength The length of buffer.
4035 @param StartLba The start logic block address.
4036 @param SectorCount The number of blocks to read.
4037 @param BlkIo2Req The upstream BlockIo2 request.
4038 @param Token The pointer to the token associated with the
4039 non-blocking read request.
4041 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4043 @return others Status returned by calling
4044 ScsiRead16CommandEx().
4048 ScsiDiskAsyncRead16 (
4049 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4051 IN UINT8 TimesRetry
,
4052 OUT UINT8
*DataBuffer
,
4053 IN UINT32 DataLength
,
4055 IN UINT32 SectorCount
,
4056 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4057 IN EFI_BLOCK_IO2_TOKEN
*Token
4061 SCSI_ASYNC_RW_REQUEST
*Request
;
4062 EFI_EVENT AsyncIoEvent
;
4065 AsyncIoEvent
= NULL
;
4067 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4068 if (Request
== NULL
) {
4069 return EFI_OUT_OF_RESOURCES
;
4072 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4073 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4074 gBS
->RestoreTPL (OldTpl
);
4076 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4077 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4078 if (Request
->SenseData
== NULL
) {
4079 Status
= EFI_OUT_OF_RESOURCES
;
4083 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4084 Request
->Timeout
= Timeout
;
4085 Request
->TimesRetry
= TimesRetry
;
4086 Request
->InBuffer
= DataBuffer
;
4087 Request
->DataLength
= DataLength
;
4088 Request
->StartLba
= StartLba
;
4089 Request
->SectorCount
= SectorCount
;
4090 Request
->BlkIo2Req
= BlkIo2Req
;
4095 Status
= gBS
->CreateEvent (
4102 if (EFI_ERROR(Status
)) {
4106 Status
= ScsiRead16CommandEx (
4107 ScsiDiskDevice
->ScsiIo
,
4110 &Request
->SenseDataLength
,
4111 &Request
->HostAdapterStatus
,
4112 &Request
->TargetStatus
,
4114 &Request
->DataLength
,
4116 Request
->SectorCount
,
4119 if (EFI_ERROR(Status
)) {
4126 if (AsyncIoEvent
!= NULL
) {
4127 gBS
->CloseEvent (AsyncIoEvent
);
4130 if (Request
!= NULL
) {
4131 if (Request
->SenseData
!= NULL
) {
4132 FreePool (Request
->SenseData
);
4135 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4136 RemoveEntryList (&Request
->Link
);
4137 gBS
->RestoreTPL (OldTpl
);
4147 Submit Async Write(16) command.
4149 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4150 @param Timeout The time to complete the command.
4151 @param TimesRetry The number of times the command has been retried.
4152 @param DataBuffer The buffer contains the data to write.
4153 @param DataLength The length of buffer.
4154 @param StartLba The start logic block address.
4155 @param SectorCount The number of blocks to write.
4156 @param BlkIo2Req The upstream BlockIo2 request.
4157 @param Token The pointer to the token associated with the
4158 non-blocking read request.
4160 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4162 @return others Status returned by calling
4163 ScsiWrite16CommandEx().
4167 ScsiDiskAsyncWrite16 (
4168 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4170 IN UINT8 TimesRetry
,
4171 IN UINT8
*DataBuffer
,
4172 IN UINT32 DataLength
,
4174 IN UINT32 SectorCount
,
4175 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4176 IN EFI_BLOCK_IO2_TOKEN
*Token
4180 SCSI_ASYNC_RW_REQUEST
*Request
;
4181 EFI_EVENT AsyncIoEvent
;
4184 AsyncIoEvent
= NULL
;
4186 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4187 if (Request
== NULL
) {
4188 return EFI_OUT_OF_RESOURCES
;
4191 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4192 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4193 gBS
->RestoreTPL (OldTpl
);
4195 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4196 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4197 if (Request
->SenseData
== NULL
) {
4198 Status
= EFI_OUT_OF_RESOURCES
;
4202 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4203 Request
->Timeout
= Timeout
;
4204 Request
->TimesRetry
= TimesRetry
;
4205 Request
->OutBuffer
= DataBuffer
;
4206 Request
->DataLength
= DataLength
;
4207 Request
->StartLba
= StartLba
;
4208 Request
->SectorCount
= SectorCount
;
4209 Request
->BlkIo2Req
= BlkIo2Req
;
4214 Status
= gBS
->CreateEvent (
4221 if (EFI_ERROR(Status
)) {
4225 Status
= ScsiWrite16CommandEx (
4226 ScsiDiskDevice
->ScsiIo
,
4229 &Request
->SenseDataLength
,
4230 &Request
->HostAdapterStatus
,
4231 &Request
->TargetStatus
,
4233 &Request
->DataLength
,
4235 Request
->SectorCount
,
4238 if (EFI_ERROR(Status
)) {
4245 if (AsyncIoEvent
!= NULL
) {
4246 gBS
->CloseEvent (AsyncIoEvent
);
4249 if (Request
!= NULL
) {
4250 if (Request
->SenseData
!= NULL
) {
4251 FreePool (Request
->SenseData
);
4254 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4255 RemoveEntryList (&Request
->Link
);
4256 gBS
->RestoreTPL (OldTpl
);
4266 Check sense key to find if media presents.
4268 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4269 @param SenseCounts The number of sense key
4271 @retval TRUE NOT any media
4272 @retval FALSE Media presents
4276 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4277 IN UINTN SenseCounts
4280 EFI_SCSI_SENSE_DATA
*SensePtr
;
4285 SensePtr
= SenseData
;
4287 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4289 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
4290 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
4292 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
4293 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
4306 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4307 @param SenseCounts The number of sense key
4310 @retval FALSE NOT error
4314 ScsiDiskIsMediaError (
4315 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4316 IN UINTN SenseCounts
4319 EFI_SCSI_SENSE_DATA
*SensePtr
;
4324 SensePtr
= SenseData
;
4326 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4328 switch (SensePtr
->Sense_Key
) {
4330 case EFI_SCSI_SK_MEDIUM_ERROR
:
4332 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
4334 switch (SensePtr
->Addnl_Sense_Code
) {
4339 case EFI_SCSI_ASC_MEDIA_ERR1
:
4344 case EFI_SCSI_ASC_MEDIA_ERR2
:
4349 case EFI_SCSI_ASC_MEDIA_ERR3
:
4350 case EFI_SCSI_ASC_MEDIA_ERR4
:
4360 case EFI_SCSI_SK_NOT_READY
:
4362 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4364 switch (SensePtr
->Addnl_Sense_Code
) {
4366 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
4368 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
4389 Check sense key to find if hardware error happens.
4391 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4392 @param SenseCounts The number of sense key
4394 @retval TRUE Hardware error exits.
4395 @retval FALSE NO error.
4399 ScsiDiskIsHardwareError (
4400 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4401 IN UINTN SenseCounts
4404 EFI_SCSI_SENSE_DATA
*SensePtr
;
4409 SensePtr
= SenseData
;
4411 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4414 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
4416 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
4428 Check sense key to find if media has changed.
4430 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4431 @param SenseCounts The number of sense key
4433 @retval TRUE Media is changed.
4434 @retval FALSE Media is NOT changed.
4437 ScsiDiskIsMediaChange (
4438 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4439 IN UINTN SenseCounts
4442 EFI_SCSI_SENSE_DATA
*SensePtr
;
4444 BOOLEAN IsMediaChanged
;
4446 IsMediaChanged
= FALSE
;
4447 SensePtr
= SenseData
;
4449 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4451 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
4452 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
4454 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
4455 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
4456 IsMediaChanged
= TRUE
;
4462 return IsMediaChanged
;
4466 Check sense key to find if reset happens.
4468 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4469 @param SenseCounts The number of sense key
4471 @retval TRUE It is reset before.
4472 @retval FALSE It is NOT reset before.
4476 ScsiDiskIsResetBefore (
4477 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4478 IN UINTN SenseCounts
4481 EFI_SCSI_SENSE_DATA
*SensePtr
;
4483 BOOLEAN IsResetBefore
;
4485 IsResetBefore
= FALSE
;
4486 SensePtr
= SenseData
;
4488 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4491 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
4492 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
4494 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
4495 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
4496 IsResetBefore
= TRUE
;
4502 return IsResetBefore
;
4506 Check sense key to find if the drive is ready.
4508 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4509 @param SenseCounts The number of sense key
4510 @param RetryLater The flag means if need a retry
4512 @retval TRUE Drive is ready.
4513 @retval FALSE Drive is NOT ready.
4517 ScsiDiskIsDriveReady (
4518 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4519 IN UINTN SenseCounts
,
4520 OUT BOOLEAN
*RetryLater
4523 EFI_SCSI_SENSE_DATA
*SensePtr
;
4528 *RetryLater
= FALSE
;
4529 SensePtr
= SenseData
;
4531 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4533 switch (SensePtr
->Sense_Key
) {
4535 case EFI_SCSI_SK_NOT_READY
:
4537 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4539 switch (SensePtr
->Addnl_Sense_Code
) {
4540 case EFI_SCSI_ASC_NOT_READY
:
4542 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
4544 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
4545 case EFI_SCSI_ASCQ_IN_PROGRESS
:
4547 // Additional Sense Code Qualifier is
4548 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
4556 *RetryLater
= FALSE
;
4577 Check sense key to find if it has sense key.
4579 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
4580 @param SenseCounts - The number of sense key
4582 @retval TRUE It has sense key.
4583 @retval FALSE It has NOT any sense key.
4587 ScsiDiskHaveSenseKey (
4588 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4589 IN UINTN SenseCounts
4592 EFI_SCSI_SENSE_DATA
*SensePtr
;
4594 BOOLEAN HaveSenseKey
;
4596 if (SenseCounts
== 0) {
4597 HaveSenseKey
= FALSE
;
4599 HaveSenseKey
= TRUE
;
4602 SensePtr
= SenseData
;
4604 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4607 // Sense Key is SK_NO_SENSE (0x0)
4609 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
4611 HaveSenseKey
= FALSE
;
4617 return HaveSenseKey
;
4621 Release resource about disk device.
4623 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4627 ReleaseScsiDiskDeviceResources (
4628 IN SCSI_DISK_DEV
*ScsiDiskDevice
4631 if (ScsiDiskDevice
== NULL
) {
4635 if (ScsiDiskDevice
->SenseData
!= NULL
) {
4636 FreePool (ScsiDiskDevice
->SenseData
);
4637 ScsiDiskDevice
->SenseData
= NULL
;
4640 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
4641 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
4642 ScsiDiskDevice
->ControllerNameTable
= NULL
;
4645 FreePool (ScsiDiskDevice
);
4647 ScsiDiskDevice
= NULL
;
4651 Determine if Block Io & Block Io2 should be produced.
4654 @param ChildHandle Child Handle to retrieve Parent information.
4656 @retval TRUE Should produce Block Io & Block Io2.
4657 @retval FALSE Should not produce Block Io & Block Io2.
4661 DetermineInstallBlockIo (
4662 IN EFI_HANDLE ChildHandle
4665 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
4666 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
4669 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
4670 // check its attribute, logic or physical.
4672 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
4673 if (ExtScsiPassThru
!= NULL
) {
4674 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
4680 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
4681 // check its attribute, logic or physical.
4683 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
4684 if (ScsiPassThru
!= NULL
) {
4685 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
4694 Search protocol database and check to see if the protocol
4695 specified by ProtocolGuid is present on a ControllerHandle and opened by
4696 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
4697 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
4698 will be opened on it.
4701 @param ProtocolGuid ProtocolGuid pointer.
4702 @param ChildHandle Child Handle to retrieve Parent information.
4708 IN EFI_GUID
*ProtocolGuid
,
4709 IN EFI_HANDLE ChildHandle
4716 EFI_HANDLE
*HandleBuffer
;
4719 // Retrieve the list of all handles from the handle database
4721 Status
= gBS
->LocateHandleBuffer (
4729 if (EFI_ERROR (Status
)) {
4734 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
4736 for (Index
= 0; Index
< HandleCount
; Index
++) {
4737 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
4738 if (!EFI_ERROR (Status
)) {
4739 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
4740 if (!EFI_ERROR (Status
)) {
4741 gBS
->FreePool (HandleBuffer
);
4747 gBS
->FreePool (HandleBuffer
);
4752 Provides inquiry information for the controller type.
4754 This function is used by the IDE bus driver to get inquiry data. Data format
4755 of Identify data is defined by the Interface GUID.
4757 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4758 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
4759 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
4761 @retval EFI_SUCCESS The command was accepted without any errors.
4762 @retval EFI_NOT_FOUND Device does not support this data class
4763 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
4764 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
4769 ScsiDiskInfoInquiry (
4770 IN EFI_DISK_INFO_PROTOCOL
*This
,
4771 IN OUT VOID
*InquiryData
,
4772 IN OUT UINT32
*InquiryDataSize
4776 SCSI_DISK_DEV
*ScsiDiskDevice
;
4778 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4780 Status
= EFI_BUFFER_TOO_SMALL
;
4781 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
4782 Status
= EFI_SUCCESS
;
4783 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
4785 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
4791 Provides identify information for the controller type.
4793 This function is used by the IDE bus driver to get identify data. Data format
4794 of Identify data is defined by the Interface GUID.
4796 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
4798 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
4799 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
4802 @retval EFI_SUCCESS The command was accepted without any errors.
4803 @retval EFI_NOT_FOUND Device does not support this data class
4804 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
4805 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
4810 ScsiDiskInfoIdentify (
4811 IN EFI_DISK_INFO_PROTOCOL
*This
,
4812 IN OUT VOID
*IdentifyData
,
4813 IN OUT UINT32
*IdentifyDataSize
4817 SCSI_DISK_DEV
*ScsiDiskDevice
;
4819 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
4821 // Physical SCSI bus does not support this data class.
4823 return EFI_NOT_FOUND
;
4826 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4828 Status
= EFI_BUFFER_TOO_SMALL
;
4829 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
4830 Status
= EFI_SUCCESS
;
4831 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
4833 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
4838 Provides sense data information for the controller type.
4840 This function is used by the IDE bus driver to get sense data.
4841 Data format of Sense data is defined by the Interface GUID.
4843 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4844 @param[in, out] SenseData Pointer to the SenseData.
4845 @param[in, out] SenseDataSize Size of SenseData in bytes.
4846 @param[out] SenseDataNumber Pointer to the value for the sense data size.
4848 @retval EFI_SUCCESS The command was accepted without any errors.
4849 @retval EFI_NOT_FOUND Device does not support this data class.
4850 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
4851 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
4856 ScsiDiskInfoSenseData (
4857 IN EFI_DISK_INFO_PROTOCOL
*This
,
4858 IN OUT VOID
*SenseData
,
4859 IN OUT UINT32
*SenseDataSize
,
4860 OUT UINT8
*SenseDataNumber
4863 return EFI_NOT_FOUND
;
4868 This function is used by the IDE bus driver to get controller information.
4870 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4871 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
4872 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
4874 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
4875 @retval EFI_UNSUPPORTED This is not an IDE device.
4880 ScsiDiskInfoWhichIde (
4881 IN EFI_DISK_INFO_PROTOCOL
*This
,
4882 OUT UINT32
*IdeChannel
,
4883 OUT UINT32
*IdeDevice
4886 SCSI_DISK_DEV
*ScsiDiskDevice
;
4888 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
4890 // This is not an IDE physical device.
4892 return EFI_UNSUPPORTED
;
4895 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4896 *IdeChannel
= ScsiDiskDevice
->Channel
;
4897 *IdeDevice
= ScsiDiskDevice
->Device
;
4904 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
4906 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
4907 implement Identify() interface for DiskInfo protocol. The ATA command is sent
4908 via SCSI Request Packet.
4910 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4912 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
4913 @retval others Some error occurred during the identification that ATAPI device.
4917 AtapiIdentifyDevice (
4918 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
4921 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
4925 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
4927 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
4928 ZeroMem (Cdb
, sizeof (Cdb
));
4930 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
4931 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
4932 CommandPacket
.Cdb
= Cdb
;
4933 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
4934 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
4935 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
4937 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
4942 Initialize the installation of DiskInfo protocol.
4944 This function prepares for the installation of DiskInfo protocol on the child handle.
4945 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
4946 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
4947 to be IDE/AHCI interface GUID.
4949 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
4950 @param ChildHandle Child handle to install DiskInfo protocol.
4954 InitializeInstallDiskInfo (
4955 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4956 IN EFI_HANDLE ChildHandle
4960 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
4961 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
4962 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
4963 SATA_DEVICE_PATH
*SataDevicePath
;
4964 UINTN IdentifyRetry
;
4966 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
4968 // Device Path protocol must be installed on the device handle.
4970 ASSERT_EFI_ERROR (Status
);
4972 // Copy the DiskInfo protocol template.
4974 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
4976 while (!IsDevicePathEnd (DevicePathNode
)) {
4977 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
4978 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
4979 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
4980 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
4981 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
4982 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
4987 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
4988 // with IDE/AHCI interface GUID.
4990 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
4991 if (!EFI_ERROR (Status
)) {
4992 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
4994 // We find the valid ATAPI device path
4996 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
4997 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
4998 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
5000 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
5002 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
5005 // We find the valid SATA device path
5007 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
5008 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
5009 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
5011 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
5013 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
5017 } while (--IdentifyRetry
> 0);
5018 } else if ((DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
5019 (DevicePathSubType (ChildDevicePathNode
) == MSG_UFS_DP
)) {
5020 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoUfsInterfaceGuid
);
5023 DevicePathNode
= ChildDevicePathNode
;