2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding
= {
19 ScsiDiskDriverBindingSupported
,
20 ScsiDiskDriverBindingStart
,
21 ScsiDiskDriverBindingStop
,
27 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate
= {
28 EFI_DISK_INFO_SCSI_INTERFACE_GUID
,
31 ScsiDiskInfoSenseData
,
36 Allocates an aligned buffer for SCSI disk.
38 This function allocates an aligned buffer for the SCSI disk to perform
39 SCSI IO operations. The alignment requirement is from SCSI IO interface.
41 @param ScsiDiskDevice The SCSI disk involved for the operation.
42 @param BufferSize The request buffer size.
44 @return A pointer to the aligned buffer or NULL if the allocation fails.
48 AllocateAlignedBuffer (
49 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
53 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), ScsiDiskDevice
->ScsiIo
->IoAlign
);
57 Frees an aligned buffer for SCSI disk.
59 This function frees an aligned buffer for the SCSI disk to perform
62 @param Buffer The aligned buffer to be freed.
63 @param BufferSize The request buffer size.
73 FreeAlignedPages (Buffer
, EFI_SIZE_TO_PAGES (BufferSize
));
78 The user Entry Point for module ScsiDisk.
80 The user code starts with this function.
82 @param ImageHandle The firmware allocated handle for the EFI image.
83 @param SystemTable A pointer to the EFI System Table.
85 @retval EFI_SUCCESS The entry point is executed successfully.
86 @retval other Some error occurs when executing this entry point.
92 IN EFI_HANDLE ImageHandle
,
93 IN EFI_SYSTEM_TABLE
*SystemTable
99 // Install driver model protocol(s).
101 Status
= EfiLibInstallDriverBindingComponentName2 (
104 &gScsiDiskDriverBinding
,
106 &gScsiDiskComponentName
,
107 &gScsiDiskComponentName2
109 ASSERT_EFI_ERROR (Status
);
116 Test to see if this driver supports ControllerHandle.
118 This service is called by the EFI boot service ConnectController(). In order
119 to make drivers as small as possible, there are a few calling restrictions for
120 this service. ConnectController() must follow these calling restrictions.
121 If any other agent wishes to call Supported() it must also follow these
122 calling restrictions.
124 @param This Protocol instance pointer.
125 @param ControllerHandle Handle of device to test
126 @param RemainingDevicePath Optional parameter use to pick a specific child
129 @retval EFI_SUCCESS This driver supports this device
130 @retval EFI_ALREADY_STARTED This driver is already running on this device
131 @retval other This driver does not support this device
136 ScsiDiskDriverBindingSupported (
137 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
138 IN EFI_HANDLE Controller
,
139 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
143 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
146 Status
= gBS
->OpenProtocol (
148 &gEfiScsiIoProtocolGuid
,
150 This
->DriverBindingHandle
,
152 EFI_OPEN_PROTOCOL_BY_DRIVER
154 if (EFI_ERROR (Status
)) {
158 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
159 if (!EFI_ERROR (Status
)) {
160 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) || (DeviceType
== EFI_SCSI_TYPE_CDROM
)) {
161 Status
= EFI_SUCCESS
;
163 Status
= EFI_UNSUPPORTED
;
169 &gEfiScsiIoProtocolGuid
,
170 This
->DriverBindingHandle
,
178 Start this driver on ControllerHandle.
180 This service is called by the EFI boot service ConnectController(). In order
181 to make drivers as small as possible, there are a few calling restrictions for
182 this service. ConnectController() must follow these calling restrictions. If
183 any other agent wishes to call Start() it must also follow these calling
186 @param This Protocol instance pointer.
187 @param ControllerHandle Handle of device to bind driver to
188 @param RemainingDevicePath Optional parameter use to pick a specific child
191 @retval EFI_SUCCESS This driver is added to ControllerHandle
192 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
193 @retval other This driver does not support this device
198 ScsiDiskDriverBindingStart (
199 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
200 IN EFI_HANDLE Controller
,
201 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
205 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
206 SCSI_DISK_DEV
*ScsiDiskDevice
;
211 BOOLEAN MustReadCapacity
;
213 MustReadCapacity
= TRUE
;
215 ScsiDiskDevice
= (SCSI_DISK_DEV
*) AllocateZeroPool (sizeof (SCSI_DISK_DEV
));
216 if (ScsiDiskDevice
== NULL
) {
217 return EFI_OUT_OF_RESOURCES
;
220 Status
= gBS
->OpenProtocol (
222 &gEfiScsiIoProtocolGuid
,
224 This
->DriverBindingHandle
,
226 EFI_OPEN_PROTOCOL_BY_DRIVER
228 if (EFI_ERROR (Status
)) {
229 FreePool (ScsiDiskDevice
);
233 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
234 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
235 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION3
;
236 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
237 ScsiDiskDevice
->BlkIo
.Media
->IoAlign
= ScsiIo
->IoAlign
;
238 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
239 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
240 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
241 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
242 ScsiDiskDevice
->BlkIo2
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
243 ScsiDiskDevice
->BlkIo2
.Reset
= ScsiDiskResetEx
;
244 ScsiDiskDevice
->BlkIo2
.ReadBlocksEx
= ScsiDiskReadBlocksEx
;
245 ScsiDiskDevice
->BlkIo2
.WriteBlocksEx
= ScsiDiskWriteBlocksEx
;
246 ScsiDiskDevice
->BlkIo2
.FlushBlocksEx
= ScsiDiskFlushBlocksEx
;
247 ScsiDiskDevice
->Handle
= Controller
;
248 InitializeListHead (&ScsiDiskDevice
->BlkIo2Queue
);
250 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
251 switch (ScsiDiskDevice
->DeviceType
) {
252 case EFI_SCSI_TYPE_DISK
:
253 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
254 MustReadCapacity
= TRUE
;
257 case EFI_SCSI_TYPE_CDROM
:
258 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
259 ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
= TRUE
;
260 MustReadCapacity
= FALSE
;
264 // The Sense Data Array's initial size is 6
266 ScsiDiskDevice
->SenseDataNumber
= 6;
267 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
268 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
270 if (ScsiDiskDevice
->SenseData
== NULL
) {
273 &gEfiScsiIoProtocolGuid
,
274 This
->DriverBindingHandle
,
277 FreePool (ScsiDiskDevice
);
278 return EFI_OUT_OF_RESOURCES
;
282 // Retrieve device information
285 for (Index
= 0; Index
< MaxRetry
; Index
++) {
286 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
287 if (!EFI_ERROR (Status
)) {
292 FreePool (ScsiDiskDevice
->SenseData
);
295 &gEfiScsiIoProtocolGuid
,
296 This
->DriverBindingHandle
,
299 FreePool (ScsiDiskDevice
);
300 return EFI_DEVICE_ERROR
;
304 // The second parameter "TRUE" means must
305 // retrieve media capacity
307 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, MustReadCapacity
, &Temp
);
308 if (!EFI_ERROR (Status
)) {
310 // Determine if Block IO & Block IO2 should be produced on this controller
313 if (DetermineInstallBlockIo(Controller
)) {
314 InitializeInstallDiskInfo(ScsiDiskDevice
, Controller
);
315 Status
= gBS
->InstallMultipleProtocolInterfaces (
317 &gEfiBlockIoProtocolGuid
,
318 &ScsiDiskDevice
->BlkIo
,
319 &gEfiBlockIo2ProtocolGuid
,
320 &ScsiDiskDevice
->BlkIo2
,
321 &gEfiDiskInfoProtocolGuid
,
322 &ScsiDiskDevice
->DiskInfo
,
325 if (!EFI_ERROR(Status
)) {
326 ScsiDiskDevice
->ControllerNameTable
= NULL
;
329 gScsiDiskComponentName
.SupportedLanguages
,
330 &ScsiDiskDevice
->ControllerNameTable
,
336 gScsiDiskComponentName2
.SupportedLanguages
,
337 &ScsiDiskDevice
->ControllerNameTable
,
346 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
347 gBS
->FreePool (ScsiDiskDevice
);
350 &gEfiScsiIoProtocolGuid
,
351 This
->DriverBindingHandle
,
360 Stop this driver on ControllerHandle.
362 This service is called by the EFI boot service DisconnectController().
363 In order to make drivers as small as possible, there are a few calling
364 restrictions for this service. DisconnectController() must follow these
365 calling restrictions. If any other agent wishes to call Stop() it must
366 also follow these calling restrictions.
368 @param This Protocol instance pointer.
369 @param ControllerHandle Handle of device to stop driver on
370 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
371 children is zero stop the entire bus driver.
372 @param ChildHandleBuffer List of Child Handles to Stop.
374 @retval EFI_SUCCESS This driver is removed ControllerHandle
375 @retval other This driver was not removed from this device
380 ScsiDiskDriverBindingStop (
381 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
382 IN EFI_HANDLE Controller
,
383 IN UINTN NumberOfChildren
,
384 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
387 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
388 SCSI_DISK_DEV
*ScsiDiskDevice
;
391 Status
= gBS
->OpenProtocol (
393 &gEfiBlockIoProtocolGuid
,
395 This
->DriverBindingHandle
,
397 EFI_OPEN_PROTOCOL_GET_PROTOCOL
399 if (EFI_ERROR (Status
)) {
403 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (BlkIo
);
406 // Wait for the BlockIo2 requests queue to become empty
408 while (!IsListEmpty (&ScsiDiskDevice
->BlkIo2Queue
));
410 Status
= gBS
->UninstallMultipleProtocolInterfaces (
412 &gEfiBlockIoProtocolGuid
,
413 &ScsiDiskDevice
->BlkIo
,
414 &gEfiBlockIo2ProtocolGuid
,
415 &ScsiDiskDevice
->BlkIo2
,
416 &gEfiDiskInfoProtocolGuid
,
417 &ScsiDiskDevice
->DiskInfo
,
420 if (!EFI_ERROR (Status
)) {
423 &gEfiScsiIoProtocolGuid
,
424 This
->DriverBindingHandle
,
428 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
442 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
443 @param ExtendedVerification The flag about if extend verificate
445 @retval EFI_SUCCESS The device was reset.
446 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
448 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
454 IN EFI_BLOCK_IO_PROTOCOL
*This
,
455 IN BOOLEAN ExtendedVerification
459 SCSI_DISK_DEV
*ScsiDiskDevice
;
462 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
464 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
466 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
468 if (EFI_ERROR (Status
)) {
469 if (Status
== EFI_UNSUPPORTED
) {
470 Status
= EFI_SUCCESS
;
472 Status
= EFI_DEVICE_ERROR
;
477 if (!ExtendedVerification
) {
481 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
483 if (EFI_ERROR (Status
)) {
484 Status
= EFI_DEVICE_ERROR
;
489 gBS
->RestoreTPL (OldTpl
);
494 The function is to Read Block from SCSI Disk.
496 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
497 @param MediaId The Id of Media detected
498 @param Lba The logic block address
499 @param BufferSize The size of Buffer
500 @param Buffer The buffer to fill the read out data
502 @retval EFI_SUCCESS Successfully to read out block.
503 @retval EFI_DEVICE_ERROR Fail to detect media.
504 @retval EFI_NO_MEDIA Media is not present.
505 @retval EFI_MEDIA_CHANGED Media has changed.
506 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
507 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
513 IN EFI_BLOCK_IO_PROTOCOL
*This
,
520 SCSI_DISK_DEV
*ScsiDiskDevice
;
521 EFI_BLOCK_IO_MEDIA
*Media
;
524 UINTN NumberOfBlocks
;
529 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
530 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
532 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
534 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
535 if (EFI_ERROR (Status
)) {
536 Status
= EFI_DEVICE_ERROR
;
541 gBS
->ReinstallProtocolInterface (
542 ScsiDiskDevice
->Handle
,
543 &gEfiBlockIoProtocolGuid
,
544 &ScsiDiskDevice
->BlkIo
,
545 &ScsiDiskDevice
->BlkIo
547 gBS
->ReinstallProtocolInterface (
548 ScsiDiskDevice
->Handle
,
549 &gEfiBlockIo2ProtocolGuid
,
550 &ScsiDiskDevice
->BlkIo2
,
551 &ScsiDiskDevice
->BlkIo2
553 Status
= EFI_MEDIA_CHANGED
;
558 // Get the intrinsic block size
560 Media
= ScsiDiskDevice
->BlkIo
.Media
;
561 BlockSize
= Media
->BlockSize
;
563 NumberOfBlocks
= BufferSize
/ BlockSize
;
565 if (!(Media
->MediaPresent
)) {
566 Status
= EFI_NO_MEDIA
;
570 if (MediaId
!= Media
->MediaId
) {
571 Status
= EFI_MEDIA_CHANGED
;
575 if (Buffer
== NULL
) {
576 Status
= EFI_INVALID_PARAMETER
;
580 if (BufferSize
== 0) {
581 Status
= EFI_SUCCESS
;
585 if (BufferSize
% BlockSize
!= 0) {
586 Status
= EFI_BAD_BUFFER_SIZE
;
590 if (Lba
> Media
->LastBlock
) {
591 Status
= EFI_INVALID_PARAMETER
;
595 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
596 Status
= EFI_INVALID_PARAMETER
;
600 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
601 Status
= EFI_INVALID_PARAMETER
;
606 // If all the parameters are valid, then perform read sectors command
607 // to transfer data from device to host.
609 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
612 gBS
->RestoreTPL (OldTpl
);
617 The function is to Write Block to SCSI Disk.
619 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
620 @param MediaId The Id of Media detected
621 @param Lba The logic block address
622 @param BufferSize The size of Buffer
623 @param Buffer The buffer to fill the read out data
625 @retval EFI_SUCCESS Successfully to read out block.
626 @retval EFI_WRITE_PROTECTED The device can not be written to.
627 @retval EFI_DEVICE_ERROR Fail to detect media.
628 @retval EFI_NO_MEDIA Media is not present.
629 @retval EFI_MEDIA_CHNAGED Media has changed.
630 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
631 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
636 ScsiDiskWriteBlocks (
637 IN EFI_BLOCK_IO_PROTOCOL
*This
,
644 SCSI_DISK_DEV
*ScsiDiskDevice
;
645 EFI_BLOCK_IO_MEDIA
*Media
;
648 UINTN NumberOfBlocks
;
653 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
654 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
656 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
658 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
659 if (EFI_ERROR (Status
)) {
660 Status
= EFI_DEVICE_ERROR
;
665 gBS
->ReinstallProtocolInterface (
666 ScsiDiskDevice
->Handle
,
667 &gEfiBlockIoProtocolGuid
,
668 &ScsiDiskDevice
->BlkIo
,
669 &ScsiDiskDevice
->BlkIo
671 gBS
->ReinstallProtocolInterface (
672 ScsiDiskDevice
->Handle
,
673 &gEfiBlockIo2ProtocolGuid
,
674 &ScsiDiskDevice
->BlkIo2
,
675 &ScsiDiskDevice
->BlkIo2
677 Status
= EFI_MEDIA_CHANGED
;
682 // Get the intrinsic block size
684 Media
= ScsiDiskDevice
->BlkIo
.Media
;
685 BlockSize
= Media
->BlockSize
;
687 NumberOfBlocks
= BufferSize
/ BlockSize
;
689 if (!(Media
->MediaPresent
)) {
690 Status
= EFI_NO_MEDIA
;
694 if (MediaId
!= Media
->MediaId
) {
695 Status
= EFI_MEDIA_CHANGED
;
699 if (Media
->ReadOnly
) {
700 Status
= EFI_WRITE_PROTECTED
;
704 if (BufferSize
== 0) {
705 Status
= EFI_SUCCESS
;
709 if (Buffer
== NULL
) {
710 Status
= EFI_INVALID_PARAMETER
;
714 if (BufferSize
% BlockSize
!= 0) {
715 Status
= EFI_BAD_BUFFER_SIZE
;
719 if (Lba
> Media
->LastBlock
) {
720 Status
= EFI_INVALID_PARAMETER
;
724 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
725 Status
= EFI_INVALID_PARAMETER
;
729 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
730 Status
= EFI_INVALID_PARAMETER
;
734 // if all the parameters are valid, then perform read sectors command
735 // to transfer data from device to host.
737 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
740 gBS
->RestoreTPL (OldTpl
);
747 EFI_SUCCESS is returned directly.
749 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
751 @retval EFI_SUCCESS All outstanding data was written to the device
756 ScsiDiskFlushBlocks (
757 IN EFI_BLOCK_IO_PROTOCOL
*This
770 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
771 @param ExtendedVerification The flag about if extend verificate.
773 @retval EFI_SUCCESS The device was reset.
774 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
776 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
782 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
783 IN BOOLEAN ExtendedVerification
787 SCSI_DISK_DEV
*ScsiDiskDevice
;
790 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
792 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
794 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
796 if (EFI_ERROR (Status
)) {
797 if (Status
== EFI_UNSUPPORTED
) {
798 Status
= EFI_SUCCESS
;
800 Status
= EFI_DEVICE_ERROR
;
805 if (!ExtendedVerification
) {
809 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
811 if (EFI_ERROR (Status
)) {
812 Status
= EFI_DEVICE_ERROR
;
817 gBS
->RestoreTPL (OldTpl
);
822 The function is to Read Block from SCSI Disk.
824 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
825 @param MediaId The Id of Media detected.
826 @param Lba The logic block address.
827 @param Token A pointer to the token associated with the transaction.
828 @param BufferSize The size of Buffer.
829 @param Buffer The buffer to fill the read out data.
831 @retval EFI_SUCCESS The read request was queued if Token-> Event is
832 not NULL. The data was read correctly from the
833 device if theToken-> Event is NULL.
834 @retval EFI_DEVICE_ERROR The device reported an error while attempting
835 to perform the read operation.
836 @retval EFI_NO_MEDIA There is no media in the device.
837 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
838 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
839 the intrinsic block size of the device.
840 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
841 valid, or the buffer is not on proper
843 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
849 ScsiDiskReadBlocksEx (
850 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
853 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
858 SCSI_DISK_DEV
*ScsiDiskDevice
;
859 EFI_BLOCK_IO_MEDIA
*Media
;
862 UINTN NumberOfBlocks
;
867 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
868 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
870 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
872 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
873 if (EFI_ERROR (Status
)) {
874 Status
= EFI_DEVICE_ERROR
;
879 gBS
->ReinstallProtocolInterface (
880 ScsiDiskDevice
->Handle
,
881 &gEfiBlockIoProtocolGuid
,
882 &ScsiDiskDevice
->BlkIo
,
883 &ScsiDiskDevice
->BlkIo
885 gBS
->ReinstallProtocolInterface (
886 ScsiDiskDevice
->Handle
,
887 &gEfiBlockIo2ProtocolGuid
,
888 &ScsiDiskDevice
->BlkIo2
,
889 &ScsiDiskDevice
->BlkIo2
891 Status
= EFI_MEDIA_CHANGED
;
896 // Get the intrinsic block size
898 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
899 BlockSize
= Media
->BlockSize
;
901 NumberOfBlocks
= BufferSize
/ BlockSize
;
903 if (!(Media
->MediaPresent
)) {
904 Status
= EFI_NO_MEDIA
;
908 if (MediaId
!= Media
->MediaId
) {
909 Status
= EFI_MEDIA_CHANGED
;
913 if (Buffer
== NULL
) {
914 Status
= EFI_INVALID_PARAMETER
;
918 if (BufferSize
== 0) {
919 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
920 Token
->TransactionStatus
= EFI_SUCCESS
;
921 gBS
->SignalEvent (Token
->Event
);
924 Status
= EFI_SUCCESS
;
928 if (BufferSize
% BlockSize
!= 0) {
929 Status
= EFI_BAD_BUFFER_SIZE
;
933 if (Lba
> Media
->LastBlock
) {
934 Status
= EFI_INVALID_PARAMETER
;
938 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
939 Status
= EFI_INVALID_PARAMETER
;
943 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
944 Status
= EFI_INVALID_PARAMETER
;
949 // If all the parameters are valid, then perform read sectors command
950 // to transfer data from device to host.
952 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
953 Token
->TransactionStatus
= EFI_SUCCESS
;
954 Status
= ScsiDiskAsyncReadSectors (
962 Status
= ScsiDiskReadSectors (
971 gBS
->RestoreTPL (OldTpl
);
976 The function is to Write Block to SCSI Disk.
978 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
979 @param MediaId The Id of Media detected.
980 @param Lba The logic block address.
981 @param Token A pointer to the token associated with the transaction.
982 @param BufferSize The size of Buffer.
983 @param Buffer The buffer to fill the read out data.
985 @retval EFI_SUCCESS The data were written correctly to the device.
986 @retval EFI_WRITE_PROTECTED The device cannot be written to.
987 @retval EFI_NO_MEDIA There is no media in the device.
988 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
989 @retval EFI_DEVICE_ERROR The device reported an error while attempting
990 to perform the write operation.
991 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
992 the intrinsic block size of the device.
993 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
994 valid, or the buffer is not on proper
1000 ScsiDiskWriteBlocksEx (
1001 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1004 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1005 IN UINTN BufferSize
,
1009 SCSI_DISK_DEV
*ScsiDiskDevice
;
1010 EFI_BLOCK_IO_MEDIA
*Media
;
1013 UINTN NumberOfBlocks
;
1014 BOOLEAN MediaChange
;
1017 MediaChange
= FALSE
;
1018 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1019 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1021 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1023 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1024 if (EFI_ERROR (Status
)) {
1025 Status
= EFI_DEVICE_ERROR
;
1030 gBS
->ReinstallProtocolInterface (
1031 ScsiDiskDevice
->Handle
,
1032 &gEfiBlockIoProtocolGuid
,
1033 &ScsiDiskDevice
->BlkIo
,
1034 &ScsiDiskDevice
->BlkIo
1036 gBS
->ReinstallProtocolInterface (
1037 ScsiDiskDevice
->Handle
,
1038 &gEfiBlockIo2ProtocolGuid
,
1039 &ScsiDiskDevice
->BlkIo2
,
1040 &ScsiDiskDevice
->BlkIo2
1042 Status
= EFI_MEDIA_CHANGED
;
1047 // Get the intrinsic block size
1049 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
1050 BlockSize
= Media
->BlockSize
;
1052 NumberOfBlocks
= BufferSize
/ BlockSize
;
1054 if (!(Media
->MediaPresent
)) {
1055 Status
= EFI_NO_MEDIA
;
1059 if (MediaId
!= Media
->MediaId
) {
1060 Status
= EFI_MEDIA_CHANGED
;
1064 if (Media
->ReadOnly
) {
1065 Status
= EFI_WRITE_PROTECTED
;
1069 if (BufferSize
== 0) {
1070 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1071 Token
->TransactionStatus
= EFI_SUCCESS
;
1072 gBS
->SignalEvent (Token
->Event
);
1075 Status
= EFI_SUCCESS
;
1079 if (Buffer
== NULL
) {
1080 Status
= EFI_INVALID_PARAMETER
;
1084 if (BufferSize
% BlockSize
!= 0) {
1085 Status
= EFI_BAD_BUFFER_SIZE
;
1089 if (Lba
> Media
->LastBlock
) {
1090 Status
= EFI_INVALID_PARAMETER
;
1094 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1095 Status
= EFI_INVALID_PARAMETER
;
1099 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1100 Status
= EFI_INVALID_PARAMETER
;
1105 // if all the parameters are valid, then perform write sectors command
1106 // to transfer data from device to host.
1108 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1109 Token
->TransactionStatus
= EFI_SUCCESS
;
1110 Status
= ScsiDiskAsyncWriteSectors (
1118 Status
= ScsiDiskWriteSectors (
1127 gBS
->RestoreTPL (OldTpl
);
1132 Flush the Block Device.
1134 @param This Indicates a pointer to the calling context.
1135 @param Token A pointer to the token associated with the transaction.
1137 @retval EFI_SUCCESS All outstanding data was written to the device.
1138 @retval EFI_DEVICE_ERROR The device reported an error while attempting to
1140 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1141 @retval EFI_NO_MEDIA There is no media in the device.
1142 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1147 ScsiDiskFlushBlocksEx (
1148 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1149 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1152 SCSI_DISK_DEV
*ScsiDiskDevice
;
1153 EFI_BLOCK_IO_MEDIA
*Media
;
1155 BOOLEAN MediaChange
;
1158 MediaChange
= FALSE
;
1159 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1160 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1162 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1164 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1165 if (EFI_ERROR (Status
)) {
1166 Status
= EFI_DEVICE_ERROR
;
1171 gBS
->ReinstallProtocolInterface (
1172 ScsiDiskDevice
->Handle
,
1173 &gEfiBlockIoProtocolGuid
,
1174 &ScsiDiskDevice
->BlkIo
,
1175 &ScsiDiskDevice
->BlkIo
1177 gBS
->ReinstallProtocolInterface (
1178 ScsiDiskDevice
->Handle
,
1179 &gEfiBlockIo2ProtocolGuid
,
1180 &ScsiDiskDevice
->BlkIo2
,
1181 &ScsiDiskDevice
->BlkIo2
1183 Status
= EFI_MEDIA_CHANGED
;
1188 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
1190 if (!(Media
->MediaPresent
)) {
1191 Status
= EFI_NO_MEDIA
;
1195 if (Media
->ReadOnly
) {
1196 Status
= EFI_WRITE_PROTECTED
;
1201 // Wait for the BlockIo2 requests queue to become empty
1203 while (!IsListEmpty (&ScsiDiskDevice
->BlkIo2Queue
));
1205 Status
= EFI_SUCCESS
;
1208 // Signal caller event
1210 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1211 Token
->TransactionStatus
= EFI_SUCCESS
;
1212 gBS
->SignalEvent (Token
->Event
);
1216 gBS
->RestoreTPL (OldTpl
);
1222 Detect Device and read out capacity ,if error occurs, parse the sense key.
1224 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1225 @param MustReadCapacity The flag about reading device capacity
1226 @param MediaChange The pointer of flag indicates if media has changed
1228 @retval EFI_DEVICE_ERROR Indicates that error occurs
1229 @retval EFI_SUCCESS Successfully to detect media
1233 ScsiDiskDetectMedia (
1234 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1235 IN BOOLEAN MustReadCapacity
,
1236 OUT BOOLEAN
*MediaChange
1240 EFI_SCSI_SENSE_DATA
*SenseData
;
1241 UINTN NumberOfSenseKeys
;
1243 BOOLEAN NeedReadCapacity
;
1246 EFI_BLOCK_IO_MEDIA OldMedia
;
1248 EFI_EVENT TimeoutEvt
;
1250 Status
= EFI_SUCCESS
;
1252 NumberOfSenseKeys
= 0;
1255 Action
= ACTION_NO_ACTION
;
1256 NeedReadCapacity
= FALSE
;
1257 *MediaChange
= FALSE
;
1260 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
1262 Status
= gBS
->CreateEvent (
1269 if (EFI_ERROR (Status
)) {
1273 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
1274 if (EFI_ERROR (Status
)) {
1279 // Sending Test_Unit cmd to poll device status.
1280 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
1281 // We limit the upper boundary to 120 seconds.
1283 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
1284 Status
= ScsiDiskTestUnitReady (
1290 if (!EFI_ERROR (Status
)) {
1291 Status
= DetectMediaParsingSenseKeys (
1297 if (EFI_ERROR (Status
)) {
1299 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1306 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1312 if (EFI_ERROR (Status
)) {
1317 // ACTION_NO_ACTION: need not read capacity
1318 // other action code: need read capacity
1320 if (Action
== ACTION_READ_CAPACITY
) {
1321 NeedReadCapacity
= TRUE
;
1325 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
1326 // retrieve capacity via Read Capacity command
1328 if (NeedReadCapacity
|| MustReadCapacity
) {
1330 // retrieve media information
1332 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
1333 Status
= ScsiDiskReadCapacity (
1339 if (!EFI_ERROR (Status
)) {
1341 // analyze sense key to action
1343 Status
= DetectMediaParsingSenseKeys (
1349 if (EFI_ERROR (Status
)) {
1351 // if Status is error, it may indicate crisis error,
1352 // so return without retry.
1355 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1363 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1369 if (EFI_ERROR (Status
)) {
1374 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
1376 // Media change information got from the device
1378 *MediaChange
= TRUE
;
1381 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
1382 *MediaChange
= TRUE
;
1383 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1386 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
1387 *MediaChange
= TRUE
;
1388 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1391 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
1392 *MediaChange
= TRUE
;
1393 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1396 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
1397 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
1399 // when change from no media to media present, reset the MediaId to 1.
1401 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
1404 // when no media, reset the MediaId to zero.
1406 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
1409 *MediaChange
= TRUE
;
1413 if (TimeoutEvt
!= NULL
) {
1414 gBS
->CloseEvent (TimeoutEvt
);
1421 Send out Inquiry command to Device.
1423 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1424 @param NeedRetry Indicates if needs try again when error happens
1426 @retval EFI_DEVICE_ERROR Indicates that error occurs
1427 @retval EFI_SUCCESS Successfully to detect media
1431 ScsiDiskInquiryDevice (
1432 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1433 OUT BOOLEAN
*NeedRetry
1436 UINT32 InquiryDataLength
;
1437 UINT8 SenseDataLength
;
1438 UINT8 HostAdapterStatus
;
1440 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
1441 UINTN NumberOfSenseKeys
;
1445 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
1446 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
1449 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1450 SenseDataLength
= 0;
1452 Status
= ScsiInquiryCommand (
1453 ScsiDiskDevice
->ScsiIo
,
1459 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
1464 // no need to check HostAdapterStatus and TargetStatus
1466 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1467 ParseInquiryData (ScsiDiskDevice
);
1469 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1471 // Check whether the device supports Block Limits VPD page (0xB0)
1473 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1474 if (SupportedVpdPages
== NULL
) {
1476 return EFI_DEVICE_ERROR
;
1478 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1479 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
1480 SenseDataLength
= 0;
1481 Status
= ScsiInquiryCommandEx (
1482 ScsiDiskDevice
->ScsiIo
,
1488 (VOID
*) SupportedVpdPages
,
1491 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
1493 if (!EFI_ERROR (Status
)) {
1494 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
1495 | SupportedVpdPages
->PageLength1
;
1498 // Sanity checks for coping with broken devices
1500 if (PageLength
> sizeof SupportedVpdPages
->SupportedVpdPageList
) {
1502 "%a: invalid PageLength (%u) in Supported VPD Pages page\n",
1503 __FUNCTION__
, (UINT32
)PageLength
));
1507 if ((PageLength
> 0) &&
1508 (SupportedVpdPages
->SupportedVpdPageList
[0] !=
1509 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
)) {
1511 "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",
1512 __FUNCTION__
, EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
));
1517 // Locate the code for the Block Limits VPD page
1519 for (Index
= 0; Index
< PageLength
; Index
++) {
1524 (SupportedVpdPages
->SupportedVpdPageList
[Index
] <=
1525 SupportedVpdPages
->SupportedVpdPageList
[Index
- 1])) {
1527 "%a: non-ascending code in Supported VPD Pages page @ %u\n",
1528 __FUNCTION__
, Index
));
1534 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
1540 // Query the Block Limits VPD page
1542 if (Index
< PageLength
) {
1543 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1544 if (BlockLimits
== NULL
) {
1545 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1547 return EFI_DEVICE_ERROR
;
1549 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1550 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
1551 SenseDataLength
= 0;
1552 Status
= ScsiInquiryCommandEx (
1553 ScsiDiskDevice
->ScsiIo
,
1559 (VOID
*) BlockLimits
,
1562 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
1564 if (!EFI_ERROR (Status
)) {
1565 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
1566 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
1567 BlockLimits
->OptimalTransferLengthGranularity1
;
1570 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1574 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1578 if (!EFI_ERROR (Status
)) {
1581 } else if (Status
== EFI_NOT_READY
) {
1583 return EFI_DEVICE_ERROR
;
1585 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1587 return EFI_DEVICE_ERROR
;
1590 // go ahead to check HostAdapterStatus and TargetStatus
1591 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1594 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1595 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1597 return EFI_DEVICE_ERROR
;
1598 } else if (Status
== EFI_DEVICE_ERROR
) {
1600 // reset the scsi channel
1602 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1604 return EFI_DEVICE_ERROR
;
1607 Status
= CheckTargetStatus (TargetStatus
);
1608 if (Status
== EFI_NOT_READY
) {
1610 // reset the scsi device
1612 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1614 return EFI_DEVICE_ERROR
;
1616 } else if (Status
== EFI_DEVICE_ERROR
) {
1618 return EFI_DEVICE_ERROR
;
1622 // if goes here, meant ScsiInquiryCommand() failed.
1623 // if ScsiDiskRequestSenseKeys() succeeds at last,
1624 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1627 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1628 Status
= ScsiDiskRequestSenseKeys (
1635 if (!EFI_ERROR (Status
)) {
1637 return EFI_DEVICE_ERROR
;
1641 return EFI_DEVICE_ERROR
;
1645 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1646 // set *NeedRetry = FALSE to avoid the outside caller try again.
1649 return EFI_DEVICE_ERROR
;
1655 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1656 When Test Unit Ready command encounters any error caused by host adapter or
1657 target, return error without retrieving Sense Keys.
1659 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1660 @param NeedRetry The pointer of flag indicates try again
1661 @param SenseDataArray The pointer of an array of sense data
1662 @param NumberOfSenseKeys The pointer of the number of sense data array
1664 @retval EFI_DEVICE_ERROR Indicates that error occurs
1665 @retval EFI_SUCCESS Successfully to test unit
1669 ScsiDiskTestUnitReady (
1670 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1671 OUT BOOLEAN
*NeedRetry
,
1672 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1673 OUT UINTN
*NumberOfSenseKeys
1677 UINT8 SenseDataLength
;
1678 UINT8 HostAdapterStatus
;
1683 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
1684 *NumberOfSenseKeys
= 0;
1687 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1689 Status
= ScsiTestUnitReadyCommand (
1690 ScsiDiskDevice
->ScsiIo
,
1692 ScsiDiskDevice
->SenseData
,
1698 // no need to check HostAdapterStatus and TargetStatus
1700 if (Status
== EFI_NOT_READY
) {
1702 return EFI_DEVICE_ERROR
;
1704 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1706 return EFI_DEVICE_ERROR
;
1709 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1712 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1713 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1715 return EFI_DEVICE_ERROR
;
1717 } else if (Status
== EFI_DEVICE_ERROR
) {
1719 // reset the scsi channel
1721 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1723 return EFI_DEVICE_ERROR
;
1726 Status
= CheckTargetStatus (TargetStatus
);
1727 if (Status
== EFI_NOT_READY
) {
1729 // reset the scsi device
1731 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1733 return EFI_DEVICE_ERROR
;
1735 } else if (Status
== EFI_DEVICE_ERROR
) {
1737 return EFI_DEVICE_ERROR
;
1740 if (SenseDataLength
!= 0) {
1741 *NumberOfSenseKeys
= SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
);
1742 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1747 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1748 Status
= ScsiDiskRequestSenseKeys (
1755 if (!EFI_ERROR (Status
)) {
1760 return EFI_DEVICE_ERROR
;
1764 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1765 // set *NeedRetry = FALSE to avoid the outside caller try again.
1768 return EFI_DEVICE_ERROR
;
1772 Parsing Sense Keys which got from request sense command.
1774 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1775 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1776 @param NumberOfSenseKeys The number of sense key
1777 @param Action The pointer of action which indicates what is need to do next
1779 @retval EFI_DEVICE_ERROR Indicates that error occurs
1780 @retval EFI_SUCCESS Successfully to complete the parsing
1784 DetectMediaParsingSenseKeys (
1785 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1786 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1787 IN UINTN NumberOfSenseKeys
,
1794 // Default is to read capacity, unless..
1796 *Action
= ACTION_READ_CAPACITY
;
1798 if (NumberOfSenseKeys
== 0) {
1799 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1800 *Action
= ACTION_NO_ACTION
;
1805 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1807 // No Sense Key returned from last submitted command
1809 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1810 *Action
= ACTION_NO_ACTION
;
1815 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1816 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1817 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1818 *Action
= ACTION_NO_ACTION
;
1819 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
1823 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1824 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1825 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
1829 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
1830 *Action
= ACTION_RETRY_COMMAND_LATER
;
1831 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
1835 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1836 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
1837 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1838 return EFI_DEVICE_ERROR
;
1841 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1842 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
1843 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1844 return EFI_DEVICE_ERROR
;
1847 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1849 *Action
= ACTION_RETRY_COMMAND_LATER
;
1850 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
1853 *Action
= ACTION_NO_ACTION
;
1854 return EFI_DEVICE_ERROR
;
1857 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1858 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
1864 Send read capacity command to device and get the device parameter.
1866 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1867 @param NeedRetry The pointer of flag indicates if need a retry
1868 @param SenseDataArray The pointer of an array of sense data
1869 @param NumberOfSenseKeys The number of sense key
1871 @retval EFI_DEVICE_ERROR Indicates that error occurs
1872 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1876 ScsiDiskReadCapacity (
1877 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1878 OUT BOOLEAN
*NeedRetry
,
1879 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1880 OUT UINTN
*NumberOfSenseKeys
1883 UINT8 HostAdapterStatus
;
1885 EFI_STATUS CommandStatus
;
1889 UINT8 SenseDataLength
;
1890 UINT32 DataLength10
;
1891 UINT32 DataLength16
;
1892 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
1893 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
1895 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1896 if (CapacityData10
== NULL
) {
1898 return EFI_DEVICE_ERROR
;
1900 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1901 if (CapacityData16
== NULL
) {
1902 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1904 return EFI_DEVICE_ERROR
;
1907 SenseDataLength
= 0;
1908 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1909 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1910 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1911 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1913 *NumberOfSenseKeys
= 0;
1917 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1918 // 16 byte command should be used to access large hard disk >2TB
1920 CommandStatus
= ScsiReadCapacityCommand (
1921 ScsiDiskDevice
->ScsiIo
,
1927 (VOID
*) CapacityData10
,
1932 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1933 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
1934 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff)) {
1936 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1938 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1940 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1941 // and LowestAlignedLba
1943 CommandStatus
= ScsiReadCapacity16Command (
1944 ScsiDiskDevice
->ScsiIo
,
1950 (VOID
*) CapacityData16
,
1957 // no need to check HostAdapterStatus and TargetStatus
1959 if (CommandStatus
== EFI_SUCCESS
) {
1960 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
1961 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1962 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1966 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1967 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1969 if (CommandStatus
== EFI_NOT_READY
) {
1971 return EFI_DEVICE_ERROR
;
1972 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1974 return EFI_DEVICE_ERROR
;
1978 // go ahead to check HostAdapterStatus and TargetStatus
1979 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1982 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1983 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1985 return EFI_DEVICE_ERROR
;
1987 } else if (Status
== EFI_DEVICE_ERROR
) {
1989 // reset the scsi channel
1991 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1993 return EFI_DEVICE_ERROR
;
1996 Status
= CheckTargetStatus (TargetStatus
);
1997 if (Status
== EFI_NOT_READY
) {
1999 // reset the scsi device
2001 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2003 return EFI_DEVICE_ERROR
;
2005 } else if (Status
== EFI_DEVICE_ERROR
) {
2007 return EFI_DEVICE_ERROR
;
2011 // if goes here, meant ScsiReadCapacityCommand() failed.
2012 // if ScsiDiskRequestSenseKeys() succeeds at last,
2013 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
2016 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2018 Status
= ScsiDiskRequestSenseKeys (
2025 if (!EFI_ERROR (Status
)) {
2030 return EFI_DEVICE_ERROR
;
2034 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
2035 // set *NeedRetry = FALSE to avoid the outside caller try again.
2038 return EFI_DEVICE_ERROR
;
2042 Check the HostAdapter status and re-interpret it in EFI_STATUS.
2044 @param HostAdapterStatus Host Adapter status
2046 @retval EFI_SUCCESS Host adapter is OK.
2047 @retval EFI_TIMEOUT Timeout.
2048 @retval EFI_NOT_READY Adapter NOT ready.
2049 @retval EFI_DEVICE_ERROR Adapter device error.
2053 CheckHostAdapterStatus (
2054 IN UINT8 HostAdapterStatus
2057 switch (HostAdapterStatus
) {
2058 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
2061 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
2062 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
2063 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
2066 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
2067 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
2068 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
2069 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
2070 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
2071 return EFI_NOT_READY
;
2073 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
2074 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
2075 return EFI_DEVICE_ERROR
;
2084 Check the target status and re-interpret it in EFI_STATUS.
2086 @param TargetStatus Target status
2088 @retval EFI_NOT_READY Device is NOT ready.
2089 @retval EFI_DEVICE_ERROR
2095 IN UINT8 TargetStatus
2098 switch (TargetStatus
) {
2099 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
2100 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
2101 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
2104 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
2105 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
2106 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
2107 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
2108 return EFI_NOT_READY
;
2110 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
2111 return EFI_DEVICE_ERROR
;
2120 Retrieve all sense keys from the device.
2122 When encountering error during the process, if retrieve sense keys before
2123 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
2124 and NeedRetry set to FALSE; otherwize, return the proper return status.
2126 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2127 @param NeedRetry The pointer of flag indicates if need a retry
2128 @param SenseDataArray The pointer of an array of sense data
2129 @param NumberOfSenseKeys The number of sense key
2130 @param AskResetIfError The flag indicates if need reset when error occurs
2132 @retval EFI_DEVICE_ERROR Indicates that error occurs
2133 @retval EFI_SUCCESS Successfully to request sense key
2137 ScsiDiskRequestSenseKeys (
2138 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2139 OUT BOOLEAN
*NeedRetry
,
2140 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2141 OUT UINTN
*NumberOfSenseKeys
,
2142 IN BOOLEAN AskResetIfError
2145 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
2146 UINT8 SenseDataLength
;
2149 EFI_STATUS FallStatus
;
2150 UINT8 HostAdapterStatus
;
2153 FallStatus
= EFI_SUCCESS
;
2154 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
2157 ScsiDiskDevice
->SenseData
,
2158 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
2161 *NumberOfSenseKeys
= 0;
2162 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2163 Status
= EFI_SUCCESS
;
2164 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
2165 if (PtrSenseData
== NULL
) {
2166 return EFI_DEVICE_ERROR
;
2169 for (SenseReq
= TRUE
; SenseReq
;) {
2170 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2171 Status
= ScsiRequestSenseCommand (
2172 ScsiDiskDevice
->ScsiIo
,
2179 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
2180 FallStatus
= EFI_SUCCESS
;
2182 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2184 FallStatus
= EFI_DEVICE_ERROR
;
2186 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2188 FallStatus
= EFI_DEVICE_ERROR
;
2190 } else if (Status
== EFI_DEVICE_ERROR
) {
2191 if (AskResetIfError
) {
2192 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2195 FallStatus
= EFI_DEVICE_ERROR
;
2198 if (EFI_ERROR (FallStatus
)) {
2199 if (*NumberOfSenseKeys
!= 0) {
2201 Status
= EFI_SUCCESS
;
2204 Status
= EFI_DEVICE_ERROR
;
2209 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
2210 (*NumberOfSenseKeys
) += 1;
2213 // no more sense key or number of sense keys exceeds predefined,
2216 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
2217 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
2223 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2229 Get information from media read capacity command.
2231 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2232 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
2233 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
2238 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2239 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
2240 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
2245 if (!ScsiDiskDevice
->Cdb16Byte
) {
2246 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
2247 (Capacity10
->LastLba2
<< 16) |
2248 (Capacity10
->LastLba1
<< 8) |
2249 Capacity10
->LastLba0
;
2251 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
2252 (Capacity10
->BlockSize2
<< 16) |
2253 (Capacity10
->BlockSize1
<< 8) |
2254 Capacity10
->BlockSize0
;
2255 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
2256 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
2258 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2259 *Ptr
++ = Capacity16
->LastLba0
;
2260 *Ptr
++ = Capacity16
->LastLba1
;
2261 *Ptr
++ = Capacity16
->LastLba2
;
2262 *Ptr
++ = Capacity16
->LastLba3
;
2263 *Ptr
++ = Capacity16
->LastLba4
;
2264 *Ptr
++ = Capacity16
->LastLba5
;
2265 *Ptr
++ = Capacity16
->LastLba6
;
2266 *Ptr
= Capacity16
->LastLba7
;
2268 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
2269 (Capacity16
->BlockSize2
<< 16) |
2270 (Capacity16
->BlockSize1
<< 8) |
2271 Capacity16
->BlockSize0
;
2273 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
2274 Capacity16
->LowestAlignLogic1
;
2275 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
2278 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
2284 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2289 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2292 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
2293 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
2297 Read sector from SCSI Disk.
2299 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2300 @param Buffer The buffer to fill in the read out data
2301 @param Lba Logic block address
2302 @param NumberOfBlocks The number of blocks to read
2304 @retval EFI_DEVICE_ERROR Indicates a device error.
2305 @retval EFI_SUCCESS Operation is successful.
2309 ScsiDiskReadSectors (
2310 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2313 IN UINTN NumberOfBlocks
2316 UINTN BlocksRemaining
;
2322 UINT32 NextSectorCount
;
2329 Status
= EFI_SUCCESS
;
2331 BlocksRemaining
= NumberOfBlocks
;
2332 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2335 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2337 if (!ScsiDiskDevice
->Cdb16Byte
) {
2340 MaxBlock
= 0xFFFFFFFF;
2345 while (BlocksRemaining
> 0) {
2347 if (BlocksRemaining
<= MaxBlock
) {
2348 if (!ScsiDiskDevice
->Cdb16Byte
) {
2349 SectorCount
= (UINT16
) BlocksRemaining
;
2351 SectorCount
= (UINT32
) BlocksRemaining
;
2354 SectorCount
= MaxBlock
;
2357 ByteCount
= SectorCount
* BlockSize
;
2359 // |------------------------|-----------------|------------------|-----------------|
2360 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2361 // |------------------------|-----------------|------------------|-----------------|
2362 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2363 // |------------------------|-----------------|------------------|-----------------|
2364 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2365 // |------------------------|-----------------|------------------|-----------------|
2366 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2367 // |------------------------|-----------------|------------------|-----------------|
2368 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2369 // |------------------------|-----------------|------------------|-----------------|
2370 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2371 // |------------------------|-----------------|------------------|-----------------|
2372 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2373 // |------------------------|-----------------|------------------|-----------------|
2374 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2375 // |------------------------|-----------------|------------------|-----------------|
2376 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2377 // |------------------------|-----------------|------------------|-----------------|
2378 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2379 // |------------------------|-----------------|------------------|-----------------|
2380 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2381 // |------------------------|-----------------|------------------|-----------------|
2383 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2384 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2385 // From the above table, we could know 2.1Mbytes per second is lowest one.
2386 // The timout value is rounded up to nearest integar and here an additional 30s is added
2387 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2388 // commands in the Standby/Idle mode.
2390 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2393 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2394 if (!ScsiDiskDevice
->Cdb16Byte
) {
2395 Status
= ScsiDiskRead10 (
2405 Status
= ScsiDiskRead16 (
2415 if (!EFI_ERROR (Status
)) {
2420 return EFI_DEVICE_ERROR
;
2424 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
2425 // lowered ByteCount on output, we must make sure that we lower
2426 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2427 // it is invalid to request more sectors in the CDB than the entire
2428 // transfer (ie. ByteCount) can carry.
2430 // In addition, ByteCount is only expected to go down, or stay unchaged.
2431 // Therefore we don't need to update Timeout: the original timeout should
2432 // accommodate shorter transfers too.
2434 NextSectorCount
= ByteCount
/ BlockSize
;
2435 if (NextSectorCount
< SectorCount
) {
2436 SectorCount
= NextSectorCount
;
2438 // Account for any rounding down.
2440 ByteCount
= SectorCount
* BlockSize
;
2444 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2445 return EFI_DEVICE_ERROR
;
2449 // actual transferred sectors
2451 SectorCount
= ByteCount
/ BlockSize
;
2454 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2455 BlocksRemaining
-= SectorCount
;
2462 Write sector to SCSI Disk.
2464 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2465 @param Buffer The buffer of data to be written into SCSI Disk
2466 @param Lba Logic block address
2467 @param NumberOfBlocks The number of blocks to read
2469 @retval EFI_DEVICE_ERROR Indicates a device error.
2470 @retval EFI_SUCCESS Operation is successful.
2474 ScsiDiskWriteSectors (
2475 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2478 IN UINTN NumberOfBlocks
2481 UINTN BlocksRemaining
;
2487 UINT32 NextSectorCount
;
2494 Status
= EFI_SUCCESS
;
2496 BlocksRemaining
= NumberOfBlocks
;
2497 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2500 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2502 if (!ScsiDiskDevice
->Cdb16Byte
) {
2505 MaxBlock
= 0xFFFFFFFF;
2510 while (BlocksRemaining
> 0) {
2512 if (BlocksRemaining
<= MaxBlock
) {
2513 if (!ScsiDiskDevice
->Cdb16Byte
) {
2514 SectorCount
= (UINT16
) BlocksRemaining
;
2516 SectorCount
= (UINT32
) BlocksRemaining
;
2519 SectorCount
= MaxBlock
;
2522 ByteCount
= SectorCount
* BlockSize
;
2524 // |------------------------|-----------------|------------------|-----------------|
2525 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2526 // |------------------------|-----------------|------------------|-----------------|
2527 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2528 // |------------------------|-----------------|------------------|-----------------|
2529 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2530 // |------------------------|-----------------|------------------|-----------------|
2531 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2532 // |------------------------|-----------------|------------------|-----------------|
2533 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2534 // |------------------------|-----------------|------------------|-----------------|
2535 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2536 // |------------------------|-----------------|------------------|-----------------|
2537 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2538 // |------------------------|-----------------|------------------|-----------------|
2539 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2540 // |------------------------|-----------------|------------------|-----------------|
2541 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2542 // |------------------------|-----------------|------------------|-----------------|
2543 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2544 // |------------------------|-----------------|------------------|-----------------|
2545 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2546 // |------------------------|-----------------|------------------|-----------------|
2548 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2549 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2550 // From the above table, we could know 2.1Mbytes per second is lowest one.
2551 // The timout value is rounded up to nearest integar and here an additional 30s is added
2552 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2553 // commands in the Standby/Idle mode.
2555 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2557 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2558 if (!ScsiDiskDevice
->Cdb16Byte
) {
2559 Status
= ScsiDiskWrite10 (
2569 Status
= ScsiDiskWrite16 (
2579 if (!EFI_ERROR (Status
)) {
2584 return EFI_DEVICE_ERROR
;
2588 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
2589 // has lowered ByteCount on output, we must make sure that we lower
2590 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2591 // it is invalid to request more sectors in the CDB than the entire
2592 // transfer (ie. ByteCount) can carry.
2594 // In addition, ByteCount is only expected to go down, or stay unchaged.
2595 // Therefore we don't need to update Timeout: the original timeout should
2596 // accommodate shorter transfers too.
2598 NextSectorCount
= ByteCount
/ BlockSize
;
2599 if (NextSectorCount
< SectorCount
) {
2600 SectorCount
= NextSectorCount
;
2602 // Account for any rounding down.
2604 ByteCount
= SectorCount
* BlockSize
;
2608 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2609 return EFI_DEVICE_ERROR
;
2612 // actual transferred sectors
2614 SectorCount
= ByteCount
/ BlockSize
;
2617 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2618 BlocksRemaining
-= SectorCount
;
2625 Asynchronously read sector from SCSI Disk.
2627 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2628 @param Buffer The buffer to fill in the read out data.
2629 @param Lba Logic block address.
2630 @param NumberOfBlocks The number of blocks to read.
2631 @param Token A pointer to the token associated with the
2632 non-blocking read request.
2634 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
2635 @retval EFI_DEVICE_ERROR Indicates a device error.
2636 @retval EFI_SUCCESS Operation is successful.
2640 ScsiDiskAsyncReadSectors (
2641 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2644 IN UINTN NumberOfBlocks
,
2645 IN EFI_BLOCK_IO2_TOKEN
*Token
2648 UINTN BlocksRemaining
;
2655 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
2659 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
2660 return EFI_INVALID_PARAMETER
;
2663 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
2664 if (BlkIo2Req
== NULL
) {
2665 return EFI_OUT_OF_RESOURCES
;
2668 BlkIo2Req
->Token
= Token
;
2670 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2671 InsertTailList (&ScsiDiskDevice
->BlkIo2Queue
, &BlkIo2Req
->Link
);
2672 gBS
->RestoreTPL (OldTpl
);
2674 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
2676 Status
= EFI_SUCCESS
;
2678 BlocksRemaining
= NumberOfBlocks
;
2679 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2682 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2685 if (!ScsiDiskDevice
->Cdb16Byte
) {
2688 MaxBlock
= 0xFFFFFFFF;
2693 while (BlocksRemaining
> 0) {
2695 if (BlocksRemaining
<= MaxBlock
) {
2696 if (!ScsiDiskDevice
->Cdb16Byte
) {
2697 SectorCount
= (UINT16
) BlocksRemaining
;
2699 SectorCount
= (UINT32
) BlocksRemaining
;
2702 SectorCount
= MaxBlock
;
2705 ByteCount
= SectorCount
* BlockSize
;
2707 // |------------------------|-----------------|------------------|-----------------|
2708 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2709 // |------------------------|-----------------|------------------|-----------------|
2710 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2711 // |------------------------|-----------------|------------------|-----------------|
2712 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2713 // |------------------------|-----------------|------------------|-----------------|
2714 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2715 // |------------------------|-----------------|------------------|-----------------|
2716 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2717 // |------------------------|-----------------|------------------|-----------------|
2718 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2719 // |------------------------|-----------------|------------------|-----------------|
2720 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2721 // |------------------------|-----------------|------------------|-----------------|
2722 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2723 // |------------------------|-----------------|------------------|-----------------|
2724 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2725 // |------------------------|-----------------|------------------|-----------------|
2726 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2727 // |------------------------|-----------------|------------------|-----------------|
2728 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2729 // |------------------------|-----------------|------------------|-----------------|
2731 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2732 // we have to use the lowest transfer rate to calculate the possible
2733 // maximum timeout value for each operation.
2734 // From the above table, we could know 2.1Mbytes per second is lowest one.
2735 // The timout value is rounded up to nearest integar and here an additional
2736 // 30s is added to follow ATA spec in which it mentioned that the device
2737 // may take up to 30s to respond commands in the Standby/Idle mode.
2739 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2741 if (!ScsiDiskDevice
->Cdb16Byte
) {
2742 Status
= ScsiDiskAsyncRead10 (
2754 Status
= ScsiDiskAsyncRead16 (
2766 if (EFI_ERROR (Status
)) {
2768 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
2769 // length of a SCSI I/O command is too large.
2770 // In this case, we retry sending the SCSI command with a data length
2771 // half of its previous value.
2773 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
2774 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
2775 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
2780 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2781 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2783 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
2784 // SCSI sub-task running. Otherwise, it will be freed in the callback
2785 // function ScsiDiskNotify().
2787 RemoveEntryList (&BlkIo2Req
->Link
);
2788 FreePool (BlkIo2Req
);
2790 gBS
->RestoreTPL (OldTpl
);
2793 // It is safe to return error status to the caller, since there is no
2794 // previous SCSI sub-task executing.
2796 Status
= EFI_DEVICE_ERROR
;
2799 gBS
->RestoreTPL (OldTpl
);
2802 // There are previous SCSI commands still running, EFI_SUCCESS should
2803 // be returned to make sure that the caller does not free resources
2804 // still using by these SCSI commands.
2806 Status
= EFI_SUCCESS
;
2812 // Sectors submitted for transfer
2814 SectorCount
= ByteCount
/ BlockSize
;
2817 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2818 BlocksRemaining
-= SectorCount
;
2821 Status
= EFI_SUCCESS
;
2824 if (BlkIo2Req
!= NULL
) {
2825 BlkIo2Req
->LastScsiRW
= TRUE
;
2827 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2828 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2829 RemoveEntryList (&BlkIo2Req
->Link
);
2830 FreePool (BlkIo2Req
);
2833 gBS
->SignalEvent (Token
->Event
);
2835 gBS
->RestoreTPL (OldTpl
);
2842 Asynchronously write sector to SCSI Disk.
2844 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2845 @param Buffer The buffer of data to be written into SCSI Disk.
2846 @param Lba Logic block address.
2847 @param NumberOfBlocks The number of blocks to read.
2848 @param Token A pointer to the token associated with the
2849 non-blocking read request.
2851 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
2852 @retval EFI_DEVICE_ERROR Indicates a device error.
2853 @retval EFI_SUCCESS Operation is successful.
2857 ScsiDiskAsyncWriteSectors (
2858 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2861 IN UINTN NumberOfBlocks
,
2862 IN EFI_BLOCK_IO2_TOKEN
*Token
2865 UINTN BlocksRemaining
;
2872 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
2876 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
2877 return EFI_INVALID_PARAMETER
;
2880 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
2881 if (BlkIo2Req
== NULL
) {
2882 return EFI_OUT_OF_RESOURCES
;
2885 BlkIo2Req
->Token
= Token
;
2887 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2888 InsertTailList (&ScsiDiskDevice
->BlkIo2Queue
, &BlkIo2Req
->Link
);
2889 gBS
->RestoreTPL (OldTpl
);
2891 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
2893 Status
= EFI_SUCCESS
;
2895 BlocksRemaining
= NumberOfBlocks
;
2896 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2899 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2902 if (!ScsiDiskDevice
->Cdb16Byte
) {
2905 MaxBlock
= 0xFFFFFFFF;
2910 while (BlocksRemaining
> 0) {
2912 if (BlocksRemaining
<= MaxBlock
) {
2913 if (!ScsiDiskDevice
->Cdb16Byte
) {
2914 SectorCount
= (UINT16
) BlocksRemaining
;
2916 SectorCount
= (UINT32
) BlocksRemaining
;
2919 SectorCount
= MaxBlock
;
2922 ByteCount
= SectorCount
* BlockSize
;
2924 // |------------------------|-----------------|------------------|-----------------|
2925 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2926 // |------------------------|-----------------|------------------|-----------------|
2927 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2928 // |------------------------|-----------------|------------------|-----------------|
2929 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2930 // |------------------------|-----------------|------------------|-----------------|
2931 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2932 // |------------------------|-----------------|------------------|-----------------|
2933 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2934 // |------------------------|-----------------|------------------|-----------------|
2935 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2936 // |------------------------|-----------------|------------------|-----------------|
2937 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2938 // |------------------------|-----------------|------------------|-----------------|
2939 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2940 // |------------------------|-----------------|------------------|-----------------|
2941 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2942 // |------------------------|-----------------|------------------|-----------------|
2943 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2944 // |------------------------|-----------------|------------------|-----------------|
2945 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2946 // |------------------------|-----------------|------------------|-----------------|
2948 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2949 // we have to use the lowest transfer rate to calculate the possible
2950 // maximum timeout value for each operation.
2951 // From the above table, we could know 2.1Mbytes per second is lowest one.
2952 // The timout value is rounded up to nearest integar and here an additional
2953 // 30s is added to follow ATA spec in which it mentioned that the device
2954 // may take up to 30s to respond commands in the Standby/Idle mode.
2956 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2958 if (!ScsiDiskDevice
->Cdb16Byte
) {
2959 Status
= ScsiDiskAsyncWrite10 (
2971 Status
= ScsiDiskAsyncWrite16 (
2983 if (EFI_ERROR (Status
)) {
2985 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
2986 // length of a SCSI I/O command is too large.
2987 // In this case, we retry sending the SCSI command with a data length
2988 // half of its previous value.
2990 if ((Status
== EFI_DEVICE_ERROR
) || (Status
== EFI_TIMEOUT
)) {
2991 if ((MaxBlock
> 1) && (SectorCount
> 1)) {
2992 MaxBlock
= MIN (MaxBlock
, SectorCount
) >> 1;
2997 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
2998 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3000 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
3001 // SCSI sub-task running. Otherwise, it will be freed in the callback
3002 // function ScsiDiskNotify().
3004 RemoveEntryList (&BlkIo2Req
->Link
);
3005 FreePool (BlkIo2Req
);
3007 gBS
->RestoreTPL (OldTpl
);
3010 // It is safe to return error status to the caller, since there is no
3011 // previous SCSI sub-task executing.
3013 Status
= EFI_DEVICE_ERROR
;
3016 gBS
->RestoreTPL (OldTpl
);
3019 // There are previous SCSI commands still running, EFI_SUCCESS should
3020 // be returned to make sure that the caller does not free resources
3021 // still using by these SCSI commands.
3023 Status
= EFI_SUCCESS
;
3029 // Sectors submitted for transfer
3031 SectorCount
= ByteCount
/ BlockSize
;
3034 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
3035 BlocksRemaining
-= SectorCount
;
3038 Status
= EFI_SUCCESS
;
3041 if (BlkIo2Req
!= NULL
) {
3042 BlkIo2Req
->LastScsiRW
= TRUE
;
3044 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3045 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
3046 RemoveEntryList (&BlkIo2Req
->Link
);
3047 FreePool (BlkIo2Req
);
3050 gBS
->SignalEvent (Token
->Event
);
3052 gBS
->RestoreTPL (OldTpl
);
3060 Submit Read(10) command.
3062 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3063 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3064 @param Timeout The time to complete the command
3065 @param DataBuffer The buffer to fill with the read out data
3066 @param DataLength The length of buffer
3067 @param StartLba The start logic block address
3068 @param SectorCount The number of blocks to read
3070 @return EFI_STATUS is returned by calling ScsiRead10Command().
3074 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3075 OUT BOOLEAN
*NeedRetry
,
3077 OUT UINT8
*DataBuffer
,
3078 IN OUT UINT32
*DataLength
,
3080 IN UINT32 SectorCount
3083 UINT8 SenseDataLength
;
3085 EFI_STATUS ReturnStatus
;
3086 UINT8 HostAdapterStatus
;
3091 // Implement a backoff algorithem to resolve some compatibility issues that
3092 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3093 // big data in a single operation.
3094 // This algorithem will at first try to execute original request. If the request fails
3095 // with media error sense data or else, it will reduce the transfer length to half and
3096 // try again till the operation succeeds or fails with one sector transfer length.
3100 Action
= ACTION_NO_ACTION
;
3101 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3102 ReturnStatus
= ScsiRead10Command (
3103 ScsiDiskDevice
->ScsiIo
,
3105 ScsiDiskDevice
->SenseData
,
3115 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3117 return EFI_DEVICE_ERROR
;
3118 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3120 return ReturnStatus
;
3124 // go ahead to check HostAdapterStatus and TargetStatus
3125 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3127 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3128 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3130 return EFI_DEVICE_ERROR
;
3131 } else if (Status
== EFI_DEVICE_ERROR
) {
3133 // reset the scsi channel
3135 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3137 return EFI_DEVICE_ERROR
;
3140 Status
= CheckTargetStatus (TargetStatus
);
3141 if (Status
== EFI_NOT_READY
) {
3143 // reset the scsi device
3145 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3147 return EFI_DEVICE_ERROR
;
3148 } else if (Status
== EFI_DEVICE_ERROR
) {
3150 return EFI_DEVICE_ERROR
;
3153 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3154 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
3155 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3156 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3158 return EFI_DEVICE_ERROR
;
3159 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3160 if (SectorCount
<= 1) {
3162 // Jump out if the operation still fails with one sector transfer length.
3165 return EFI_DEVICE_ERROR
;
3168 // Try again with half length if the sense data shows we need to retry.
3171 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3175 return EFI_DEVICE_ERROR
;
3179 return ReturnStatus
;
3184 Submit Write(10) Command.
3186 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3187 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3188 @param Timeout The time to complete the command
3189 @param DataBuffer The buffer to fill with the read out data
3190 @param DataLength The length of buffer
3191 @param StartLba The start logic block address
3192 @param SectorCount The number of blocks to write
3194 @return EFI_STATUS is returned by calling ScsiWrite10Command().
3199 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3200 OUT BOOLEAN
*NeedRetry
,
3202 IN UINT8
*DataBuffer
,
3203 IN OUT UINT32
*DataLength
,
3205 IN UINT32 SectorCount
3209 EFI_STATUS ReturnStatus
;
3210 UINT8 SenseDataLength
;
3211 UINT8 HostAdapterStatus
;
3216 // Implement a backoff algorithem to resolve some compatibility issues that
3217 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3218 // big data in a single operation.
3219 // This algorithem will at first try to execute original request. If the request fails
3220 // with media error sense data or else, it will reduce the transfer length to half and
3221 // try again till the operation succeeds or fails with one sector transfer length.
3225 Action
= ACTION_NO_ACTION
;
3226 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3227 ReturnStatus
= ScsiWrite10Command (
3228 ScsiDiskDevice
->ScsiIo
,
3230 ScsiDiskDevice
->SenseData
,
3239 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3241 return EFI_DEVICE_ERROR
;
3242 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3244 return ReturnStatus
;
3248 // go ahead to check HostAdapterStatus and TargetStatus
3249 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3251 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3252 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3254 return EFI_DEVICE_ERROR
;
3255 } else if (Status
== EFI_DEVICE_ERROR
) {
3257 // reset the scsi channel
3259 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3261 return EFI_DEVICE_ERROR
;
3264 Status
= CheckTargetStatus (TargetStatus
);
3265 if (Status
== EFI_NOT_READY
) {
3267 // reset the scsi device
3269 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3271 return EFI_DEVICE_ERROR
;
3272 } else if (Status
== EFI_DEVICE_ERROR
) {
3274 return EFI_DEVICE_ERROR
;
3277 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3278 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
3279 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3280 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3282 return EFI_DEVICE_ERROR
;
3283 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3284 if (SectorCount
<= 1) {
3286 // Jump out if the operation still fails with one sector transfer length.
3289 return EFI_DEVICE_ERROR
;
3292 // Try again with half length if the sense data shows we need to retry.
3295 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3299 return EFI_DEVICE_ERROR
;
3303 return ReturnStatus
;
3308 Submit Read(16) command.
3310 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3311 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3312 @param Timeout The time to complete the command
3313 @param DataBuffer The buffer to fill with the read out data
3314 @param DataLength The length of buffer
3315 @param StartLba The start logic block address
3316 @param SectorCount The number of blocks to read
3318 @return EFI_STATUS is returned by calling ScsiRead16Command().
3322 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3323 OUT BOOLEAN
*NeedRetry
,
3325 OUT UINT8
*DataBuffer
,
3326 IN OUT UINT32
*DataLength
,
3328 IN UINT32 SectorCount
3331 UINT8 SenseDataLength
;
3333 EFI_STATUS ReturnStatus
;
3334 UINT8 HostAdapterStatus
;
3339 // Implement a backoff algorithem to resolve some compatibility issues that
3340 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3341 // big data in a single operation.
3342 // This algorithem will at first try to execute original request. If the request fails
3343 // with media error sense data or else, it will reduce the transfer length to half and
3344 // try again till the operation succeeds or fails with one sector transfer length.
3348 Action
= ACTION_NO_ACTION
;
3349 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3350 ReturnStatus
= ScsiRead16Command (
3351 ScsiDiskDevice
->ScsiIo
,
3353 ScsiDiskDevice
->SenseData
,
3362 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3364 return EFI_DEVICE_ERROR
;
3365 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3367 return ReturnStatus
;
3371 // go ahead to check HostAdapterStatus and TargetStatus
3372 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3374 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3375 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3377 return EFI_DEVICE_ERROR
;
3378 } else if (Status
== EFI_DEVICE_ERROR
) {
3380 // reset the scsi channel
3382 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3384 return EFI_DEVICE_ERROR
;
3387 Status
= CheckTargetStatus (TargetStatus
);
3388 if (Status
== EFI_NOT_READY
) {
3390 // reset the scsi device
3392 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3394 return EFI_DEVICE_ERROR
;
3395 } else if (Status
== EFI_DEVICE_ERROR
) {
3397 return EFI_DEVICE_ERROR
;
3400 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3401 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
3402 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3403 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3405 return EFI_DEVICE_ERROR
;
3406 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3407 if (SectorCount
<= 1) {
3409 // Jump out if the operation still fails with one sector transfer length.
3412 return EFI_DEVICE_ERROR
;
3415 // Try again with half length if the sense data shows we need to retry.
3418 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3422 return EFI_DEVICE_ERROR
;
3426 return ReturnStatus
;
3431 Submit Write(16) Command.
3433 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3434 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3435 @param Timeout The time to complete the command
3436 @param DataBuffer The buffer to fill with the read out data
3437 @param DataLength The length of buffer
3438 @param StartLba The start logic block address
3439 @param SectorCount The number of blocks to write
3441 @return EFI_STATUS is returned by calling ScsiWrite16Command().
3446 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3447 OUT BOOLEAN
*NeedRetry
,
3449 IN UINT8
*DataBuffer
,
3450 IN OUT UINT32
*DataLength
,
3452 IN UINT32 SectorCount
3456 EFI_STATUS ReturnStatus
;
3457 UINT8 SenseDataLength
;
3458 UINT8 HostAdapterStatus
;
3463 // Implement a backoff algorithem to resolve some compatibility issues that
3464 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3465 // big data in a single operation.
3466 // This algorithem will at first try to execute original request. If the request fails
3467 // with media error sense data or else, it will reduce the transfer length to half and
3468 // try again till the operation succeeds or fails with one sector transfer length.
3472 Action
= ACTION_NO_ACTION
;
3473 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3474 ReturnStatus
= ScsiWrite16Command (
3475 ScsiDiskDevice
->ScsiIo
,
3477 ScsiDiskDevice
->SenseData
,
3486 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3488 return EFI_DEVICE_ERROR
;
3489 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3491 return ReturnStatus
;
3495 // go ahead to check HostAdapterStatus and TargetStatus
3496 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3498 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3499 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3501 return EFI_DEVICE_ERROR
;
3502 } else if (Status
== EFI_DEVICE_ERROR
) {
3504 // reset the scsi channel
3506 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3508 return EFI_DEVICE_ERROR
;
3511 Status
= CheckTargetStatus (TargetStatus
);
3512 if (Status
== EFI_NOT_READY
) {
3514 // reset the scsi device
3516 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3518 return EFI_DEVICE_ERROR
;
3519 } else if (Status
== EFI_DEVICE_ERROR
) {
3521 return EFI_DEVICE_ERROR
;
3524 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3525 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
3526 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3527 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3529 return EFI_DEVICE_ERROR
;
3530 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3531 if (SectorCount
<= 1) {
3533 // Jump out if the operation still fails with one sector transfer length.
3536 return EFI_DEVICE_ERROR
;
3539 // Try again with half length if the sense data shows we need to retry.
3542 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3546 return EFI_DEVICE_ERROR
;
3550 return ReturnStatus
;
3555 Internal helper notify function in which determine whether retry of a SCSI
3556 Read/Write command is needed and signal the event passed from Block I/O(2) if
3557 the SCSI I/O operation completes.
3559 @param Event The instance of EFI_EVENT.
3560 @param Context The parameter passed in.
3571 SCSI_ASYNC_RW_REQUEST
*Request
;
3572 SCSI_DISK_DEV
*ScsiDiskDevice
;
3573 EFI_BLOCK_IO2_TOKEN
*Token
;
3575 UINT32 OldDataLength
;
3576 UINT32 OldSectorCount
;
3579 gBS
->CloseEvent (Event
);
3581 Request
= (SCSI_ASYNC_RW_REQUEST
*) Context
;
3582 ScsiDiskDevice
= Request
->ScsiDiskDevice
;
3583 Token
= Request
->BlkIo2Req
->Token
;
3584 OldDataLength
= Request
->DataLength
;
3585 OldSectorCount
= Request
->SectorCount
;
3589 // If previous sub-tasks already fails, no need to process this sub-task.
3591 if (Token
->TransactionStatus
!= EFI_SUCCESS
) {
3596 // Check HostAdapterStatus and TargetStatus
3597 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3599 Status
= CheckHostAdapterStatus (Request
->HostAdapterStatus
);
3600 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3601 if (++Request
->TimesRetry
> MaxRetry
) {
3602 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3607 } else if (Status
== EFI_DEVICE_ERROR
) {
3609 // reset the scsi channel
3611 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3612 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3616 Status
= CheckTargetStatus (Request
->TargetStatus
);
3617 if (Status
== EFI_NOT_READY
) {
3619 // reset the scsi device
3621 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3622 if (++Request
->TimesRetry
> MaxRetry
) {
3623 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3628 } else if (Status
== EFI_DEVICE_ERROR
) {
3629 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3633 if (Request
->TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) {
3634 DEBUG ((EFI_D_ERROR
, "ScsiDiskNotify: Check Condition happened!\n"));
3636 Status
= DetectMediaParsingSenseKeys (
3639 Request
->SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
),
3642 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3643 if (++Request
->TimesRetry
> MaxRetry
) {
3644 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3649 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3650 if (Request
->SectorCount
<= 1) {
3652 // Jump out if the operation still fails with one sector transfer
3655 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3659 // Try again with two half length request if the sense data shows we need
3662 Request
->SectorCount
>>= 1;
3663 Request
->DataLength
= Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3664 Request
->TimesRetry
= 0;
3668 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3674 // This sub-task succeeds, no need to retry.
3679 if (Request
->InBuffer
!= NULL
) {
3681 // SCSI read command
3683 if (!ScsiDiskDevice
->Cdb16Byte
) {
3684 Status
= ScsiDiskAsyncRead10 (
3687 Request
->TimesRetry
,
3689 Request
->DataLength
,
3690 (UINT32
) Request
->StartLba
,
3691 Request
->SectorCount
,
3696 Status
= ScsiDiskAsyncRead16 (
3699 Request
->TimesRetry
,
3701 Request
->DataLength
,
3703 Request
->SectorCount
,
3709 if (EFI_ERROR (Status
)) {
3710 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3712 } else if (OldSectorCount
!= Request
->SectorCount
) {
3714 // Original sub-task will be split into two new sub-tasks with smaller
3717 if (!ScsiDiskDevice
->Cdb16Byte
) {
3718 Status
= ScsiDiskAsyncRead10 (
3722 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3723 OldDataLength
- Request
->DataLength
,
3724 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
3725 OldSectorCount
- Request
->SectorCount
,
3730 Status
= ScsiDiskAsyncRead16 (
3734 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3735 OldDataLength
- Request
->DataLength
,
3736 Request
->StartLba
+ Request
->SectorCount
,
3737 OldSectorCount
- Request
->SectorCount
,
3742 if (EFI_ERROR (Status
)) {
3743 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3749 // SCSI write command
3751 if (!ScsiDiskDevice
->Cdb16Byte
) {
3752 Status
= ScsiDiskAsyncWrite10 (
3755 Request
->TimesRetry
,
3757 Request
->DataLength
,
3758 (UINT32
) Request
->StartLba
,
3759 Request
->SectorCount
,
3764 Status
= ScsiDiskAsyncWrite16 (
3767 Request
->TimesRetry
,
3769 Request
->DataLength
,
3771 Request
->SectorCount
,
3777 if (EFI_ERROR (Status
)) {
3778 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3780 } else if (OldSectorCount
!= Request
->SectorCount
) {
3782 // Original sub-task will be split into two new sub-tasks with smaller
3785 if (!ScsiDiskDevice
->Cdb16Byte
) {
3786 Status
= ScsiDiskAsyncWrite10 (
3790 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3791 OldDataLength
- Request
->DataLength
,
3792 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
3793 OldSectorCount
- Request
->SectorCount
,
3798 Status
= ScsiDiskAsyncWrite16 (
3802 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3803 OldDataLength
- Request
->DataLength
,
3804 Request
->StartLba
+ Request
->SectorCount
,
3805 OldSectorCount
- Request
->SectorCount
,
3810 if (EFI_ERROR (Status
)) {
3811 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3818 RemoveEntryList (&Request
->Link
);
3819 if ((IsListEmpty (&Request
->BlkIo2Req
->ScsiRWQueue
)) &&
3820 (Request
->BlkIo2Req
->LastScsiRW
)) {
3822 // The last SCSI R/W command of a BlockIo2 request completes
3824 RemoveEntryList (&Request
->BlkIo2Req
->Link
);
3825 FreePool (Request
->BlkIo2Req
); // Should be freed only once
3826 gBS
->SignalEvent (Token
->Event
);
3829 FreePool (Request
->SenseData
);
3835 Submit Async Read(10) command.
3837 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3838 @param Timeout The time to complete the command.
3839 @param TimesRetry The number of times the command has been retried.
3840 @param DataBuffer The buffer to fill with the read out data.
3841 @param DataLength The length of buffer.
3842 @param StartLba The start logic block address.
3843 @param SectorCount The number of blocks to read.
3844 @param BlkIo2Req The upstream BlockIo2 request.
3845 @param Token The pointer to the token associated with the
3846 non-blocking read request.
3848 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3850 @return others Status returned by calling
3851 ScsiRead10CommandEx().
3855 ScsiDiskAsyncRead10 (
3856 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3858 IN UINT8 TimesRetry
,
3859 OUT UINT8
*DataBuffer
,
3860 IN UINT32 DataLength
,
3862 IN UINT32 SectorCount
,
3863 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3864 IN EFI_BLOCK_IO2_TOKEN
*Token
3868 SCSI_ASYNC_RW_REQUEST
*Request
;
3869 EFI_EVENT AsyncIoEvent
;
3872 AsyncIoEvent
= NULL
;
3874 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3875 if (Request
== NULL
) {
3876 return EFI_OUT_OF_RESOURCES
;
3879 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3880 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3881 gBS
->RestoreTPL (OldTpl
);
3883 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3884 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3885 if (Request
->SenseData
== NULL
) {
3886 Status
= EFI_OUT_OF_RESOURCES
;
3890 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3891 Request
->Timeout
= Timeout
;
3892 Request
->TimesRetry
= TimesRetry
;
3893 Request
->InBuffer
= DataBuffer
;
3894 Request
->DataLength
= DataLength
;
3895 Request
->StartLba
= StartLba
;
3896 Request
->SectorCount
= SectorCount
;
3897 Request
->BlkIo2Req
= BlkIo2Req
;
3902 Status
= gBS
->CreateEvent (
3909 if (EFI_ERROR(Status
)) {
3913 Status
= ScsiRead10CommandEx (
3914 ScsiDiskDevice
->ScsiIo
,
3917 &Request
->SenseDataLength
,
3918 &Request
->HostAdapterStatus
,
3919 &Request
->TargetStatus
,
3921 &Request
->DataLength
,
3922 (UINT32
) Request
->StartLba
,
3923 Request
->SectorCount
,
3926 if (EFI_ERROR(Status
)) {
3933 if (AsyncIoEvent
!= NULL
) {
3934 gBS
->CloseEvent (AsyncIoEvent
);
3937 if (Request
!= NULL
) {
3938 if (Request
->SenseData
!= NULL
) {
3939 FreePool (Request
->SenseData
);
3942 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3943 RemoveEntryList (&Request
->Link
);
3944 gBS
->RestoreTPL (OldTpl
);
3954 Submit Async Write(10) command.
3956 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3957 @param Timeout The time to complete the command.
3958 @param TimesRetry The number of times the command has been retried.
3959 @param DataBuffer The buffer contains the data to write.
3960 @param DataLength The length of buffer.
3961 @param StartLba The start logic block address.
3962 @param SectorCount The number of blocks to write.
3963 @param BlkIo2Req The upstream BlockIo2 request.
3964 @param Token The pointer to the token associated with the
3965 non-blocking read request.
3967 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3969 @return others Status returned by calling
3970 ScsiWrite10CommandEx().
3974 ScsiDiskAsyncWrite10 (
3975 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3977 IN UINT8 TimesRetry
,
3978 IN UINT8
*DataBuffer
,
3979 IN UINT32 DataLength
,
3981 IN UINT32 SectorCount
,
3982 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3983 IN EFI_BLOCK_IO2_TOKEN
*Token
3987 SCSI_ASYNC_RW_REQUEST
*Request
;
3988 EFI_EVENT AsyncIoEvent
;
3991 AsyncIoEvent
= NULL
;
3993 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3994 if (Request
== NULL
) {
3995 return EFI_OUT_OF_RESOURCES
;
3998 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
3999 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4000 gBS
->RestoreTPL (OldTpl
);
4002 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4003 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4004 if (Request
->SenseData
== NULL
) {
4005 Status
= EFI_OUT_OF_RESOURCES
;
4009 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4010 Request
->Timeout
= Timeout
;
4011 Request
->TimesRetry
= TimesRetry
;
4012 Request
->OutBuffer
= DataBuffer
;
4013 Request
->DataLength
= DataLength
;
4014 Request
->StartLba
= StartLba
;
4015 Request
->SectorCount
= SectorCount
;
4016 Request
->BlkIo2Req
= BlkIo2Req
;
4021 Status
= gBS
->CreateEvent (
4028 if (EFI_ERROR(Status
)) {
4032 Status
= ScsiWrite10CommandEx (
4033 ScsiDiskDevice
->ScsiIo
,
4036 &Request
->SenseDataLength
,
4037 &Request
->HostAdapterStatus
,
4038 &Request
->TargetStatus
,
4040 &Request
->DataLength
,
4041 (UINT32
) Request
->StartLba
,
4042 Request
->SectorCount
,
4045 if (EFI_ERROR(Status
)) {
4052 if (AsyncIoEvent
!= NULL
) {
4053 gBS
->CloseEvent (AsyncIoEvent
);
4056 if (Request
!= NULL
) {
4057 if (Request
->SenseData
!= NULL
) {
4058 FreePool (Request
->SenseData
);
4061 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4062 RemoveEntryList (&Request
->Link
);
4063 gBS
->RestoreTPL (OldTpl
);
4073 Submit Async Read(16) command.
4075 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4076 @param Timeout The time to complete the command.
4077 @param TimesRetry The number of times the command has been retried.
4078 @param DataBuffer The buffer to fill with the read out data.
4079 @param DataLength The length of buffer.
4080 @param StartLba The start logic block address.
4081 @param SectorCount The number of blocks to read.
4082 @param BlkIo2Req The upstream BlockIo2 request.
4083 @param Token The pointer to the token associated with the
4084 non-blocking read request.
4086 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4088 @return others Status returned by calling
4089 ScsiRead16CommandEx().
4093 ScsiDiskAsyncRead16 (
4094 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4096 IN UINT8 TimesRetry
,
4097 OUT UINT8
*DataBuffer
,
4098 IN UINT32 DataLength
,
4100 IN UINT32 SectorCount
,
4101 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4102 IN EFI_BLOCK_IO2_TOKEN
*Token
4106 SCSI_ASYNC_RW_REQUEST
*Request
;
4107 EFI_EVENT AsyncIoEvent
;
4110 AsyncIoEvent
= NULL
;
4112 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4113 if (Request
== NULL
) {
4114 return EFI_OUT_OF_RESOURCES
;
4117 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4118 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4119 gBS
->RestoreTPL (OldTpl
);
4121 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4122 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4123 if (Request
->SenseData
== NULL
) {
4124 Status
= EFI_OUT_OF_RESOURCES
;
4128 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4129 Request
->Timeout
= Timeout
;
4130 Request
->TimesRetry
= TimesRetry
;
4131 Request
->InBuffer
= DataBuffer
;
4132 Request
->DataLength
= DataLength
;
4133 Request
->StartLba
= StartLba
;
4134 Request
->SectorCount
= SectorCount
;
4135 Request
->BlkIo2Req
= BlkIo2Req
;
4140 Status
= gBS
->CreateEvent (
4147 if (EFI_ERROR(Status
)) {
4151 Status
= ScsiRead16CommandEx (
4152 ScsiDiskDevice
->ScsiIo
,
4155 &Request
->SenseDataLength
,
4156 &Request
->HostAdapterStatus
,
4157 &Request
->TargetStatus
,
4159 &Request
->DataLength
,
4161 Request
->SectorCount
,
4164 if (EFI_ERROR(Status
)) {
4171 if (AsyncIoEvent
!= NULL
) {
4172 gBS
->CloseEvent (AsyncIoEvent
);
4175 if (Request
!= NULL
) {
4176 if (Request
->SenseData
!= NULL
) {
4177 FreePool (Request
->SenseData
);
4180 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4181 RemoveEntryList (&Request
->Link
);
4182 gBS
->RestoreTPL (OldTpl
);
4192 Submit Async Write(16) command.
4194 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
4195 @param Timeout The time to complete the command.
4196 @param TimesRetry The number of times the command has been retried.
4197 @param DataBuffer The buffer contains the data to write.
4198 @param DataLength The length of buffer.
4199 @param StartLba The start logic block address.
4200 @param SectorCount The number of blocks to write.
4201 @param BlkIo2Req The upstream BlockIo2 request.
4202 @param Token The pointer to the token associated with the
4203 non-blocking read request.
4205 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
4207 @return others Status returned by calling
4208 ScsiWrite16CommandEx().
4212 ScsiDiskAsyncWrite16 (
4213 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4215 IN UINT8 TimesRetry
,
4216 IN UINT8
*DataBuffer
,
4217 IN UINT32 DataLength
,
4219 IN UINT32 SectorCount
,
4220 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
4221 IN EFI_BLOCK_IO2_TOKEN
*Token
4225 SCSI_ASYNC_RW_REQUEST
*Request
;
4226 EFI_EVENT AsyncIoEvent
;
4229 AsyncIoEvent
= NULL
;
4231 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
4232 if (Request
== NULL
) {
4233 return EFI_OUT_OF_RESOURCES
;
4236 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4237 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
4238 gBS
->RestoreTPL (OldTpl
);
4240 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
4241 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
4242 if (Request
->SenseData
== NULL
) {
4243 Status
= EFI_OUT_OF_RESOURCES
;
4247 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
4248 Request
->Timeout
= Timeout
;
4249 Request
->TimesRetry
= TimesRetry
;
4250 Request
->OutBuffer
= DataBuffer
;
4251 Request
->DataLength
= DataLength
;
4252 Request
->StartLba
= StartLba
;
4253 Request
->SectorCount
= SectorCount
;
4254 Request
->BlkIo2Req
= BlkIo2Req
;
4259 Status
= gBS
->CreateEvent (
4266 if (EFI_ERROR(Status
)) {
4270 Status
= ScsiWrite16CommandEx (
4271 ScsiDiskDevice
->ScsiIo
,
4274 &Request
->SenseDataLength
,
4275 &Request
->HostAdapterStatus
,
4276 &Request
->TargetStatus
,
4278 &Request
->DataLength
,
4280 Request
->SectorCount
,
4283 if (EFI_ERROR(Status
)) {
4290 if (AsyncIoEvent
!= NULL
) {
4291 gBS
->CloseEvent (AsyncIoEvent
);
4294 if (Request
!= NULL
) {
4295 if (Request
->SenseData
!= NULL
) {
4296 FreePool (Request
->SenseData
);
4299 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
4300 RemoveEntryList (&Request
->Link
);
4301 gBS
->RestoreTPL (OldTpl
);
4311 Check sense key to find if media presents.
4313 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4314 @param SenseCounts The number of sense key
4316 @retval TRUE NOT any media
4317 @retval FALSE Media presents
4321 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4322 IN UINTN SenseCounts
4325 EFI_SCSI_SENSE_DATA
*SensePtr
;
4330 SensePtr
= SenseData
;
4332 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4334 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
4335 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
4337 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
4338 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
4351 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4352 @param SenseCounts The number of sense key
4355 @retval FALSE NOT error
4359 ScsiDiskIsMediaError (
4360 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4361 IN UINTN SenseCounts
4364 EFI_SCSI_SENSE_DATA
*SensePtr
;
4369 SensePtr
= SenseData
;
4371 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4373 switch (SensePtr
->Sense_Key
) {
4375 case EFI_SCSI_SK_MEDIUM_ERROR
:
4377 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
4379 switch (SensePtr
->Addnl_Sense_Code
) {
4384 case EFI_SCSI_ASC_MEDIA_ERR1
:
4389 case EFI_SCSI_ASC_MEDIA_ERR2
:
4394 case EFI_SCSI_ASC_MEDIA_ERR3
:
4395 case EFI_SCSI_ASC_MEDIA_ERR4
:
4405 case EFI_SCSI_SK_NOT_READY
:
4407 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4409 switch (SensePtr
->Addnl_Sense_Code
) {
4411 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
4413 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
4434 Check sense key to find if hardware error happens.
4436 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4437 @param SenseCounts The number of sense key
4439 @retval TRUE Hardware error exits.
4440 @retval FALSE NO error.
4444 ScsiDiskIsHardwareError (
4445 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4446 IN UINTN SenseCounts
4449 EFI_SCSI_SENSE_DATA
*SensePtr
;
4454 SensePtr
= SenseData
;
4456 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4459 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
4461 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
4473 Check sense key to find if media has changed.
4475 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4476 @param SenseCounts The number of sense key
4478 @retval TRUE Media is changed.
4479 @retval FALSE Media is NOT changed.
4482 ScsiDiskIsMediaChange (
4483 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4484 IN UINTN SenseCounts
4487 EFI_SCSI_SENSE_DATA
*SensePtr
;
4489 BOOLEAN IsMediaChanged
;
4491 IsMediaChanged
= FALSE
;
4492 SensePtr
= SenseData
;
4494 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4496 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
4497 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
4499 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
4500 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
4501 IsMediaChanged
= TRUE
;
4507 return IsMediaChanged
;
4511 Check sense key to find if reset happens.
4513 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4514 @param SenseCounts The number of sense key
4516 @retval TRUE It is reset before.
4517 @retval FALSE It is NOT reset before.
4521 ScsiDiskIsResetBefore (
4522 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4523 IN UINTN SenseCounts
4526 EFI_SCSI_SENSE_DATA
*SensePtr
;
4528 BOOLEAN IsResetBefore
;
4530 IsResetBefore
= FALSE
;
4531 SensePtr
= SenseData
;
4533 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4536 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
4537 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
4539 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
4540 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
4541 IsResetBefore
= TRUE
;
4547 return IsResetBefore
;
4551 Check sense key to find if the drive is ready.
4553 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4554 @param SenseCounts The number of sense key
4555 @param RetryLater The flag means if need a retry
4557 @retval TRUE Drive is ready.
4558 @retval FALSE Drive is NOT ready.
4562 ScsiDiskIsDriveReady (
4563 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4564 IN UINTN SenseCounts
,
4565 OUT BOOLEAN
*RetryLater
4568 EFI_SCSI_SENSE_DATA
*SensePtr
;
4573 *RetryLater
= FALSE
;
4574 SensePtr
= SenseData
;
4576 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4578 switch (SensePtr
->Sense_Key
) {
4580 case EFI_SCSI_SK_NOT_READY
:
4582 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4584 switch (SensePtr
->Addnl_Sense_Code
) {
4585 case EFI_SCSI_ASC_NOT_READY
:
4587 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
4589 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
4590 case EFI_SCSI_ASCQ_IN_PROGRESS
:
4592 // Additional Sense Code Qualifier is
4593 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
4601 *RetryLater
= FALSE
;
4622 Check sense key to find if it has sense key.
4624 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
4625 @param SenseCounts - The number of sense key
4627 @retval TRUE It has sense key.
4628 @retval FALSE It has NOT any sense key.
4632 ScsiDiskHaveSenseKey (
4633 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4634 IN UINTN SenseCounts
4637 EFI_SCSI_SENSE_DATA
*SensePtr
;
4639 BOOLEAN HaveSenseKey
;
4641 if (SenseCounts
== 0) {
4642 HaveSenseKey
= FALSE
;
4644 HaveSenseKey
= TRUE
;
4647 SensePtr
= SenseData
;
4649 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4652 // Sense Key is SK_NO_SENSE (0x0)
4654 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
4656 HaveSenseKey
= FALSE
;
4662 return HaveSenseKey
;
4666 Release resource about disk device.
4668 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4672 ReleaseScsiDiskDeviceResources (
4673 IN SCSI_DISK_DEV
*ScsiDiskDevice
4676 if (ScsiDiskDevice
== NULL
) {
4680 if (ScsiDiskDevice
->SenseData
!= NULL
) {
4681 FreePool (ScsiDiskDevice
->SenseData
);
4682 ScsiDiskDevice
->SenseData
= NULL
;
4685 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
4686 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
4687 ScsiDiskDevice
->ControllerNameTable
= NULL
;
4690 FreePool (ScsiDiskDevice
);
4692 ScsiDiskDevice
= NULL
;
4696 Determine if Block Io & Block Io2 should be produced.
4699 @param ChildHandle Child Handle to retrieve Parent information.
4701 @retval TRUE Should produce Block Io & Block Io2.
4702 @retval FALSE Should not produce Block Io & Block Io2.
4706 DetermineInstallBlockIo (
4707 IN EFI_HANDLE ChildHandle
4710 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
4711 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
4714 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
4715 // check its attribute, logic or physical.
4717 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
4718 if (ExtScsiPassThru
!= NULL
) {
4719 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
4725 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
4726 // check its attribute, logic or physical.
4728 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
4729 if (ScsiPassThru
!= NULL
) {
4730 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
4739 Search protocol database and check to see if the protocol
4740 specified by ProtocolGuid is present on a ControllerHandle and opened by
4741 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
4742 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
4743 will be opened on it.
4746 @param ProtocolGuid ProtocolGuid pointer.
4747 @param ChildHandle Child Handle to retrieve Parent information.
4753 IN EFI_GUID
*ProtocolGuid
,
4754 IN EFI_HANDLE ChildHandle
4761 EFI_HANDLE
*HandleBuffer
;
4764 // Retrieve the list of all handles from the handle database
4766 Status
= gBS
->LocateHandleBuffer (
4774 if (EFI_ERROR (Status
)) {
4779 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
4781 for (Index
= 0; Index
< HandleCount
; Index
++) {
4782 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
4783 if (!EFI_ERROR (Status
)) {
4784 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
4785 if (!EFI_ERROR (Status
)) {
4786 gBS
->FreePool (HandleBuffer
);
4792 gBS
->FreePool (HandleBuffer
);
4797 Provides inquiry information for the controller type.
4799 This function is used by the IDE bus driver to get inquiry data. Data format
4800 of Identify data is defined by the Interface GUID.
4802 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4803 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
4804 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
4806 @retval EFI_SUCCESS The command was accepted without any errors.
4807 @retval EFI_NOT_FOUND Device does not support this data class
4808 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
4809 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
4814 ScsiDiskInfoInquiry (
4815 IN EFI_DISK_INFO_PROTOCOL
*This
,
4816 IN OUT VOID
*InquiryData
,
4817 IN OUT UINT32
*InquiryDataSize
4821 SCSI_DISK_DEV
*ScsiDiskDevice
;
4823 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4825 Status
= EFI_BUFFER_TOO_SMALL
;
4826 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
4827 Status
= EFI_SUCCESS
;
4828 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
4830 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
4836 Provides identify information for the controller type.
4838 This function is used by the IDE bus driver to get identify data. Data format
4839 of Identify data is defined by the Interface GUID.
4841 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
4843 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
4844 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
4847 @retval EFI_SUCCESS The command was accepted without any errors.
4848 @retval EFI_NOT_FOUND Device does not support this data class
4849 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
4850 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
4855 ScsiDiskInfoIdentify (
4856 IN EFI_DISK_INFO_PROTOCOL
*This
,
4857 IN OUT VOID
*IdentifyData
,
4858 IN OUT UINT32
*IdentifyDataSize
4862 SCSI_DISK_DEV
*ScsiDiskDevice
;
4864 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
4866 // Physical SCSI bus does not support this data class.
4868 return EFI_NOT_FOUND
;
4871 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4873 Status
= EFI_BUFFER_TOO_SMALL
;
4874 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
4875 Status
= EFI_SUCCESS
;
4876 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
4878 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
4883 Provides sense data information for the controller type.
4885 This function is used by the IDE bus driver to get sense data.
4886 Data format of Sense data is defined by the Interface GUID.
4888 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4889 @param[in, out] SenseData Pointer to the SenseData.
4890 @param[in, out] SenseDataSize Size of SenseData in bytes.
4891 @param[out] SenseDataNumber Pointer to the value for the sense data size.
4893 @retval EFI_SUCCESS The command was accepted without any errors.
4894 @retval EFI_NOT_FOUND Device does not support this data class.
4895 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
4896 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
4901 ScsiDiskInfoSenseData (
4902 IN EFI_DISK_INFO_PROTOCOL
*This
,
4903 IN OUT VOID
*SenseData
,
4904 IN OUT UINT32
*SenseDataSize
,
4905 OUT UINT8
*SenseDataNumber
4908 return EFI_NOT_FOUND
;
4913 This function is used by the IDE bus driver to get controller information.
4915 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4916 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
4917 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
4919 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
4920 @retval EFI_UNSUPPORTED This is not an IDE device.
4925 ScsiDiskInfoWhichIde (
4926 IN EFI_DISK_INFO_PROTOCOL
*This
,
4927 OUT UINT32
*IdeChannel
,
4928 OUT UINT32
*IdeDevice
4931 SCSI_DISK_DEV
*ScsiDiskDevice
;
4933 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
4935 // This is not an IDE physical device.
4937 return EFI_UNSUPPORTED
;
4940 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4941 *IdeChannel
= ScsiDiskDevice
->Channel
;
4942 *IdeDevice
= ScsiDiskDevice
->Device
;
4949 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
4951 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
4952 implement Identify() interface for DiskInfo protocol. The ATA command is sent
4953 via SCSI Request Packet.
4955 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4957 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
4958 @retval others Some error occurred during the identification that ATAPI device.
4962 AtapiIdentifyDevice (
4963 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
4966 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
4970 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
4972 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
4973 ZeroMem (Cdb
, sizeof (Cdb
));
4975 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
4976 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
4977 CommandPacket
.Cdb
= Cdb
;
4978 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
4979 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
4980 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
4982 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
4987 Initialize the installation of DiskInfo protocol.
4989 This function prepares for the installation of DiskInfo protocol on the child handle.
4990 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
4991 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
4992 to be IDE/AHCI interface GUID.
4994 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
4995 @param ChildHandle Child handle to install DiskInfo protocol.
4999 InitializeInstallDiskInfo (
5000 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
5001 IN EFI_HANDLE ChildHandle
5005 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
5006 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
5007 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
5008 SATA_DEVICE_PATH
*SataDevicePath
;
5009 UINTN IdentifyRetry
;
5011 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
5013 // Device Path protocol must be installed on the device handle.
5015 ASSERT_EFI_ERROR (Status
);
5017 // Copy the DiskInfo protocol template.
5019 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
5021 while (!IsDevicePathEnd (DevicePathNode
)) {
5022 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
5023 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
5024 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
5025 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
5026 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
5027 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
5032 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
5033 // with IDE/AHCI interface GUID.
5035 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
5036 if (!EFI_ERROR (Status
)) {
5037 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
5039 // We find the valid ATAPI device path
5041 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
5042 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
5043 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
5045 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
5047 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
5050 // We find the valid SATA device path
5052 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
5053 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
5054 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
5056 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
5058 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
5062 } while (--IdentifyRetry
> 0);
5063 } else if ((DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
5064 (DevicePathSubType (ChildDevicePathNode
) == MSG_UFS_DP
)) {
5065 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoUfsInterfaceGuid
);
5068 DevicePathNode
= ChildDevicePathNode
;