2 SCSI disk driver that layers on every SCSI IO protocol in the system.
4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding
= {
19 ScsiDiskDriverBindingSupported
,
20 ScsiDiskDriverBindingStart
,
21 ScsiDiskDriverBindingStop
,
27 EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate
= {
28 EFI_DISK_INFO_SCSI_INTERFACE_GUID
,
31 ScsiDiskInfoSenseData
,
36 Allocates an aligned buffer for SCSI disk.
38 This function allocates an aligned buffer for the SCSI disk to perform
39 SCSI IO operations. The alignment requirement is from SCSI IO interface.
41 @param ScsiDiskDevice The SCSI disk involved for the operation.
42 @param BufferSize The request buffer size.
44 @return A pointer to the aligned buffer or NULL if the allocation fails.
48 AllocateAlignedBuffer (
49 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
53 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), ScsiDiskDevice
->ScsiIo
->IoAlign
);
57 Frees an aligned buffer for SCSI disk.
59 This function frees an aligned buffer for the SCSI disk to perform
62 @param Buffer The aligned buffer to be freed.
63 @param BufferSize The request buffer size.
73 FreeAlignedPages (Buffer
, EFI_SIZE_TO_PAGES (BufferSize
));
78 The user Entry Point for module ScsiDisk.
80 The user code starts with this function.
82 @param ImageHandle The firmware allocated handle for the EFI image.
83 @param SystemTable A pointer to the EFI System Table.
85 @retval EFI_SUCCESS The entry point is executed successfully.
86 @retval other Some error occurs when executing this entry point.
92 IN EFI_HANDLE ImageHandle
,
93 IN EFI_SYSTEM_TABLE
*SystemTable
99 // Install driver model protocol(s).
101 Status
= EfiLibInstallDriverBindingComponentName2 (
104 &gScsiDiskDriverBinding
,
106 &gScsiDiskComponentName
,
107 &gScsiDiskComponentName2
109 ASSERT_EFI_ERROR (Status
);
116 Test to see if this driver supports ControllerHandle.
118 This service is called by the EFI boot service ConnectController(). In order
119 to make drivers as small as possible, there are a few calling restrictions for
120 this service. ConnectController() must follow these calling restrictions.
121 If any other agent wishes to call Supported() it must also follow these
122 calling restrictions.
124 @param This Protocol instance pointer.
125 @param ControllerHandle Handle of device to test
126 @param RemainingDevicePath Optional parameter use to pick a specific child
129 @retval EFI_SUCCESS This driver supports this device
130 @retval EFI_ALREADY_STARTED This driver is already running on this device
131 @retval other This driver does not support this device
136 ScsiDiskDriverBindingSupported (
137 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
138 IN EFI_HANDLE Controller
,
139 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
143 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
146 Status
= gBS
->OpenProtocol (
148 &gEfiScsiIoProtocolGuid
,
150 This
->DriverBindingHandle
,
152 EFI_OPEN_PROTOCOL_BY_DRIVER
154 if (EFI_ERROR (Status
)) {
158 Status
= ScsiIo
->GetDeviceType (ScsiIo
, &DeviceType
);
159 if (!EFI_ERROR (Status
)) {
160 if ((DeviceType
== EFI_SCSI_TYPE_DISK
) || (DeviceType
== EFI_SCSI_TYPE_CDROM
)) {
161 Status
= EFI_SUCCESS
;
163 Status
= EFI_UNSUPPORTED
;
169 &gEfiScsiIoProtocolGuid
,
170 This
->DriverBindingHandle
,
178 Start this driver on ControllerHandle.
180 This service is called by the EFI boot service ConnectController(). In order
181 to make drivers as small as possible, there are a few calling restrictions for
182 this service. ConnectController() must follow these calling restrictions. If
183 any other agent wishes to call Start() it must also follow these calling
186 @param This Protocol instance pointer.
187 @param ControllerHandle Handle of device to bind driver to
188 @param RemainingDevicePath Optional parameter use to pick a specific child
191 @retval EFI_SUCCESS This driver is added to ControllerHandle
192 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
193 @retval other This driver does not support this device
198 ScsiDiskDriverBindingStart (
199 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
200 IN EFI_HANDLE Controller
,
201 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
205 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
206 SCSI_DISK_DEV
*ScsiDiskDevice
;
211 BOOLEAN MustReadCapacity
;
213 MustReadCapacity
= TRUE
;
215 ScsiDiskDevice
= (SCSI_DISK_DEV
*) AllocateZeroPool (sizeof (SCSI_DISK_DEV
));
216 if (ScsiDiskDevice
== NULL
) {
217 return EFI_OUT_OF_RESOURCES
;
220 Status
= gBS
->OpenProtocol (
222 &gEfiScsiIoProtocolGuid
,
224 This
->DriverBindingHandle
,
226 EFI_OPEN_PROTOCOL_BY_DRIVER
228 if (EFI_ERROR (Status
)) {
229 FreePool (ScsiDiskDevice
);
233 ScsiDiskDevice
->Signature
= SCSI_DISK_DEV_SIGNATURE
;
234 ScsiDiskDevice
->ScsiIo
= ScsiIo
;
235 ScsiDiskDevice
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION3
;
236 ScsiDiskDevice
->BlkIo
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
237 ScsiDiskDevice
->BlkIo
.Media
->IoAlign
= ScsiIo
->IoAlign
;
238 ScsiDiskDevice
->BlkIo
.Reset
= ScsiDiskReset
;
239 ScsiDiskDevice
->BlkIo
.ReadBlocks
= ScsiDiskReadBlocks
;
240 ScsiDiskDevice
->BlkIo
.WriteBlocks
= ScsiDiskWriteBlocks
;
241 ScsiDiskDevice
->BlkIo
.FlushBlocks
= ScsiDiskFlushBlocks
;
242 ScsiDiskDevice
->BlkIo2
.Media
= &ScsiDiskDevice
->BlkIoMedia
;
243 ScsiDiskDevice
->BlkIo2
.Reset
= ScsiDiskResetEx
;
244 ScsiDiskDevice
->BlkIo2
.ReadBlocksEx
= ScsiDiskReadBlocksEx
;
245 ScsiDiskDevice
->BlkIo2
.WriteBlocksEx
= ScsiDiskWriteBlocksEx
;
246 ScsiDiskDevice
->BlkIo2
.FlushBlocksEx
= ScsiDiskFlushBlocksEx
;
247 ScsiDiskDevice
->Handle
= Controller
;
248 InitializeListHead (&ScsiDiskDevice
->BlkIo2Queue
);
250 ScsiIo
->GetDeviceType (ScsiIo
, &(ScsiDiskDevice
->DeviceType
));
251 switch (ScsiDiskDevice
->DeviceType
) {
252 case EFI_SCSI_TYPE_DISK
:
253 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x200;
254 MustReadCapacity
= TRUE
;
257 case EFI_SCSI_TYPE_CDROM
:
258 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= 0x800;
259 MustReadCapacity
= FALSE
;
263 // The Sense Data Array's initial size is 6
265 ScsiDiskDevice
->SenseDataNumber
= 6;
266 ScsiDiskDevice
->SenseData
= (EFI_SCSI_SENSE_DATA
*) AllocateZeroPool (
267 sizeof (EFI_SCSI_SENSE_DATA
) * ScsiDiskDevice
->SenseDataNumber
269 if (ScsiDiskDevice
->SenseData
== NULL
) {
272 &gEfiScsiIoProtocolGuid
,
273 This
->DriverBindingHandle
,
276 FreePool (ScsiDiskDevice
);
277 return EFI_OUT_OF_RESOURCES
;
281 // Retrieve device information
284 for (Index
= 0; Index
< MaxRetry
; Index
++) {
285 Status
= ScsiDiskInquiryDevice (ScsiDiskDevice
, &NeedRetry
);
286 if (!EFI_ERROR (Status
)) {
291 FreePool (ScsiDiskDevice
->SenseData
);
294 &gEfiScsiIoProtocolGuid
,
295 This
->DriverBindingHandle
,
298 FreePool (ScsiDiskDevice
);
299 return EFI_DEVICE_ERROR
;
303 // The second parameter "TRUE" means must
304 // retrieve media capacity
306 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, MustReadCapacity
, &Temp
);
307 if (!EFI_ERROR (Status
)) {
309 // Determine if Block IO & Block IO2 should be produced on this controller
312 if (DetermineInstallBlockIo(Controller
)) {
313 InitializeInstallDiskInfo(ScsiDiskDevice
, Controller
);
314 Status
= gBS
->InstallMultipleProtocolInterfaces (
316 &gEfiBlockIoProtocolGuid
,
317 &ScsiDiskDevice
->BlkIo
,
318 &gEfiBlockIo2ProtocolGuid
,
319 &ScsiDiskDevice
->BlkIo2
,
320 &gEfiDiskInfoProtocolGuid
,
321 &ScsiDiskDevice
->DiskInfo
,
324 if (!EFI_ERROR(Status
)) {
325 ScsiDiskDevice
->ControllerNameTable
= NULL
;
328 gScsiDiskComponentName
.SupportedLanguages
,
329 &ScsiDiskDevice
->ControllerNameTable
,
335 gScsiDiskComponentName2
.SupportedLanguages
,
336 &ScsiDiskDevice
->ControllerNameTable
,
345 gBS
->FreePool (ScsiDiskDevice
->SenseData
);
346 gBS
->FreePool (ScsiDiskDevice
);
349 &gEfiScsiIoProtocolGuid
,
350 This
->DriverBindingHandle
,
359 Stop this driver on ControllerHandle.
361 This service is called by the EFI boot service DisconnectController().
362 In order to make drivers as small as possible, there are a few calling
363 restrictions for this service. DisconnectController() must follow these
364 calling restrictions. If any other agent wishes to call Stop() it must
365 also follow these calling restrictions.
367 @param This Protocol instance pointer.
368 @param ControllerHandle Handle of device to stop driver on
369 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
370 children is zero stop the entire bus driver.
371 @param ChildHandleBuffer List of Child Handles to Stop.
373 @retval EFI_SUCCESS This driver is removed ControllerHandle
374 @retval other This driver was not removed from this device
379 ScsiDiskDriverBindingStop (
380 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
381 IN EFI_HANDLE Controller
,
382 IN UINTN NumberOfChildren
,
383 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
386 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
387 SCSI_DISK_DEV
*ScsiDiskDevice
;
390 Status
= gBS
->OpenProtocol (
392 &gEfiBlockIoProtocolGuid
,
394 This
->DriverBindingHandle
,
396 EFI_OPEN_PROTOCOL_GET_PROTOCOL
398 if (EFI_ERROR (Status
)) {
402 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (BlkIo
);
405 // Wait for the BlockIo2 requests queue to become empty
407 while (!IsListEmpty (&ScsiDiskDevice
->BlkIo2Queue
));
409 Status
= gBS
->UninstallMultipleProtocolInterfaces (
411 &gEfiBlockIoProtocolGuid
,
412 &ScsiDiskDevice
->BlkIo
,
413 &gEfiBlockIo2ProtocolGuid
,
414 &ScsiDiskDevice
->BlkIo2
,
415 &gEfiDiskInfoProtocolGuid
,
416 &ScsiDiskDevice
->DiskInfo
,
419 if (!EFI_ERROR (Status
)) {
422 &gEfiScsiIoProtocolGuid
,
423 This
->DriverBindingHandle
,
427 ReleaseScsiDiskDeviceResources (ScsiDiskDevice
);
441 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
442 @param ExtendedVerification The flag about if extend verificate
444 @retval EFI_SUCCESS The device was reset.
445 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
447 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
453 IN EFI_BLOCK_IO_PROTOCOL
*This
,
454 IN BOOLEAN ExtendedVerification
458 SCSI_DISK_DEV
*ScsiDiskDevice
;
461 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
463 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
465 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
467 if (EFI_ERROR (Status
)) {
468 Status
= EFI_DEVICE_ERROR
;
472 if (!ExtendedVerification
) {
476 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
478 if (EFI_ERROR (Status
)) {
479 Status
= EFI_DEVICE_ERROR
;
484 gBS
->RestoreTPL (OldTpl
);
489 The function is to Read Block from SCSI Disk.
491 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
492 @param MediaId The Id of Media detected
493 @param Lba The logic block address
494 @param BufferSize The size of Buffer
495 @param Buffer The buffer to fill the read out data
497 @retval EFI_SUCCESS Successfully to read out block.
498 @retval EFI_DEVICE_ERROR Fail to detect media.
499 @retval EFI_NO_MEDIA Media is not present.
500 @retval EFI_MEDIA_CHANGED Media has changed.
501 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
502 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
508 IN EFI_BLOCK_IO_PROTOCOL
*This
,
515 SCSI_DISK_DEV
*ScsiDiskDevice
;
516 EFI_BLOCK_IO_MEDIA
*Media
;
519 UINTN NumberOfBlocks
;
524 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
525 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
527 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
529 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
530 if (EFI_ERROR (Status
)) {
531 Status
= EFI_DEVICE_ERROR
;
536 gBS
->ReinstallProtocolInterface (
537 ScsiDiskDevice
->Handle
,
538 &gEfiBlockIoProtocolGuid
,
539 &ScsiDiskDevice
->BlkIo
,
540 &ScsiDiskDevice
->BlkIo
542 gBS
->ReinstallProtocolInterface (
543 ScsiDiskDevice
->Handle
,
544 &gEfiBlockIo2ProtocolGuid
,
545 &ScsiDiskDevice
->BlkIo2
,
546 &ScsiDiskDevice
->BlkIo2
548 Status
= EFI_MEDIA_CHANGED
;
553 // Get the intrinsic block size
555 Media
= ScsiDiskDevice
->BlkIo
.Media
;
556 BlockSize
= Media
->BlockSize
;
558 NumberOfBlocks
= BufferSize
/ BlockSize
;
560 if (!(Media
->MediaPresent
)) {
561 Status
= EFI_NO_MEDIA
;
565 if (MediaId
!= Media
->MediaId
) {
566 Status
= EFI_MEDIA_CHANGED
;
570 if (Buffer
== NULL
) {
571 Status
= EFI_INVALID_PARAMETER
;
575 if (BufferSize
== 0) {
576 Status
= EFI_SUCCESS
;
580 if (BufferSize
% BlockSize
!= 0) {
581 Status
= EFI_BAD_BUFFER_SIZE
;
585 if (Lba
> Media
->LastBlock
) {
586 Status
= EFI_INVALID_PARAMETER
;
590 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
591 Status
= EFI_INVALID_PARAMETER
;
595 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
596 Status
= EFI_INVALID_PARAMETER
;
601 // If all the parameters are valid, then perform read sectors command
602 // to transfer data from device to host.
604 Status
= ScsiDiskReadSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
607 gBS
->RestoreTPL (OldTpl
);
612 The function is to Write Block to SCSI Disk.
614 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
615 @param MediaId The Id of Media detected
616 @param Lba The logic block address
617 @param BufferSize The size of Buffer
618 @param Buffer The buffer to fill the read out data
620 @retval EFI_SUCCESS Successfully to read out block.
621 @retval EFI_WRITE_PROTECTED The device can not be written to.
622 @retval EFI_DEVICE_ERROR Fail to detect media.
623 @retval EFI_NO_MEDIA Media is not present.
624 @retval EFI_MEDIA_CHNAGED Media has changed.
625 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
626 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.
631 ScsiDiskWriteBlocks (
632 IN EFI_BLOCK_IO_PROTOCOL
*This
,
639 SCSI_DISK_DEV
*ScsiDiskDevice
;
640 EFI_BLOCK_IO_MEDIA
*Media
;
643 UINTN NumberOfBlocks
;
648 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
649 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO (This
);
651 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
653 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
654 if (EFI_ERROR (Status
)) {
655 Status
= EFI_DEVICE_ERROR
;
660 gBS
->ReinstallProtocolInterface (
661 ScsiDiskDevice
->Handle
,
662 &gEfiBlockIoProtocolGuid
,
663 &ScsiDiskDevice
->BlkIo
,
664 &ScsiDiskDevice
->BlkIo
666 gBS
->ReinstallProtocolInterface (
667 ScsiDiskDevice
->Handle
,
668 &gEfiBlockIo2ProtocolGuid
,
669 &ScsiDiskDevice
->BlkIo2
,
670 &ScsiDiskDevice
->BlkIo2
672 Status
= EFI_MEDIA_CHANGED
;
677 // Get the intrinsic block size
679 Media
= ScsiDiskDevice
->BlkIo
.Media
;
680 BlockSize
= Media
->BlockSize
;
682 NumberOfBlocks
= BufferSize
/ BlockSize
;
684 if (!(Media
->MediaPresent
)) {
685 Status
= EFI_NO_MEDIA
;
689 if (MediaId
!= Media
->MediaId
) {
690 Status
= EFI_MEDIA_CHANGED
;
694 if (BufferSize
== 0) {
695 Status
= EFI_SUCCESS
;
699 if (Buffer
== NULL
) {
700 Status
= EFI_INVALID_PARAMETER
;
704 if (BufferSize
% BlockSize
!= 0) {
705 Status
= EFI_BAD_BUFFER_SIZE
;
709 if (Lba
> Media
->LastBlock
) {
710 Status
= EFI_INVALID_PARAMETER
;
714 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
715 Status
= EFI_INVALID_PARAMETER
;
719 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
720 Status
= EFI_INVALID_PARAMETER
;
724 // if all the parameters are valid, then perform read sectors command
725 // to transfer data from device to host.
727 Status
= ScsiDiskWriteSectors (ScsiDiskDevice
, Buffer
, Lba
, NumberOfBlocks
);
730 gBS
->RestoreTPL (OldTpl
);
737 EFI_SUCCESS is returned directly.
739 @param This The pointer of EFI_BLOCK_IO_PROTOCOL
741 @retval EFI_SUCCESS All outstanding data was written to the device
746 ScsiDiskFlushBlocks (
747 IN EFI_BLOCK_IO_PROTOCOL
*This
760 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.
761 @param ExtendedVerification The flag about if extend verificate.
763 @retval EFI_SUCCESS The device was reset.
764 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
766 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().
772 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
773 IN BOOLEAN ExtendedVerification
777 SCSI_DISK_DEV
*ScsiDiskDevice
;
780 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
782 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
784 Status
= ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
786 if (EFI_ERROR (Status
)) {
787 Status
= EFI_DEVICE_ERROR
;
791 if (!ExtendedVerification
) {
795 Status
= ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
797 if (EFI_ERROR (Status
)) {
798 Status
= EFI_DEVICE_ERROR
;
803 gBS
->RestoreTPL (OldTpl
);
808 The function is to Read Block from SCSI Disk.
810 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
811 @param MediaId The Id of Media detected.
812 @param Lba The logic block address.
813 @param Token A pointer to the token associated with the transaction.
814 @param BufferSize The size of Buffer.
815 @param Buffer The buffer to fill the read out data.
817 @retval EFI_SUCCESS The read request was queued if Token-> Event is
818 not NULL. The data was read correctly from the
819 device if theToken-> Event is NULL.
820 @retval EFI_DEVICE_ERROR The device reported an error while attempting
821 to perform the read operation.
822 @retval EFI_NO_MEDIA There is no media in the device.
823 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
824 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
825 the intrinsic block size of the device.
826 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
827 valid, or the buffer is not on proper
829 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
835 ScsiDiskReadBlocksEx (
836 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
839 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
844 SCSI_DISK_DEV
*ScsiDiskDevice
;
845 EFI_BLOCK_IO_MEDIA
*Media
;
848 UINTN NumberOfBlocks
;
853 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
854 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
856 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
858 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
859 if (EFI_ERROR (Status
)) {
860 Status
= EFI_DEVICE_ERROR
;
865 gBS
->ReinstallProtocolInterface (
866 ScsiDiskDevice
->Handle
,
867 &gEfiBlockIoProtocolGuid
,
868 &ScsiDiskDevice
->BlkIo
,
869 &ScsiDiskDevice
->BlkIo
871 gBS
->ReinstallProtocolInterface (
872 ScsiDiskDevice
->Handle
,
873 &gEfiBlockIo2ProtocolGuid
,
874 &ScsiDiskDevice
->BlkIo2
,
875 &ScsiDiskDevice
->BlkIo2
877 Status
= EFI_MEDIA_CHANGED
;
882 // Get the intrinsic block size
884 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
885 BlockSize
= Media
->BlockSize
;
887 NumberOfBlocks
= BufferSize
/ BlockSize
;
889 if (!(Media
->MediaPresent
)) {
890 Status
= EFI_NO_MEDIA
;
894 if (MediaId
!= Media
->MediaId
) {
895 Status
= EFI_MEDIA_CHANGED
;
899 if (Buffer
== NULL
) {
900 Status
= EFI_INVALID_PARAMETER
;
904 if (BufferSize
== 0) {
905 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
906 Token
->TransactionStatus
= EFI_SUCCESS
;
907 gBS
->SignalEvent (Token
->Event
);
910 Status
= EFI_SUCCESS
;
914 if (BufferSize
% BlockSize
!= 0) {
915 Status
= EFI_BAD_BUFFER_SIZE
;
919 if (Lba
> Media
->LastBlock
) {
920 Status
= EFI_INVALID_PARAMETER
;
924 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
925 Status
= EFI_INVALID_PARAMETER
;
929 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
930 Status
= EFI_INVALID_PARAMETER
;
935 // If all the parameters are valid, then perform read sectors command
936 // to transfer data from device to host.
938 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
939 Token
->TransactionStatus
= EFI_SUCCESS
;
940 Status
= ScsiDiskAsyncReadSectors (
948 Status
= ScsiDiskReadSectors (
957 gBS
->RestoreTPL (OldTpl
);
962 The function is to Write Block to SCSI Disk.
964 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.
965 @param MediaId The Id of Media detected.
966 @param Lba The logic block address.
967 @param Token A pointer to the token associated with the transaction.
968 @param BufferSize The size of Buffer.
969 @param Buffer The buffer to fill the read out data.
971 @retval EFI_SUCCESS The data were written correctly to the device.
972 @retval EFI_WRITE_PROTECTED The device cannot be written to.
973 @retval EFI_NO_MEDIA There is no media in the device.
974 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
975 @retval EFI_DEVICE_ERROR The device reported an error while attempting
976 to perform the write operation.
977 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
978 the intrinsic block size of the device.
979 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
980 valid, or the buffer is not on proper
986 ScsiDiskWriteBlocksEx (
987 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
990 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
995 SCSI_DISK_DEV
*ScsiDiskDevice
;
996 EFI_BLOCK_IO_MEDIA
*Media
;
999 UINTN NumberOfBlocks
;
1000 BOOLEAN MediaChange
;
1003 MediaChange
= FALSE
;
1004 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1005 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_BLKIO2 (This
);
1007 if (!IS_DEVICE_FIXED(ScsiDiskDevice
)) {
1009 Status
= ScsiDiskDetectMedia (ScsiDiskDevice
, FALSE
, &MediaChange
);
1010 if (EFI_ERROR (Status
)) {
1011 Status
= EFI_DEVICE_ERROR
;
1016 gBS
->ReinstallProtocolInterface (
1017 ScsiDiskDevice
->Handle
,
1018 &gEfiBlockIoProtocolGuid
,
1019 &ScsiDiskDevice
->BlkIo
,
1020 &ScsiDiskDevice
->BlkIo
1022 gBS
->ReinstallProtocolInterface (
1023 ScsiDiskDevice
->Handle
,
1024 &gEfiBlockIo2ProtocolGuid
,
1025 &ScsiDiskDevice
->BlkIo2
,
1026 &ScsiDiskDevice
->BlkIo2
1028 Status
= EFI_MEDIA_CHANGED
;
1033 // Get the intrinsic block size
1035 Media
= ScsiDiskDevice
->BlkIo2
.Media
;
1036 BlockSize
= Media
->BlockSize
;
1038 NumberOfBlocks
= BufferSize
/ BlockSize
;
1040 if (!(Media
->MediaPresent
)) {
1041 Status
= EFI_NO_MEDIA
;
1045 if (MediaId
!= Media
->MediaId
) {
1046 Status
= EFI_MEDIA_CHANGED
;
1050 if (BufferSize
== 0) {
1051 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1052 Token
->TransactionStatus
= EFI_SUCCESS
;
1053 gBS
->SignalEvent (Token
->Event
);
1056 Status
= EFI_SUCCESS
;
1060 if (Buffer
== NULL
) {
1061 Status
= EFI_INVALID_PARAMETER
;
1065 if (BufferSize
% BlockSize
!= 0) {
1066 Status
= EFI_BAD_BUFFER_SIZE
;
1070 if (Lba
> Media
->LastBlock
) {
1071 Status
= EFI_INVALID_PARAMETER
;
1075 if ((Lba
+ NumberOfBlocks
- 1) > Media
->LastBlock
) {
1076 Status
= EFI_INVALID_PARAMETER
;
1080 if ((Media
->IoAlign
> 1) && (((UINTN
) Buffer
& (Media
->IoAlign
- 1)) != 0)) {
1081 Status
= EFI_INVALID_PARAMETER
;
1086 // if all the parameters are valid, then perform write sectors command
1087 // to transfer data from device to host.
1089 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1090 Token
->TransactionStatus
= EFI_SUCCESS
;
1091 Status
= ScsiDiskAsyncWriteSectors (
1099 Status
= ScsiDiskWriteSectors (
1108 gBS
->RestoreTPL (OldTpl
);
1113 Flush the Block Device.
1115 @param This Indicates a pointer to the calling context.
1116 @param Token A pointer to the token associated with the transaction.
1118 @retval EFI_SUCCESS All outstanding data was written to the device.
1119 @retval EFI_DEVICE_ERROR The device reported an error while writing back the
1121 @retval EFI_NO_MEDIA There is no media in the device.
1126 ScsiDiskFlushBlocksEx (
1127 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1128 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1132 // Signal event and return directly.
1134 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1135 Token
->TransactionStatus
= EFI_SUCCESS
;
1136 gBS
->SignalEvent (Token
->Event
);
1144 Detect Device and read out capacity ,if error occurs, parse the sense key.
1146 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1147 @param MustReadCapacity The flag about reading device capacity
1148 @param MediaChange The pointer of flag indicates if media has changed
1150 @retval EFI_DEVICE_ERROR Indicates that error occurs
1151 @retval EFI_SUCCESS Successfully to detect media
1155 ScsiDiskDetectMedia (
1156 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1157 IN BOOLEAN MustReadCapacity
,
1158 OUT BOOLEAN
*MediaChange
1162 EFI_SCSI_SENSE_DATA
*SenseData
;
1163 UINTN NumberOfSenseKeys
;
1165 BOOLEAN NeedReadCapacity
;
1168 EFI_BLOCK_IO_MEDIA OldMedia
;
1170 EFI_EVENT TimeoutEvt
;
1172 Status
= EFI_SUCCESS
;
1174 NumberOfSenseKeys
= 0;
1177 Action
= ACTION_NO_ACTION
;
1178 NeedReadCapacity
= FALSE
;
1179 *MediaChange
= FALSE
;
1182 CopyMem (&OldMedia
, ScsiDiskDevice
->BlkIo
.Media
, sizeof (OldMedia
));
1184 Status
= gBS
->CreateEvent (
1191 if (EFI_ERROR (Status
)) {
1195 Status
= gBS
->SetTimer (TimeoutEvt
, TimerRelative
, EFI_TIMER_PERIOD_SECONDS(120));
1196 if (EFI_ERROR (Status
)) {
1201 // Sending Test_Unit cmd to poll device status.
1202 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.
1203 // We limit the upper boundary to 120 seconds.
1205 while (EFI_ERROR (gBS
->CheckEvent (TimeoutEvt
))) {
1206 Status
= ScsiDiskTestUnitReady (
1212 if (!EFI_ERROR (Status
)) {
1213 Status
= DetectMediaParsingSenseKeys (
1219 if (EFI_ERROR (Status
)) {
1221 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1228 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1234 if (EFI_ERROR (Status
)) {
1239 // ACTION_NO_ACTION: need not read capacity
1240 // other action code: need read capacity
1242 if (Action
== ACTION_READ_CAPACITY
) {
1243 NeedReadCapacity
= TRUE
;
1247 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,
1248 // retrieve capacity via Read Capacity command
1250 if (NeedReadCapacity
|| MustReadCapacity
) {
1252 // retrieve media information
1254 for (Retry
= 0; Retry
< MaxRetry
; Retry
++) {
1255 Status
= ScsiDiskReadCapacity (
1261 if (!EFI_ERROR (Status
)) {
1263 // analyze sense key to action
1265 Status
= DetectMediaParsingSenseKeys (
1271 if (EFI_ERROR (Status
)) {
1273 // if Status is error, it may indicate crisis error,
1274 // so return without retry.
1277 } else if (Action
== ACTION_RETRY_COMMAND_LATER
) {
1285 if (!NeedRetry
|| (Retry
>= MaxRetry
)) {
1291 if (EFI_ERROR (Status
)) {
1296 if (ScsiDiskDevice
->BlkIo
.Media
->MediaId
!= OldMedia
.MediaId
) {
1298 // Media change information got from the device
1300 *MediaChange
= TRUE
;
1303 if (ScsiDiskDevice
->BlkIo
.Media
->ReadOnly
!= OldMedia
.ReadOnly
) {
1304 *MediaChange
= TRUE
;
1305 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1308 if (ScsiDiskDevice
->BlkIo
.Media
->BlockSize
!= OldMedia
.BlockSize
) {
1309 *MediaChange
= TRUE
;
1310 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1313 if (ScsiDiskDevice
->BlkIo
.Media
->LastBlock
!= OldMedia
.LastBlock
) {
1314 *MediaChange
= TRUE
;
1315 ScsiDiskDevice
->BlkIo
.Media
->MediaId
+= 1;
1318 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
!= OldMedia
.MediaPresent
) {
1319 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
) {
1321 // when change from no media to media present, reset the MediaId to 1.
1323 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 1;
1326 // when no media, reset the MediaId to zero.
1328 ScsiDiskDevice
->BlkIo
.Media
->MediaId
= 0;
1331 *MediaChange
= TRUE
;
1335 if (TimeoutEvt
!= NULL
) {
1336 gBS
->CloseEvent (TimeoutEvt
);
1343 Send out Inquiry command to Device.
1345 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1346 @param NeedRetry Indicates if needs try again when error happens
1348 @retval EFI_DEVICE_ERROR Indicates that error occurs
1349 @retval EFI_SUCCESS Successfully to detect media
1353 ScsiDiskInquiryDevice (
1354 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1355 OUT BOOLEAN
*NeedRetry
1358 UINT32 InquiryDataLength
;
1359 UINT8 SenseDataLength
;
1360 UINT8 HostAdapterStatus
;
1362 EFI_SCSI_SENSE_DATA
*SenseDataArray
;
1363 UINTN NumberOfSenseKeys
;
1367 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
*SupportedVpdPages
;
1368 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
*BlockLimits
;
1371 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
1372 SenseDataLength
= 0;
1374 Status
= ScsiInquiryCommand (
1375 ScsiDiskDevice
->ScsiIo
,
1381 (VOID
*) &(ScsiDiskDevice
->InquiryData
),
1386 // no need to check HostAdapterStatus and TargetStatus
1388 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
1389 ParseInquiryData (ScsiDiskDevice
);
1391 if (ScsiDiskDevice
->DeviceType
== EFI_SCSI_TYPE_DISK
) {
1393 // Check whether the device supports Block Limits VPD page (0xB0)
1395 SupportedVpdPages
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1396 if (SupportedVpdPages
== NULL
) {
1398 return EFI_DEVICE_ERROR
;
1400 ZeroMem (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1401 InquiryDataLength
= sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
);
1402 SenseDataLength
= 0;
1403 Status
= ScsiInquiryCommandEx (
1404 ScsiDiskDevice
->ScsiIo
,
1410 (VOID
*) SupportedVpdPages
,
1413 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD
1415 if (!EFI_ERROR (Status
)) {
1416 PageLength
= (SupportedVpdPages
->PageLength2
<< 8)
1417 | SupportedVpdPages
->PageLength1
;
1418 for (Index
= 0; Index
< PageLength
; Index
++) {
1419 if (SupportedVpdPages
->SupportedVpdPageList
[Index
] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
) {
1425 // Query the Block Limits VPD page
1427 if (Index
< PageLength
) {
1428 BlockLimits
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1429 if (BlockLimits
== NULL
) {
1430 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1432 return EFI_DEVICE_ERROR
;
1434 ZeroMem (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1435 InquiryDataLength
= sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
);
1436 SenseDataLength
= 0;
1437 Status
= ScsiInquiryCommandEx (
1438 ScsiDiskDevice
->ScsiIo
,
1444 (VOID
*) BlockLimits
,
1447 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD
1449 if (!EFI_ERROR (Status
)) {
1450 ScsiDiskDevice
->BlkIo
.Media
->OptimalTransferLengthGranularity
=
1451 (BlockLimits
->OptimalTransferLengthGranularity2
<< 8) |
1452 BlockLimits
->OptimalTransferLengthGranularity1
;
1455 FreeAlignedBuffer (BlockLimits
, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE
));
1459 FreeAlignedBuffer (SupportedVpdPages
, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE
));
1463 if (!EFI_ERROR (Status
)) {
1466 } else if (Status
== EFI_NOT_READY
) {
1468 return EFI_DEVICE_ERROR
;
1470 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1472 return EFI_DEVICE_ERROR
;
1475 // go ahead to check HostAdapterStatus and TargetStatus
1476 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)
1479 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1480 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1482 return EFI_DEVICE_ERROR
;
1483 } else if (Status
== EFI_DEVICE_ERROR
) {
1485 // reset the scsi channel
1487 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1489 return EFI_DEVICE_ERROR
;
1492 Status
= CheckTargetStatus (TargetStatus
);
1493 if (Status
== EFI_NOT_READY
) {
1495 // reset the scsi device
1497 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1499 return EFI_DEVICE_ERROR
;
1501 } else if (Status
== EFI_DEVICE_ERROR
) {
1503 return EFI_DEVICE_ERROR
;
1507 // if goes here, meant ScsiInquiryCommand() failed.
1508 // if ScsiDiskRequestSenseKeys() succeeds at last,
1509 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)
1512 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1513 Status
= ScsiDiskRequestSenseKeys (
1520 if (!EFI_ERROR (Status
)) {
1522 return EFI_DEVICE_ERROR
;
1526 return EFI_DEVICE_ERROR
;
1530 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1531 // set *NeedRetry = FALSE to avoid the outside caller try again.
1534 return EFI_DEVICE_ERROR
;
1540 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;
1541 When Test Unit Ready command encounters any error caused by host adapter or
1542 target, return error without retrieving Sense Keys.
1544 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1545 @param NeedRetry The pointer of flag indicates try again
1546 @param SenseDataArray The pointer of an array of sense data
1547 @param NumberOfSenseKeys The pointer of the number of sense data array
1549 @retval EFI_DEVICE_ERROR Indicates that error occurs
1550 @retval EFI_SUCCESS Successfully to test unit
1554 ScsiDiskTestUnitReady (
1555 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
1556 OUT BOOLEAN
*NeedRetry
,
1557 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1558 OUT UINTN
*NumberOfSenseKeys
1562 UINT8 SenseDataLength
;
1563 UINT8 HostAdapterStatus
;
1568 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
1569 *NumberOfSenseKeys
= 0;
1572 // Parameter 3 and 4: do not require sense data, retrieve it when needed.
1574 Status
= ScsiTestUnitReadyCommand (
1575 ScsiDiskDevice
->ScsiIo
,
1577 ScsiDiskDevice
->SenseData
,
1583 // no need to check HostAdapterStatus and TargetStatus
1585 if (Status
== EFI_NOT_READY
) {
1587 return EFI_DEVICE_ERROR
;
1589 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
1591 return EFI_DEVICE_ERROR
;
1594 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)
1597 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1598 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1600 return EFI_DEVICE_ERROR
;
1602 } else if (Status
== EFI_DEVICE_ERROR
) {
1604 // reset the scsi channel
1606 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1608 return EFI_DEVICE_ERROR
;
1611 Status
= CheckTargetStatus (TargetStatus
);
1612 if (Status
== EFI_NOT_READY
) {
1614 // reset the scsi device
1616 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1618 return EFI_DEVICE_ERROR
;
1620 } else if (Status
== EFI_DEVICE_ERROR
) {
1622 return EFI_DEVICE_ERROR
;
1625 if (SenseDataLength
!= 0) {
1626 *NumberOfSenseKeys
= SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
);
1627 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
1632 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1633 Status
= ScsiDiskRequestSenseKeys (
1640 if (!EFI_ERROR (Status
)) {
1645 return EFI_DEVICE_ERROR
;
1649 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1650 // set *NeedRetry = FALSE to avoid the outside caller try again.
1653 return EFI_DEVICE_ERROR
;
1657 Parsing Sense Keys which got from request sense command.
1659 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1660 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
1661 @param NumberOfSenseKeys The number of sense key
1662 @param Action The pointer of action which indicates what is need to do next
1664 @retval EFI_DEVICE_ERROR Indicates that error occurs
1665 @retval EFI_SUCCESS Successfully to complete the parsing
1669 DetectMediaParsingSenseKeys (
1670 OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1671 IN EFI_SCSI_SENSE_DATA
*SenseData
,
1672 IN UINTN NumberOfSenseKeys
,
1679 // Default is to read capacity, unless..
1681 *Action
= ACTION_READ_CAPACITY
;
1683 if (NumberOfSenseKeys
== 0) {
1684 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1685 *Action
= ACTION_NO_ACTION
;
1690 if (!ScsiDiskHaveSenseKey (SenseData
, NumberOfSenseKeys
)) {
1692 // No Sense Key returned from last submitted command
1694 if (ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
== TRUE
) {
1695 *Action
= ACTION_NO_ACTION
;
1700 if (ScsiDiskIsNoMedia (SenseData
, NumberOfSenseKeys
)) {
1701 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= FALSE
;
1702 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= 0;
1703 *Action
= ACTION_NO_ACTION
;
1704 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsNoMedia\n"));
1708 if (ScsiDiskIsMediaChange (SenseData
, NumberOfSenseKeys
)) {
1709 ScsiDiskDevice
->BlkIo
.Media
->MediaId
++;
1710 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaChange!\n"));
1714 if (ScsiDiskIsResetBefore (SenseData
, NumberOfSenseKeys
)) {
1715 *Action
= ACTION_RETRY_COMMAND_LATER
;
1716 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsResetBefore!\n"));
1720 if (ScsiDiskIsMediaError (SenseData
, NumberOfSenseKeys
)) {
1721 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsMediaError\n"));
1722 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1723 return EFI_DEVICE_ERROR
;
1726 if (ScsiDiskIsHardwareError (SenseData
, NumberOfSenseKeys
)) {
1727 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskIsHardwareError\n"));
1728 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1729 return EFI_DEVICE_ERROR
;
1732 if (!ScsiDiskIsDriveReady (SenseData
, NumberOfSenseKeys
, &RetryLater
)) {
1734 *Action
= ACTION_RETRY_COMMAND_LATER
;
1735 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: ScsiDiskDriveNotReady!\n"));
1738 *Action
= ACTION_NO_ACTION
;
1739 return EFI_DEVICE_ERROR
;
1742 *Action
= ACTION_RETRY_WITH_BACKOFF_ALGO
;
1743 DEBUG ((EFI_D_VERBOSE
, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData
->Sense_Key
, SenseData
->Addnl_Sense_Code
));
1749 Send read capacity command to device and get the device parameter.
1751 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
1752 @param NeedRetry The pointer of flag indicates if need a retry
1753 @param SenseDataArray The pointer of an array of sense data
1754 @param NumberOfSenseKeys The number of sense key
1756 @retval EFI_DEVICE_ERROR Indicates that error occurs
1757 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.
1761 ScsiDiskReadCapacity (
1762 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
1763 OUT BOOLEAN
*NeedRetry
,
1764 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
1765 OUT UINTN
*NumberOfSenseKeys
1768 UINT8 HostAdapterStatus
;
1770 EFI_STATUS CommandStatus
;
1774 UINT8 SenseDataLength
;
1775 UINT32 DataLength10
;
1776 UINT32 DataLength16
;
1777 EFI_SCSI_DISK_CAPACITY_DATA
*CapacityData10
;
1778 EFI_SCSI_DISK_CAPACITY_DATA16
*CapacityData16
;
1780 CapacityData10
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1781 if (CapacityData10
== NULL
) {
1783 return EFI_DEVICE_ERROR
;
1785 CapacityData16
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1786 if (CapacityData16
== NULL
) {
1787 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1789 return EFI_DEVICE_ERROR
;
1792 SenseDataLength
= 0;
1793 DataLength10
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA
);
1794 DataLength16
= sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
);
1795 ZeroMem (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1796 ZeroMem (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1798 *NumberOfSenseKeys
= 0;
1802 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,
1803 // 16 byte command should be used to access large hard disk >2TB
1805 CommandStatus
= ScsiReadCapacityCommand (
1806 ScsiDiskDevice
->ScsiIo
,
1812 (VOID
*) CapacityData10
,
1817 ScsiDiskDevice
->Cdb16Byte
= FALSE
;
1818 if ((!EFI_ERROR (CommandStatus
)) && (CapacityData10
->LastLba3
== 0xff) && (CapacityData10
->LastLba2
== 0xff) &&
1819 (CapacityData10
->LastLba1
== 0xff) && (CapacityData10
->LastLba0
== 0xff)) {
1821 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB
1823 ScsiDiskDevice
->Cdb16Byte
= TRUE
;
1825 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock
1826 // and LowestAlignedLba
1828 CommandStatus
= ScsiReadCapacity16Command (
1829 ScsiDiskDevice
->ScsiIo
,
1835 (VOID
*) CapacityData16
,
1842 // no need to check HostAdapterStatus and TargetStatus
1844 if (CommandStatus
== EFI_SUCCESS
) {
1845 GetMediaInfo (ScsiDiskDevice
, CapacityData10
, CapacityData16
);
1846 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1847 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1851 FreeAlignedBuffer (CapacityData10
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA
));
1852 FreeAlignedBuffer (CapacityData16
, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16
));
1854 if (CommandStatus
== EFI_NOT_READY
) {
1856 return EFI_DEVICE_ERROR
;
1857 } else if ((CommandStatus
== EFI_INVALID_PARAMETER
) || (CommandStatus
== EFI_UNSUPPORTED
)) {
1859 return EFI_DEVICE_ERROR
;
1863 // go ahead to check HostAdapterStatus and TargetStatus
1864 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
1867 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
1868 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
1870 return EFI_DEVICE_ERROR
;
1872 } else if (Status
== EFI_DEVICE_ERROR
) {
1874 // reset the scsi channel
1876 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
1878 return EFI_DEVICE_ERROR
;
1881 Status
= CheckTargetStatus (TargetStatus
);
1882 if (Status
== EFI_NOT_READY
) {
1884 // reset the scsi device
1886 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
1888 return EFI_DEVICE_ERROR
;
1890 } else if (Status
== EFI_DEVICE_ERROR
) {
1892 return EFI_DEVICE_ERROR
;
1896 // if goes here, meant ScsiReadCapacityCommand() failed.
1897 // if ScsiDiskRequestSenseKeys() succeeds at last,
1898 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)
1901 for (Index
= 0; Index
< MaxRetry
; Index
++) {
1903 Status
= ScsiDiskRequestSenseKeys (
1910 if (!EFI_ERROR (Status
)) {
1915 return EFI_DEVICE_ERROR
;
1919 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.
1920 // set *NeedRetry = FALSE to avoid the outside caller try again.
1923 return EFI_DEVICE_ERROR
;
1927 Check the HostAdapter status and re-interpret it in EFI_STATUS.
1929 @param HostAdapterStatus Host Adapter status
1931 @retval EFI_SUCCESS Host adapter is OK.
1932 @retval EFI_TIMEOUT Timeout.
1933 @retval EFI_NOT_READY Adapter NOT ready.
1934 @retval EFI_DEVICE_ERROR Adapter device error.
1938 CheckHostAdapterStatus (
1939 IN UINT8 HostAdapterStatus
1942 switch (HostAdapterStatus
) {
1943 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK
:
1946 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT
:
1947 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT
:
1948 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND
:
1951 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT
:
1952 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR
:
1953 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED
:
1954 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN
:
1955 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET
:
1956 return EFI_NOT_READY
;
1958 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE
:
1959 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR
:
1960 return EFI_DEVICE_ERROR
;
1969 Check the target status and re-interpret it in EFI_STATUS.
1971 @param TargetStatus Target status
1973 @retval EFI_NOT_READY Device is NOT ready.
1974 @retval EFI_DEVICE_ERROR
1980 IN UINT8 TargetStatus
1983 switch (TargetStatus
) {
1984 case EFI_EXT_SCSI_STATUS_TARGET_GOOD
:
1985 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
:
1986 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET
:
1989 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE
:
1990 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET
:
1991 case EFI_EXT_SCSI_STATUS_TARGET_BUSY
:
1992 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL
:
1993 return EFI_NOT_READY
;
1995 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT
:
1996 return EFI_DEVICE_ERROR
;
2005 Retrieve all sense keys from the device.
2007 When encountering error during the process, if retrieve sense keys before
2008 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,
2009 and NeedRetry set to FALSE; otherwize, return the proper return status.
2011 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2012 @param NeedRetry The pointer of flag indicates if need a retry
2013 @param SenseDataArray The pointer of an array of sense data
2014 @param NumberOfSenseKeys The number of sense key
2015 @param AskResetIfError The flag indicates if need reset when error occurs
2017 @retval EFI_DEVICE_ERROR Indicates that error occurs
2018 @retval EFI_SUCCESS Successfully to request sense key
2022 ScsiDiskRequestSenseKeys (
2023 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2024 OUT BOOLEAN
*NeedRetry
,
2025 OUT EFI_SCSI_SENSE_DATA
**SenseDataArray
,
2026 OUT UINTN
*NumberOfSenseKeys
,
2027 IN BOOLEAN AskResetIfError
2030 EFI_SCSI_SENSE_DATA
*PtrSenseData
;
2031 UINT8 SenseDataLength
;
2034 EFI_STATUS FallStatus
;
2035 UINT8 HostAdapterStatus
;
2038 FallStatus
= EFI_SUCCESS
;
2039 SenseDataLength
= (UINT8
) sizeof (EFI_SCSI_SENSE_DATA
);
2042 ScsiDiskDevice
->SenseData
,
2043 sizeof (EFI_SCSI_SENSE_DATA
) * (ScsiDiskDevice
->SenseDataNumber
)
2046 *NumberOfSenseKeys
= 0;
2047 *SenseDataArray
= ScsiDiskDevice
->SenseData
;
2048 Status
= EFI_SUCCESS
;
2049 PtrSenseData
= AllocateAlignedBuffer (ScsiDiskDevice
, sizeof (EFI_SCSI_SENSE_DATA
));
2050 if (PtrSenseData
== NULL
) {
2051 return EFI_DEVICE_ERROR
;
2054 for (SenseReq
= TRUE
; SenseReq
;) {
2055 ZeroMem (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2056 Status
= ScsiRequestSenseCommand (
2057 ScsiDiskDevice
->ScsiIo
,
2064 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_WARN_BUFFER_TOO_SMALL
)) {
2065 FallStatus
= EFI_SUCCESS
;
2067 } else if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2069 FallStatus
= EFI_DEVICE_ERROR
;
2071 } else if ((Status
== EFI_INVALID_PARAMETER
) || (Status
== EFI_UNSUPPORTED
)) {
2073 FallStatus
= EFI_DEVICE_ERROR
;
2075 } else if (Status
== EFI_DEVICE_ERROR
) {
2076 if (AskResetIfError
) {
2077 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2080 FallStatus
= EFI_DEVICE_ERROR
;
2083 if (EFI_ERROR (FallStatus
)) {
2084 if (*NumberOfSenseKeys
!= 0) {
2086 Status
= EFI_SUCCESS
;
2089 Status
= EFI_DEVICE_ERROR
;
2094 CopyMem (ScsiDiskDevice
->SenseData
+ *NumberOfSenseKeys
, PtrSenseData
, SenseDataLength
);
2095 (*NumberOfSenseKeys
) += 1;
2098 // no more sense key or number of sense keys exceeds predefined,
2101 if ((PtrSenseData
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) ||
2102 (*NumberOfSenseKeys
== ScsiDiskDevice
->SenseDataNumber
)) {
2108 FreeAlignedBuffer (PtrSenseData
, sizeof (EFI_SCSI_SENSE_DATA
));
2114 Get information from media read capacity command.
2116 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2117 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA
2118 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16
2123 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
,
2124 IN EFI_SCSI_DISK_CAPACITY_DATA
*Capacity10
,
2125 IN EFI_SCSI_DISK_CAPACITY_DATA16
*Capacity16
2130 if (!ScsiDiskDevice
->Cdb16Byte
) {
2131 ScsiDiskDevice
->BlkIo
.Media
->LastBlock
= (Capacity10
->LastLba3
<< 24) |
2132 (Capacity10
->LastLba2
<< 16) |
2133 (Capacity10
->LastLba1
<< 8) |
2134 Capacity10
->LastLba0
;
2136 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity10
->BlockSize3
<< 24) |
2137 (Capacity10
->BlockSize2
<< 16) |
2138 (Capacity10
->BlockSize1
<< 8) |
2139 Capacity10
->BlockSize0
;
2140 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= 0;
2141 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= 0;
2143 Ptr
= (UINT8
*)&ScsiDiskDevice
->BlkIo
.Media
->LastBlock
;
2144 *Ptr
++ = Capacity16
->LastLba0
;
2145 *Ptr
++ = Capacity16
->LastLba1
;
2146 *Ptr
++ = Capacity16
->LastLba2
;
2147 *Ptr
++ = Capacity16
->LastLba3
;
2148 *Ptr
++ = Capacity16
->LastLba4
;
2149 *Ptr
++ = Capacity16
->LastLba5
;
2150 *Ptr
++ = Capacity16
->LastLba6
;
2151 *Ptr
= Capacity16
->LastLba7
;
2153 ScsiDiskDevice
->BlkIo
.Media
->BlockSize
= (Capacity16
->BlockSize3
<< 24) |
2154 (Capacity16
->BlockSize2
<< 16) |
2155 (Capacity16
->BlockSize1
<< 8) |
2156 Capacity16
->BlockSize0
;
2158 ScsiDiskDevice
->BlkIo
.Media
->LowestAlignedLba
= (Capacity16
->LowestAlignLogic2
<< 8) |
2159 Capacity16
->LowestAlignLogic1
;
2160 ScsiDiskDevice
->BlkIo
.Media
->LogicalBlocksPerPhysicalBlock
= (1 << Capacity16
->LogicPerPhysical
);
2163 ScsiDiskDevice
->BlkIo
.Media
->MediaPresent
= TRUE
;
2169 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2174 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
2177 ScsiDiskDevice
->FixedDevice
= (BOOLEAN
) ((ScsiDiskDevice
->InquiryData
.Rmb
== 1) ? 0 : 1);
2178 ScsiDiskDevice
->BlkIoMedia
.RemovableMedia
= (BOOLEAN
) (!ScsiDiskDevice
->FixedDevice
);
2182 Read sector from SCSI Disk.
2184 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2185 @param Buffer The buffer to fill in the read out data
2186 @param Lba Logic block address
2187 @param NumberOfBlocks The number of blocks to read
2189 @retval EFI_DEVICE_ERROR Indicates a device error.
2190 @retval EFI_SUCCESS Operation is successful.
2194 ScsiDiskReadSectors (
2195 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2198 IN UINTN NumberOfBlocks
2201 UINTN BlocksRemaining
;
2207 UINT32 NextSectorCount
;
2214 Status
= EFI_SUCCESS
;
2216 BlocksRemaining
= NumberOfBlocks
;
2217 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2220 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2222 if (!ScsiDiskDevice
->Cdb16Byte
) {
2225 MaxBlock
= 0xFFFFFFFF;
2230 while (BlocksRemaining
> 0) {
2232 if (BlocksRemaining
<= MaxBlock
) {
2233 if (!ScsiDiskDevice
->Cdb16Byte
) {
2234 SectorCount
= (UINT16
) BlocksRemaining
;
2236 SectorCount
= (UINT32
) BlocksRemaining
;
2239 SectorCount
= MaxBlock
;
2242 ByteCount
= SectorCount
* BlockSize
;
2244 // |------------------------|-----------------|------------------|-----------------|
2245 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2246 // |------------------------|-----------------|------------------|-----------------|
2247 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2248 // |------------------------|-----------------|------------------|-----------------|
2249 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2250 // |------------------------|-----------------|------------------|-----------------|
2251 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2252 // |------------------------|-----------------|------------------|-----------------|
2253 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2254 // |------------------------|-----------------|------------------|-----------------|
2255 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2256 // |------------------------|-----------------|------------------|-----------------|
2257 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2258 // |------------------------|-----------------|------------------|-----------------|
2259 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2260 // |------------------------|-----------------|------------------|-----------------|
2261 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2262 // |------------------------|-----------------|------------------|-----------------|
2263 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2264 // |------------------------|-----------------|------------------|-----------------|
2265 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2266 // |------------------------|-----------------|------------------|-----------------|
2268 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2269 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2270 // From the above table, we could know 2.1Mbytes per second is lowest one.
2271 // The timout value is rounded up to nearest integar and here an additional 30s is added
2272 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2273 // commands in the Standby/Idle mode.
2275 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2278 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2279 if (!ScsiDiskDevice
->Cdb16Byte
) {
2280 Status
= ScsiDiskRead10 (
2290 Status
= ScsiDiskRead16 (
2300 if (!EFI_ERROR (Status
)) {
2305 return EFI_DEVICE_ERROR
;
2309 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
2310 // lowered ByteCount on output, we must make sure that we lower
2311 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2312 // it is invalid to request more sectors in the CDB than the entire
2313 // transfer (ie. ByteCount) can carry.
2315 // In addition, ByteCount is only expected to go down, or stay unchaged.
2316 // Therefore we don't need to update Timeout: the original timeout should
2317 // accommodate shorter transfers too.
2319 NextSectorCount
= ByteCount
/ BlockSize
;
2320 if (NextSectorCount
< SectorCount
) {
2321 SectorCount
= NextSectorCount
;
2323 // Account for any rounding down.
2325 ByteCount
= SectorCount
* BlockSize
;
2329 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2330 return EFI_DEVICE_ERROR
;
2334 // actual transferred sectors
2336 SectorCount
= ByteCount
/ BlockSize
;
2339 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2340 BlocksRemaining
-= SectorCount
;
2347 Write sector to SCSI Disk.
2349 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
2350 @param Buffer The buffer of data to be written into SCSI Disk
2351 @param Lba Logic block address
2352 @param NumberOfBlocks The number of blocks to read
2354 @retval EFI_DEVICE_ERROR Indicates a device error.
2355 @retval EFI_SUCCESS Operation is successful.
2359 ScsiDiskWriteSectors (
2360 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2363 IN UINTN NumberOfBlocks
2366 UINTN BlocksRemaining
;
2372 UINT32 NextSectorCount
;
2379 Status
= EFI_SUCCESS
;
2381 BlocksRemaining
= NumberOfBlocks
;
2382 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2385 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command
2387 if (!ScsiDiskDevice
->Cdb16Byte
) {
2390 MaxBlock
= 0xFFFFFFFF;
2395 while (BlocksRemaining
> 0) {
2397 if (BlocksRemaining
<= MaxBlock
) {
2398 if (!ScsiDiskDevice
->Cdb16Byte
) {
2399 SectorCount
= (UINT16
) BlocksRemaining
;
2401 SectorCount
= (UINT32
) BlocksRemaining
;
2404 SectorCount
= MaxBlock
;
2407 ByteCount
= SectorCount
* BlockSize
;
2409 // |------------------------|-----------------|------------------|-----------------|
2410 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2411 // |------------------------|-----------------|------------------|-----------------|
2412 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2413 // |------------------------|-----------------|------------------|-----------------|
2414 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2415 // |------------------------|-----------------|------------------|-----------------|
2416 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2417 // |------------------------|-----------------|------------------|-----------------|
2418 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2419 // |------------------------|-----------------|------------------|-----------------|
2420 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2421 // |------------------------|-----------------|------------------|-----------------|
2422 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2423 // |------------------------|-----------------|------------------|-----------------|
2424 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2425 // |------------------------|-----------------|------------------|-----------------|
2426 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2427 // |------------------------|-----------------|------------------|-----------------|
2428 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2429 // |------------------------|-----------------|------------------|-----------------|
2430 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2431 // |------------------------|-----------------|------------------|-----------------|
2433 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use
2434 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.
2435 // From the above table, we could know 2.1Mbytes per second is lowest one.
2436 // The timout value is rounded up to nearest integar and here an additional 30s is added
2437 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond
2438 // commands in the Standby/Idle mode.
2440 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2442 for (Index
= 0; Index
< MaxRetry
; Index
++) {
2443 if (!ScsiDiskDevice
->Cdb16Byte
) {
2444 Status
= ScsiDiskWrite10 (
2454 Status
= ScsiDiskWrite16 (
2464 if (!EFI_ERROR (Status
)) {
2469 return EFI_DEVICE_ERROR
;
2473 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
2474 // has lowered ByteCount on output, we must make sure that we lower
2475 // SectorCount accordingly. SectorCount will be encoded in the CDB, and
2476 // it is invalid to request more sectors in the CDB than the entire
2477 // transfer (ie. ByteCount) can carry.
2479 // In addition, ByteCount is only expected to go down, or stay unchaged.
2480 // Therefore we don't need to update Timeout: the original timeout should
2481 // accommodate shorter transfers too.
2483 NextSectorCount
= ByteCount
/ BlockSize
;
2484 if (NextSectorCount
< SectorCount
) {
2485 SectorCount
= NextSectorCount
;
2487 // Account for any rounding down.
2489 ByteCount
= SectorCount
* BlockSize
;
2493 if ((Index
== MaxRetry
) && (Status
!= EFI_SUCCESS
)) {
2494 return EFI_DEVICE_ERROR
;
2497 // actual transferred sectors
2499 SectorCount
= ByteCount
/ BlockSize
;
2502 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2503 BlocksRemaining
-= SectorCount
;
2510 Asynchronously read sector from SCSI Disk.
2512 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2513 @param Buffer The buffer to fill in the read out data.
2514 @param Lba Logic block address.
2515 @param NumberOfBlocks The number of blocks to read.
2516 @param Token A pointer to the token associated with the
2517 non-blocking read request.
2519 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.
2520 @retval EFI_DEVICE_ERROR Indicates a device error.
2521 @retval EFI_SUCCESS Operation is successful.
2525 ScsiDiskAsyncReadSectors (
2526 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2529 IN UINTN NumberOfBlocks
,
2530 IN EFI_BLOCK_IO2_TOKEN
*Token
2533 UINTN BlocksRemaining
;
2540 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
2543 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
2544 return EFI_INVALID_PARAMETER
;
2547 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
2548 if (BlkIo2Req
== NULL
) {
2549 return EFI_OUT_OF_RESOURCES
;
2552 BlkIo2Req
->Token
= Token
;
2553 InsertTailList (&ScsiDiskDevice
->BlkIo2Queue
, &BlkIo2Req
->Link
);
2554 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
2556 Status
= EFI_SUCCESS
;
2558 BlocksRemaining
= NumberOfBlocks
;
2559 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2562 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2565 if (!ScsiDiskDevice
->Cdb16Byte
) {
2568 MaxBlock
= 0xFFFFFFFF;
2573 while (BlocksRemaining
> 0) {
2575 if (BlocksRemaining
<= MaxBlock
) {
2576 if (!ScsiDiskDevice
->Cdb16Byte
) {
2577 SectorCount
= (UINT16
) BlocksRemaining
;
2579 SectorCount
= (UINT32
) BlocksRemaining
;
2582 SectorCount
= MaxBlock
;
2585 ByteCount
= SectorCount
* BlockSize
;
2587 // |------------------------|-----------------|------------------|-----------------|
2588 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2589 // |------------------------|-----------------|------------------|-----------------|
2590 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2591 // |------------------------|-----------------|------------------|-----------------|
2592 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2593 // |------------------------|-----------------|------------------|-----------------|
2594 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2595 // |------------------------|-----------------|------------------|-----------------|
2596 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2597 // |------------------------|-----------------|------------------|-----------------|
2598 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2599 // |------------------------|-----------------|------------------|-----------------|
2600 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2601 // |------------------------|-----------------|------------------|-----------------|
2602 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2603 // |------------------------|-----------------|------------------|-----------------|
2604 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2605 // |------------------------|-----------------|------------------|-----------------|
2606 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2607 // |------------------------|-----------------|------------------|-----------------|
2608 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2609 // |------------------------|-----------------|------------------|-----------------|
2611 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2612 // we have to use the lowest transfer rate to calculate the possible
2613 // maximum timeout value for each operation.
2614 // From the above table, we could know 2.1Mbytes per second is lowest one.
2615 // The timout value is rounded up to nearest integar and here an additional
2616 // 30s is added to follow ATA spec in which it mentioned that the device
2617 // may take up to 30s to respond commands in the Standby/Idle mode.
2619 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2621 if (!ScsiDiskDevice
->Cdb16Byte
) {
2622 Status
= ScsiDiskAsyncRead10 (
2633 Status
= ScsiDiskAsyncRead16 (
2644 if (EFI_ERROR (Status
)) {
2646 // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI
2647 // command fails. Otherwise, it will be freed in the callback function
2648 // ScsiDiskNotify().
2650 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2651 RemoveEntryList (&BlkIo2Req
->Link
);
2652 FreePool (BlkIo2Req
);
2654 return EFI_DEVICE_ERROR
;
2658 // Sectors submitted for transfer
2660 SectorCount
= ByteCount
/ BlockSize
;
2663 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2664 BlocksRemaining
-= SectorCount
;
2671 Asynchronously write sector to SCSI Disk.
2673 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
2674 @param Buffer The buffer of data to be written into SCSI Disk.
2675 @param Lba Logic block address.
2676 @param NumberOfBlocks The number of blocks to read.
2677 @param Token A pointer to the token associated with the
2678 non-blocking read request.
2680 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL
2681 @retval EFI_DEVICE_ERROR Indicates a device error.
2682 @retval EFI_SUCCESS Operation is successful.
2686 ScsiDiskAsyncWriteSectors (
2687 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2690 IN UINTN NumberOfBlocks
,
2691 IN EFI_BLOCK_IO2_TOKEN
*Token
2694 UINTN BlocksRemaining
;
2701 SCSI_BLKIO2_REQUEST
*BlkIo2Req
;
2704 if ((Token
== NULL
) || (Token
->Event
== NULL
)) {
2705 return EFI_INVALID_PARAMETER
;
2708 BlkIo2Req
= AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST
));
2709 if (BlkIo2Req
== NULL
) {
2710 return EFI_OUT_OF_RESOURCES
;
2713 BlkIo2Req
->Token
= Token
;
2714 InsertTailList (&ScsiDiskDevice
->BlkIo2Queue
, &BlkIo2Req
->Link
);
2715 InitializeListHead (&BlkIo2Req
->ScsiRWQueue
);
2717 Status
= EFI_SUCCESS
;
2719 BlocksRemaining
= NumberOfBlocks
;
2720 BlockSize
= ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2723 // Limit the data bytes that can be transferred by one Read(10) or Read(16)
2726 if (!ScsiDiskDevice
->Cdb16Byte
) {
2729 MaxBlock
= 0xFFFFFFFF;
2734 while (BlocksRemaining
> 0) {
2736 if (BlocksRemaining
<= MaxBlock
) {
2737 if (!ScsiDiskDevice
->Cdb16Byte
) {
2738 SectorCount
= (UINT16
) BlocksRemaining
;
2740 SectorCount
= (UINT32
) BlocksRemaining
;
2743 SectorCount
= MaxBlock
;
2746 ByteCount
= SectorCount
* BlockSize
;
2748 // |------------------------|-----------------|------------------|-----------------|
2749 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |
2750 // |------------------------|-----------------|------------------|-----------------|
2751 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |
2752 // |------------------------|-----------------|------------------|-----------------|
2753 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |
2754 // |------------------------|-----------------|------------------|-----------------|
2755 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |
2756 // |------------------------|-----------------|------------------|-----------------|
2757 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |
2758 // |------------------------|-----------------|------------------|-----------------|
2759 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |
2760 // |------------------------|-----------------|------------------|-----------------|
2761 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |
2762 // |------------------------|-----------------|------------------|-----------------|
2763 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |
2764 // |------------------------|-----------------|------------------|-----------------|
2765 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |
2766 // |------------------------|-----------------|------------------|-----------------|
2767 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |
2768 // |------------------------|-----------------|------------------|-----------------|
2769 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |
2770 // |------------------------|-----------------|------------------|-----------------|
2772 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,
2773 // we have to use the lowest transfer rate to calculate the possible
2774 // maximum timeout value for each operation.
2775 // From the above table, we could know 2.1Mbytes per second is lowest one.
2776 // The timout value is rounded up to nearest integar and here an additional
2777 // 30s is added to follow ATA spec in which it mentioned that the device
2778 // may take up to 30s to respond commands in the Standby/Idle mode.
2780 Timeout
= EFI_TIMER_PERIOD_SECONDS (ByteCount
/ 2100000 + 31);
2782 if (!ScsiDiskDevice
->Cdb16Byte
) {
2783 Status
= ScsiDiskAsyncWrite10 (
2794 Status
= ScsiDiskAsyncWrite16 (
2805 if (EFI_ERROR (Status
)) {
2807 // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI
2808 // command fails. Otherwise, it will be freed in the callback function
2809 // ScsiDiskNotify().
2811 if (IsListEmpty (&BlkIo2Req
->ScsiRWQueue
)) {
2812 RemoveEntryList (&BlkIo2Req
->Link
);
2813 FreePool (BlkIo2Req
);
2815 return EFI_DEVICE_ERROR
;
2819 // Sectors submitted for transfer
2821 SectorCount
= ByteCount
/ BlockSize
;
2824 PtrBuffer
= PtrBuffer
+ SectorCount
* BlockSize
;
2825 BlocksRemaining
-= SectorCount
;
2833 Submit Read(10) command.
2835 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2836 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2837 @param Timeout The time to complete the command
2838 @param DataBuffer The buffer to fill with the read out data
2839 @param DataLength The length of buffer
2840 @param StartLba The start logic block address
2841 @param SectorCount The number of blocks to read
2843 @return EFI_STATUS is returned by calling ScsiRead10Command().
2847 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2848 OUT BOOLEAN
*NeedRetry
,
2850 OUT UINT8
*DataBuffer
,
2851 IN OUT UINT32
*DataLength
,
2853 IN UINT32 SectorCount
2856 UINT8 SenseDataLength
;
2858 EFI_STATUS ReturnStatus
;
2859 UINT8 HostAdapterStatus
;
2864 // Implement a backoff algorithem to resolve some compatibility issues that
2865 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2866 // big data in a single operation.
2867 // This algorithem will at first try to execute original request. If the request fails
2868 // with media error sense data or else, it will reduce the transfer length to half and
2869 // try again till the operation succeeds or fails with one sector transfer length.
2873 Action
= ACTION_NO_ACTION
;
2874 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
2875 ReturnStatus
= ScsiRead10Command (
2876 ScsiDiskDevice
->ScsiIo
,
2878 ScsiDiskDevice
->SenseData
,
2888 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
2890 return EFI_DEVICE_ERROR
;
2891 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
2893 return ReturnStatus
;
2897 // go ahead to check HostAdapterStatus and TargetStatus
2898 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
2900 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
2901 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
2903 return EFI_DEVICE_ERROR
;
2904 } else if (Status
== EFI_DEVICE_ERROR
) {
2906 // reset the scsi channel
2908 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
2910 return EFI_DEVICE_ERROR
;
2913 Status
= CheckTargetStatus (TargetStatus
);
2914 if (Status
== EFI_NOT_READY
) {
2916 // reset the scsi device
2918 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
2920 return EFI_DEVICE_ERROR
;
2921 } else if (Status
== EFI_DEVICE_ERROR
) {
2923 return EFI_DEVICE_ERROR
;
2926 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
2927 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead10: Check Condition happened!\n"));
2928 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
2929 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
2931 return EFI_DEVICE_ERROR
;
2932 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
2933 if (SectorCount
<= 1) {
2935 // Jump out if the operation still fails with one sector transfer length.
2938 return EFI_DEVICE_ERROR
;
2941 // Try again with half length if the sense data shows we need to retry.
2944 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
2948 return EFI_DEVICE_ERROR
;
2952 return ReturnStatus
;
2957 Submit Write(10) Command.
2959 @param ScsiDiskDevice The pointer of ScsiDiskDevice
2960 @param NeedRetry The pointer of flag indicates if needs retry if error happens
2961 @param Timeout The time to complete the command
2962 @param DataBuffer The buffer to fill with the read out data
2963 @param DataLength The length of buffer
2964 @param StartLba The start logic block address
2965 @param SectorCount The number of blocks to write
2967 @return EFI_STATUS is returned by calling ScsiWrite10Command().
2972 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
2973 OUT BOOLEAN
*NeedRetry
,
2975 IN UINT8
*DataBuffer
,
2976 IN OUT UINT32
*DataLength
,
2978 IN UINT32 SectorCount
2982 EFI_STATUS ReturnStatus
;
2983 UINT8 SenseDataLength
;
2984 UINT8 HostAdapterStatus
;
2989 // Implement a backoff algorithem to resolve some compatibility issues that
2990 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
2991 // big data in a single operation.
2992 // This algorithem will at first try to execute original request. If the request fails
2993 // with media error sense data or else, it will reduce the transfer length to half and
2994 // try again till the operation succeeds or fails with one sector transfer length.
2998 Action
= ACTION_NO_ACTION
;
2999 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3000 ReturnStatus
= ScsiWrite10Command (
3001 ScsiDiskDevice
->ScsiIo
,
3003 ScsiDiskDevice
->SenseData
,
3012 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3014 return EFI_DEVICE_ERROR
;
3015 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3017 return ReturnStatus
;
3021 // go ahead to check HostAdapterStatus and TargetStatus
3022 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3024 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3025 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3027 return EFI_DEVICE_ERROR
;
3028 } else if (Status
== EFI_DEVICE_ERROR
) {
3030 // reset the scsi channel
3032 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3034 return EFI_DEVICE_ERROR
;
3037 Status
= CheckTargetStatus (TargetStatus
);
3038 if (Status
== EFI_NOT_READY
) {
3040 // reset the scsi device
3042 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3044 return EFI_DEVICE_ERROR
;
3045 } else if (Status
== EFI_DEVICE_ERROR
) {
3047 return EFI_DEVICE_ERROR
;
3050 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3051 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite10: Check Condition happened!\n"));
3052 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3053 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3055 return EFI_DEVICE_ERROR
;
3056 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3057 if (SectorCount
<= 1) {
3059 // Jump out if the operation still fails with one sector transfer length.
3062 return EFI_DEVICE_ERROR
;
3065 // Try again with half length if the sense data shows we need to retry.
3068 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3072 return EFI_DEVICE_ERROR
;
3076 return ReturnStatus
;
3081 Submit Read(16) command.
3083 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3084 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3085 @param Timeout The time to complete the command
3086 @param DataBuffer The buffer to fill with the read out data
3087 @param DataLength The length of buffer
3088 @param StartLba The start logic block address
3089 @param SectorCount The number of blocks to read
3091 @return EFI_STATUS is returned by calling ScsiRead16Command().
3095 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3096 OUT BOOLEAN
*NeedRetry
,
3098 OUT UINT8
*DataBuffer
,
3099 IN OUT UINT32
*DataLength
,
3101 IN UINT32 SectorCount
3104 UINT8 SenseDataLength
;
3106 EFI_STATUS ReturnStatus
;
3107 UINT8 HostAdapterStatus
;
3112 // Implement a backoff algorithem to resolve some compatibility issues that
3113 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3114 // big data in a single operation.
3115 // This algorithem will at first try to execute original request. If the request fails
3116 // with media error sense data or else, it will reduce the transfer length to half and
3117 // try again till the operation succeeds or fails with one sector transfer length.
3121 Action
= ACTION_NO_ACTION
;
3122 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3123 ReturnStatus
= ScsiRead16Command (
3124 ScsiDiskDevice
->ScsiIo
,
3126 ScsiDiskDevice
->SenseData
,
3135 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3137 return EFI_DEVICE_ERROR
;
3138 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3140 return ReturnStatus
;
3144 // go ahead to check HostAdapterStatus and TargetStatus
3145 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3147 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3148 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3150 return EFI_DEVICE_ERROR
;
3151 } else if (Status
== EFI_DEVICE_ERROR
) {
3153 // reset the scsi channel
3155 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3157 return EFI_DEVICE_ERROR
;
3160 Status
= CheckTargetStatus (TargetStatus
);
3161 if (Status
== EFI_NOT_READY
) {
3163 // reset the scsi device
3165 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3167 return EFI_DEVICE_ERROR
;
3168 } else if (Status
== EFI_DEVICE_ERROR
) {
3170 return EFI_DEVICE_ERROR
;
3173 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3174 DEBUG ((EFI_D_ERROR
, "ScsiDiskRead16: Check Condition happened!\n"));
3175 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3176 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3178 return EFI_DEVICE_ERROR
;
3179 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3180 if (SectorCount
<= 1) {
3182 // Jump out if the operation still fails with one sector transfer length.
3185 return EFI_DEVICE_ERROR
;
3188 // Try again with half length if the sense data shows we need to retry.
3191 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3195 return EFI_DEVICE_ERROR
;
3199 return ReturnStatus
;
3204 Submit Write(16) Command.
3206 @param ScsiDiskDevice The pointer of ScsiDiskDevice
3207 @param NeedRetry The pointer of flag indicates if needs retry if error happens
3208 @param Timeout The time to complete the command
3209 @param DataBuffer The buffer to fill with the read out data
3210 @param DataLength The length of buffer
3211 @param StartLba The start logic block address
3212 @param SectorCount The number of blocks to write
3214 @return EFI_STATUS is returned by calling ScsiWrite16Command().
3219 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3220 OUT BOOLEAN
*NeedRetry
,
3222 IN UINT8
*DataBuffer
,
3223 IN OUT UINT32
*DataLength
,
3225 IN UINT32 SectorCount
3229 EFI_STATUS ReturnStatus
;
3230 UINT8 SenseDataLength
;
3231 UINT8 HostAdapterStatus
;
3236 // Implement a backoff algorithem to resolve some compatibility issues that
3237 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing
3238 // big data in a single operation.
3239 // This algorithem will at first try to execute original request. If the request fails
3240 // with media error sense data or else, it will reduce the transfer length to half and
3241 // try again till the operation succeeds or fails with one sector transfer length.
3245 Action
= ACTION_NO_ACTION
;
3246 SenseDataLength
= (UINT8
) (ScsiDiskDevice
->SenseDataNumber
* sizeof (EFI_SCSI_SENSE_DATA
));
3247 ReturnStatus
= ScsiWrite16Command (
3248 ScsiDiskDevice
->ScsiIo
,
3250 ScsiDiskDevice
->SenseData
,
3259 if (ReturnStatus
== EFI_NOT_READY
|| ReturnStatus
== EFI_BAD_BUFFER_SIZE
) {
3261 return EFI_DEVICE_ERROR
;
3262 } else if ((ReturnStatus
== EFI_INVALID_PARAMETER
) || (ReturnStatus
== EFI_UNSUPPORTED
)) {
3264 return ReturnStatus
;
3268 // go ahead to check HostAdapterStatus and TargetStatus
3269 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3271 Status
= CheckHostAdapterStatus (HostAdapterStatus
);
3272 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3274 return EFI_DEVICE_ERROR
;
3275 } else if (Status
== EFI_DEVICE_ERROR
) {
3277 // reset the scsi channel
3279 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3281 return EFI_DEVICE_ERROR
;
3284 Status
= CheckTargetStatus (TargetStatus
);
3285 if (Status
== EFI_NOT_READY
) {
3287 // reset the scsi device
3289 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3291 return EFI_DEVICE_ERROR
;
3292 } else if (Status
== EFI_DEVICE_ERROR
) {
3294 return EFI_DEVICE_ERROR
;
3297 if ((TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) || (EFI_ERROR (ReturnStatus
))) {
3298 DEBUG ((EFI_D_ERROR
, "ScsiDiskWrite16: Check Condition happened!\n"));
3299 Status
= DetectMediaParsingSenseKeys (ScsiDiskDevice
, ScsiDiskDevice
->SenseData
, SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
), &Action
);
3300 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3302 return EFI_DEVICE_ERROR
;
3303 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3304 if (SectorCount
<= 1) {
3306 // Jump out if the operation still fails with one sector transfer length.
3309 return EFI_DEVICE_ERROR
;
3312 // Try again with half length if the sense data shows we need to retry.
3315 *DataLength
= SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3319 return EFI_DEVICE_ERROR
;
3323 return ReturnStatus
;
3328 Internal helper notify function in which determine whether retry of a SCSI
3329 Read/Write command is needed and signal the event passed from Block I/O(2) if
3330 the SCSI I/O operation completes.
3332 @param Event The instance of EFI_EVENT.
3333 @param Context The parameter passed in.
3344 SCSI_ASYNC_RW_REQUEST
*Request
;
3345 SCSI_DISK_DEV
*ScsiDiskDevice
;
3346 EFI_BLOCK_IO2_TOKEN
*Token
;
3348 UINT32 OldDataLength
;
3349 UINT32 OldSectorCount
;
3352 gBS
->CloseEvent (Event
);
3354 Request
= (SCSI_ASYNC_RW_REQUEST
*) Context
;
3355 ScsiDiskDevice
= Request
->ScsiDiskDevice
;
3356 Token
= Request
->BlkIo2Req
->Token
;
3357 OldDataLength
= Request
->DataLength
;
3358 OldSectorCount
= Request
->SectorCount
;
3362 // If previous sub-tasks already fails, no need to process this sub-task.
3364 if (Token
->TransactionStatus
!= EFI_SUCCESS
) {
3369 // Check HostAdapterStatus and TargetStatus
3370 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)
3372 Status
= CheckHostAdapterStatus (Request
->HostAdapterStatus
);
3373 if ((Status
== EFI_TIMEOUT
) || (Status
== EFI_NOT_READY
)) {
3374 if (++Request
->TimesRetry
> MaxRetry
) {
3375 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3380 } else if (Status
== EFI_DEVICE_ERROR
) {
3382 // reset the scsi channel
3384 ScsiDiskDevice
->ScsiIo
->ResetBus (ScsiDiskDevice
->ScsiIo
);
3385 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3389 Status
= CheckTargetStatus (Request
->TargetStatus
);
3390 if (Status
== EFI_NOT_READY
) {
3392 // reset the scsi device
3394 ScsiDiskDevice
->ScsiIo
->ResetDevice (ScsiDiskDevice
->ScsiIo
);
3395 if (++Request
->TimesRetry
> MaxRetry
) {
3396 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3401 } else if (Status
== EFI_DEVICE_ERROR
) {
3402 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3406 if (Request
->TargetStatus
== EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION
) {
3407 DEBUG ((EFI_D_ERROR
, "ScsiDiskNotify: Check Condition happened!\n"));
3409 Status
= DetectMediaParsingSenseKeys (
3412 Request
->SenseDataLength
/ sizeof (EFI_SCSI_SENSE_DATA
),
3415 if (Action
== ACTION_RETRY_COMMAND_LATER
) {
3416 if (++Request
->TimesRetry
> MaxRetry
) {
3417 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3422 } else if (Action
== ACTION_RETRY_WITH_BACKOFF_ALGO
) {
3423 if (Request
->SectorCount
<= 1) {
3425 // Jump out if the operation still fails with one sector transfer
3428 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3432 // Try again with two half length request if the sense data shows we need
3435 Request
->SectorCount
>>= 1;
3436 Request
->DataLength
= Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
;
3437 Request
->TimesRetry
= 0;
3441 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3447 // This sub-task succeeds, no need to retry.
3452 if (Request
->InBuffer
!= NULL
) {
3454 // SCSI read command
3456 if (!ScsiDiskDevice
->Cdb16Byte
) {
3457 Status
= ScsiDiskAsyncRead10 (
3461 Request
->DataLength
,
3462 (UINT32
) Request
->StartLba
,
3463 Request
->SectorCount
,
3468 Status
= ScsiDiskAsyncRead16 (
3472 Request
->DataLength
,
3474 Request
->SectorCount
,
3480 if (EFI_ERROR (Status
)) {
3481 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3483 } else if (OldSectorCount
!= Request
->SectorCount
) {
3485 // Original sub-task will be split into two new sub-tasks with smaller
3488 if (!ScsiDiskDevice
->Cdb16Byte
) {
3489 Status
= ScsiDiskAsyncRead10 (
3492 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3493 OldDataLength
- Request
->DataLength
,
3494 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
3495 OldSectorCount
- Request
->SectorCount
,
3500 Status
= ScsiDiskAsyncRead16 (
3503 Request
->InBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3504 OldDataLength
- Request
->DataLength
,
3505 Request
->StartLba
+ Request
->SectorCount
,
3506 OldSectorCount
- Request
->SectorCount
,
3511 if (EFI_ERROR (Status
)) {
3512 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3518 // SCSI write command
3520 if (!ScsiDiskDevice
->Cdb16Byte
) {
3521 Status
= ScsiDiskAsyncWrite10 (
3525 Request
->DataLength
,
3526 (UINT32
) Request
->StartLba
,
3527 Request
->SectorCount
,
3532 Status
= ScsiDiskAsyncWrite16 (
3536 Request
->DataLength
,
3538 Request
->SectorCount
,
3544 if (EFI_ERROR (Status
)) {
3545 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3547 } else if (OldSectorCount
!= Request
->SectorCount
) {
3549 // Original sub-task will be split into two new sub-tasks with smaller
3552 if (!ScsiDiskDevice
->Cdb16Byte
) {
3553 Status
= ScsiDiskAsyncWrite10 (
3556 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3557 OldDataLength
- Request
->DataLength
,
3558 (UINT32
) Request
->StartLba
+ Request
->SectorCount
,
3559 OldSectorCount
- Request
->SectorCount
,
3564 Status
= ScsiDiskAsyncWrite16 (
3567 Request
->OutBuffer
+ Request
->SectorCount
* ScsiDiskDevice
->BlkIo
.Media
->BlockSize
,
3568 OldDataLength
- Request
->DataLength
,
3569 Request
->StartLba
+ Request
->SectorCount
,
3570 OldSectorCount
- Request
->SectorCount
,
3575 if (EFI_ERROR (Status
)) {
3576 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
3583 RemoveEntryList (&Request
->Link
);
3584 if (IsListEmpty (&Request
->BlkIo2Req
->ScsiRWQueue
)) {
3586 // The last SCSI R/W command of a BlockIo2 request completes
3588 RemoveEntryList (&Request
->BlkIo2Req
->Link
);
3589 FreePool (Request
->BlkIo2Req
); // Should be freed only once
3590 gBS
->SignalEvent (Token
->Event
);
3593 FreePool (Request
->SenseData
);
3599 Submit Async Read(10) command.
3601 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3602 @param Timeout The time to complete the command.
3603 @param DataBuffer The buffer to fill with the read out data.
3604 @param DataLength The length of buffer.
3605 @param StartLba The start logic block address.
3606 @param SectorCount The number of blocks to read.
3607 @param BlkIo2Req The upstream BlockIo2 request.
3608 @param Token The pointer to the token associated with the
3609 non-blocking read request.
3611 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3613 @return others Status returned by calling
3614 ScsiRead10CommandEx().
3618 ScsiDiskAsyncRead10 (
3619 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3621 OUT UINT8
*DataBuffer
,
3622 IN UINT32 DataLength
,
3624 IN UINT32 SectorCount
,
3625 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3626 IN EFI_BLOCK_IO2_TOKEN
*Token
3630 SCSI_ASYNC_RW_REQUEST
*Request
;
3631 EFI_EVENT AsyncIoEvent
;
3633 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3634 if (Request
== NULL
) {
3635 return EFI_OUT_OF_RESOURCES
;
3637 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3639 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3640 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3641 if (Request
->SenseData
== NULL
) {
3642 Status
= EFI_OUT_OF_RESOURCES
;
3646 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3647 Request
->Timeout
= Timeout
;
3648 Request
->InBuffer
= DataBuffer
;
3649 Request
->DataLength
= DataLength
;
3650 Request
->StartLba
= StartLba
;
3651 Request
->SectorCount
= SectorCount
;
3652 Request
->BlkIo2Req
= BlkIo2Req
;
3657 Status
= gBS
->CreateEvent (
3664 if (EFI_ERROR(Status
)) {
3668 Status
= ScsiRead10CommandEx (
3669 ScsiDiskDevice
->ScsiIo
,
3672 &Request
->SenseDataLength
,
3673 &Request
->HostAdapterStatus
,
3674 &Request
->TargetStatus
,
3676 &Request
->DataLength
,
3677 (UINT32
) Request
->StartLba
,
3678 Request
->SectorCount
,
3681 if (EFI_ERROR(Status
)) {
3688 if (Request
!= NULL
) {
3689 if (Request
->SenseData
!= NULL
) {
3690 FreePool (Request
->SenseData
);
3693 RemoveEntryList (&Request
->Link
);
3702 Submit Async Write(10) command.
3704 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3705 @param Timeout The time to complete the command.
3706 @param DataBuffer The buffer contains the data to write.
3707 @param DataLength The length of buffer.
3708 @param StartLba The start logic block address.
3709 @param SectorCount The number of blocks to write.
3710 @param BlkIo2Req The upstream BlockIo2 request.
3711 @param Token The pointer to the token associated with the
3712 non-blocking read request.
3714 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3716 @return others Status returned by calling
3717 ScsiWrite10CommandEx().
3721 ScsiDiskAsyncWrite10 (
3722 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3724 IN UINT8
*DataBuffer
,
3725 IN UINT32 DataLength
,
3727 IN UINT32 SectorCount
,
3728 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3729 IN EFI_BLOCK_IO2_TOKEN
*Token
3733 SCSI_ASYNC_RW_REQUEST
*Request
;
3734 EFI_EVENT AsyncIoEvent
;
3736 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3737 if (Request
== NULL
) {
3738 return EFI_OUT_OF_RESOURCES
;
3740 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3742 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3743 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3744 if (Request
->SenseData
== NULL
) {
3745 Status
= EFI_OUT_OF_RESOURCES
;
3749 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3750 Request
->Timeout
= Timeout
;
3751 Request
->OutBuffer
= DataBuffer
;
3752 Request
->DataLength
= DataLength
;
3753 Request
->StartLba
= StartLba
;
3754 Request
->SectorCount
= SectorCount
;
3755 Request
->BlkIo2Req
= BlkIo2Req
;
3760 Status
= gBS
->CreateEvent (
3767 if (EFI_ERROR(Status
)) {
3771 Status
= ScsiWrite10CommandEx (
3772 ScsiDiskDevice
->ScsiIo
,
3775 &Request
->SenseDataLength
,
3776 &Request
->HostAdapterStatus
,
3777 &Request
->TargetStatus
,
3779 &Request
->DataLength
,
3780 (UINT32
) Request
->StartLba
,
3781 Request
->SectorCount
,
3784 if (EFI_ERROR(Status
)) {
3791 if (Request
!= NULL
) {
3792 if (Request
->SenseData
!= NULL
) {
3793 FreePool (Request
->SenseData
);
3796 RemoveEntryList (&Request
->Link
);
3805 Submit Async Read(16) command.
3807 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3808 @param Timeout The time to complete the command.
3809 @param DataBuffer The buffer to fill with the read out data.
3810 @param DataLength The length of buffer.
3811 @param StartLba The start logic block address.
3812 @param SectorCount The number of blocks to read.
3813 @param BlkIo2Req The upstream BlockIo2 request.
3814 @param Token The pointer to the token associated with the
3815 non-blocking read request.
3817 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3819 @return others Status returned by calling
3820 ScsiRead16CommandEx().
3824 ScsiDiskAsyncRead16 (
3825 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3827 OUT UINT8
*DataBuffer
,
3828 IN UINT32 DataLength
,
3830 IN UINT32 SectorCount
,
3831 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3832 IN EFI_BLOCK_IO2_TOKEN
*Token
3836 SCSI_ASYNC_RW_REQUEST
*Request
;
3837 EFI_EVENT AsyncIoEvent
;
3839 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3840 if (Request
== NULL
) {
3841 return EFI_OUT_OF_RESOURCES
;
3843 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3845 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3846 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3847 if (Request
->SenseData
== NULL
) {
3848 Status
= EFI_OUT_OF_RESOURCES
;
3852 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3853 Request
->Timeout
= Timeout
;
3854 Request
->InBuffer
= DataBuffer
;
3855 Request
->DataLength
= DataLength
;
3856 Request
->StartLba
= StartLba
;
3857 Request
->SectorCount
= SectorCount
;
3858 Request
->BlkIo2Req
= BlkIo2Req
;
3863 Status
= gBS
->CreateEvent (
3870 if (EFI_ERROR(Status
)) {
3874 Status
= ScsiRead16CommandEx (
3875 ScsiDiskDevice
->ScsiIo
,
3878 &Request
->SenseDataLength
,
3879 &Request
->HostAdapterStatus
,
3880 &Request
->TargetStatus
,
3882 &Request
->DataLength
,
3884 Request
->SectorCount
,
3887 if (EFI_ERROR(Status
)) {
3894 if (Request
!= NULL
) {
3895 if (Request
->SenseData
!= NULL
) {
3896 FreePool (Request
->SenseData
);
3899 RemoveEntryList (&Request
->Link
);
3908 Submit Async Write(16) command.
3910 @param ScsiDiskDevice The pointer of ScsiDiskDevice.
3911 @param Timeout The time to complete the command.
3912 @param DataBuffer The buffer contains the data to write.
3913 @param DataLength The length of buffer.
3914 @param StartLba The start logic block address.
3915 @param SectorCount The number of blocks to write.
3916 @param BlkIo2Req The upstream BlockIo2 request.
3917 @param Token The pointer to the token associated with the
3918 non-blocking read request.
3920 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
3922 @return others Status returned by calling
3923 ScsiWrite16CommandEx().
3927 ScsiDiskAsyncWrite16 (
3928 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
3930 IN UINT8
*DataBuffer
,
3931 IN UINT32 DataLength
,
3933 IN UINT32 SectorCount
,
3934 IN OUT SCSI_BLKIO2_REQUEST
*BlkIo2Req
,
3935 IN EFI_BLOCK_IO2_TOKEN
*Token
3939 SCSI_ASYNC_RW_REQUEST
*Request
;
3940 EFI_EVENT AsyncIoEvent
;
3942 Request
= AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST
));
3943 if (Request
== NULL
) {
3944 return EFI_OUT_OF_RESOURCES
;
3946 InsertTailList (&BlkIo2Req
->ScsiRWQueue
, &Request
->Link
);
3948 Request
->SenseDataLength
= (UINT8
) (6 * sizeof (EFI_SCSI_SENSE_DATA
));
3949 Request
->SenseData
= AllocateZeroPool (Request
->SenseDataLength
);
3950 if (Request
->SenseData
== NULL
) {
3951 Status
= EFI_OUT_OF_RESOURCES
;
3955 Request
->ScsiDiskDevice
= ScsiDiskDevice
;
3956 Request
->Timeout
= Timeout
;
3957 Request
->OutBuffer
= DataBuffer
;
3958 Request
->DataLength
= DataLength
;
3959 Request
->StartLba
= StartLba
;
3960 Request
->SectorCount
= SectorCount
;
3961 Request
->BlkIo2Req
= BlkIo2Req
;
3966 Status
= gBS
->CreateEvent (
3973 if (EFI_ERROR(Status
)) {
3977 Status
= ScsiWrite16CommandEx (
3978 ScsiDiskDevice
->ScsiIo
,
3981 &Request
->SenseDataLength
,
3982 &Request
->HostAdapterStatus
,
3983 &Request
->TargetStatus
,
3985 &Request
->DataLength
,
3987 Request
->SectorCount
,
3990 if (EFI_ERROR(Status
)) {
3997 if (Request
!= NULL
) {
3998 if (Request
->SenseData
!= NULL
) {
3999 FreePool (Request
->SenseData
);
4002 RemoveEntryList (&Request
->Link
);
4011 Check sense key to find if media presents.
4013 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4014 @param SenseCounts The number of sense key
4016 @retval TRUE NOT any media
4017 @retval FALSE Media presents
4021 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4022 IN UINTN SenseCounts
4025 EFI_SCSI_SENSE_DATA
*SensePtr
;
4030 SensePtr
= SenseData
;
4032 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4034 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),
4035 // Additional Sense Code is ASC_NO_MEDIA (0x3A)
4037 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NOT_READY
) &&
4038 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_NO_MEDIA
)) {
4051 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4052 @param SenseCounts The number of sense key
4055 @retval FALSE NOT error
4059 ScsiDiskIsMediaError (
4060 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4061 IN UINTN SenseCounts
4064 EFI_SCSI_SENSE_DATA
*SensePtr
;
4069 SensePtr
= SenseData
;
4071 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4073 switch (SensePtr
->Sense_Key
) {
4075 case EFI_SCSI_SK_MEDIUM_ERROR
:
4077 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)
4079 switch (SensePtr
->Addnl_Sense_Code
) {
4084 case EFI_SCSI_ASC_MEDIA_ERR1
:
4089 case EFI_SCSI_ASC_MEDIA_ERR2
:
4094 case EFI_SCSI_ASC_MEDIA_ERR3
:
4095 case EFI_SCSI_ASC_MEDIA_ERR4
:
4105 case EFI_SCSI_SK_NOT_READY
:
4107 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4109 switch (SensePtr
->Addnl_Sense_Code
) {
4111 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
4113 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN
:
4134 Check sense key to find if hardware error happens.
4136 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4137 @param SenseCounts The number of sense key
4139 @retval TRUE Hardware error exits.
4140 @retval FALSE NO error.
4144 ScsiDiskIsHardwareError (
4145 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4146 IN UINTN SenseCounts
4149 EFI_SCSI_SENSE_DATA
*SensePtr
;
4154 SensePtr
= SenseData
;
4156 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4159 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)
4161 if (SensePtr
->Sense_Key
== EFI_SCSI_SK_HARDWARE_ERROR
) {
4173 Check sense key to find if media has changed.
4175 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4176 @param SenseCounts The number of sense key
4178 @retval TRUE Media is changed.
4179 @retval FALSE Media is NOT changed.
4182 ScsiDiskIsMediaChange (
4183 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4184 IN UINTN SenseCounts
4187 EFI_SCSI_SENSE_DATA
*SensePtr
;
4189 BOOLEAN IsMediaChanged
;
4191 IsMediaChanged
= FALSE
;
4192 SensePtr
= SenseData
;
4194 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4196 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),
4197 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)
4199 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
4200 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_MEDIA_CHANGE
)) {
4201 IsMediaChanged
= TRUE
;
4207 return IsMediaChanged
;
4211 Check sense key to find if reset happens.
4213 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4214 @param SenseCounts The number of sense key
4216 @retval TRUE It is reset before.
4217 @retval FALSE It is NOT reset before.
4221 ScsiDiskIsResetBefore (
4222 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4223 IN UINTN SenseCounts
4226 EFI_SCSI_SENSE_DATA
*SensePtr
;
4228 BOOLEAN IsResetBefore
;
4230 IsResetBefore
= FALSE
;
4231 SensePtr
= SenseData
;
4233 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4236 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)
4237 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)
4239 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_UNIT_ATTENTION
) &&
4240 (SensePtr
->Addnl_Sense_Code
== EFI_SCSI_ASC_RESET
)) {
4241 IsResetBefore
= TRUE
;
4247 return IsResetBefore
;
4251 Check sense key to find if the drive is ready.
4253 @param SenseData The pointer of EFI_SCSI_SENSE_DATA
4254 @param SenseCounts The number of sense key
4255 @param RetryLater The flag means if need a retry
4257 @retval TRUE Drive is ready.
4258 @retval FALSE Drive is NOT ready.
4262 ScsiDiskIsDriveReady (
4263 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4264 IN UINTN SenseCounts
,
4265 OUT BOOLEAN
*RetryLater
4268 EFI_SCSI_SENSE_DATA
*SensePtr
;
4273 *RetryLater
= FALSE
;
4274 SensePtr
= SenseData
;
4276 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4278 switch (SensePtr
->Sense_Key
) {
4280 case EFI_SCSI_SK_NOT_READY
:
4282 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)
4284 switch (SensePtr
->Addnl_Sense_Code
) {
4285 case EFI_SCSI_ASC_NOT_READY
:
4287 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)
4289 switch (SensePtr
->Addnl_Sense_Code_Qualifier
) {
4290 case EFI_SCSI_ASCQ_IN_PROGRESS
:
4292 // Additional Sense Code Qualifier is
4293 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)
4301 *RetryLater
= FALSE
;
4322 Check sense key to find if it has sense key.
4324 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA
4325 @param SenseCounts - The number of sense key
4327 @retval TRUE It has sense key.
4328 @retval FALSE It has NOT any sense key.
4332 ScsiDiskHaveSenseKey (
4333 IN EFI_SCSI_SENSE_DATA
*SenseData
,
4334 IN UINTN SenseCounts
4337 EFI_SCSI_SENSE_DATA
*SensePtr
;
4339 BOOLEAN HaveSenseKey
;
4341 if (SenseCounts
== 0) {
4342 HaveSenseKey
= FALSE
;
4344 HaveSenseKey
= TRUE
;
4347 SensePtr
= SenseData
;
4349 for (Index
= 0; Index
< SenseCounts
; Index
++) {
4352 // Sense Key is SK_NO_SENSE (0x0)
4354 if ((SensePtr
->Sense_Key
== EFI_SCSI_SK_NO_SENSE
) &&
4356 HaveSenseKey
= FALSE
;
4362 return HaveSenseKey
;
4366 Release resource about disk device.
4368 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4372 ReleaseScsiDiskDeviceResources (
4373 IN SCSI_DISK_DEV
*ScsiDiskDevice
4376 if (ScsiDiskDevice
== NULL
) {
4380 if (ScsiDiskDevice
->SenseData
!= NULL
) {
4381 FreePool (ScsiDiskDevice
->SenseData
);
4382 ScsiDiskDevice
->SenseData
= NULL
;
4385 if (ScsiDiskDevice
->ControllerNameTable
!= NULL
) {
4386 FreeUnicodeStringTable (ScsiDiskDevice
->ControllerNameTable
);
4387 ScsiDiskDevice
->ControllerNameTable
= NULL
;
4390 FreePool (ScsiDiskDevice
);
4392 ScsiDiskDevice
= NULL
;
4396 Determine if Block Io & Block Io2 should be produced.
4399 @param ChildHandle Child Handle to retrieve Parent information.
4401 @retval TRUE Should produce Block Io & Block Io2.
4402 @retval FALSE Should not produce Block Io & Block Io2.
4406 DetermineInstallBlockIo (
4407 IN EFI_HANDLE ChildHandle
4410 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
4411 EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*ExtScsiPassThru
;
4414 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,
4415 // check its attribute, logic or physical.
4417 ExtScsiPassThru
= (EFI_EXT_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid
, ChildHandle
);
4418 if (ExtScsiPassThru
!= NULL
) {
4419 if ((ExtScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
4425 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,
4426 // check its attribute, logic or physical.
4428 ScsiPassThru
= (EFI_SCSI_PASS_THRU_PROTOCOL
*)GetParentProtocol (&gEfiScsiPassThruProtocolGuid
, ChildHandle
);
4429 if (ScsiPassThru
!= NULL
) {
4430 if ((ScsiPassThru
->Mode
->Attributes
& EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL
) != 0) {
4439 Search protocol database and check to see if the protocol
4440 specified by ProtocolGuid is present on a ControllerHandle and opened by
4441 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
4442 If the ControllerHandle is found, then the protocol specified by ProtocolGuid
4443 will be opened on it.
4446 @param ProtocolGuid ProtocolGuid pointer.
4447 @param ChildHandle Child Handle to retrieve Parent information.
4453 IN EFI_GUID
*ProtocolGuid
,
4454 IN EFI_HANDLE ChildHandle
4461 EFI_HANDLE
*HandleBuffer
;
4464 // Retrieve the list of all handles from the handle database
4466 Status
= gBS
->LocateHandleBuffer (
4474 if (EFI_ERROR (Status
)) {
4479 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle
4481 for (Index
= 0; Index
< HandleCount
; Index
++) {
4482 Status
= EfiTestChildHandle (HandleBuffer
[Index
], ChildHandle
, ProtocolGuid
);
4483 if (!EFI_ERROR (Status
)) {
4484 Status
= gBS
->HandleProtocol (HandleBuffer
[Index
], ProtocolGuid
, (VOID
**)&Interface
);
4485 if (!EFI_ERROR (Status
)) {
4486 gBS
->FreePool (HandleBuffer
);
4492 gBS
->FreePool (HandleBuffer
);
4497 Provides inquiry information for the controller type.
4499 This function is used by the IDE bus driver to get inquiry data. Data format
4500 of Identify data is defined by the Interface GUID.
4502 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4503 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
4504 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
4506 @retval EFI_SUCCESS The command was accepted without any errors.
4507 @retval EFI_NOT_FOUND Device does not support this data class
4508 @retval EFI_DEVICE_ERROR Error reading InquiryData from device
4509 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
4514 ScsiDiskInfoInquiry (
4515 IN EFI_DISK_INFO_PROTOCOL
*This
,
4516 IN OUT VOID
*InquiryData
,
4517 IN OUT UINT32
*InquiryDataSize
4521 SCSI_DISK_DEV
*ScsiDiskDevice
;
4523 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4525 Status
= EFI_BUFFER_TOO_SMALL
;
4526 if (*InquiryDataSize
>= sizeof (ScsiDiskDevice
->InquiryData
)) {
4527 Status
= EFI_SUCCESS
;
4528 CopyMem (InquiryData
, &ScsiDiskDevice
->InquiryData
, sizeof (ScsiDiskDevice
->InquiryData
));
4530 *InquiryDataSize
= sizeof (ScsiDiskDevice
->InquiryData
);
4536 Provides identify information for the controller type.
4538 This function is used by the IDE bus driver to get identify data. Data format
4539 of Identify data is defined by the Interface GUID.
4541 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
4543 @param[in, out] IdentifyData Pointer to a buffer for the identify data.
4544 @param[in, out] IdentifyDataSize Pointer to the value for the identify data
4547 @retval EFI_SUCCESS The command was accepted without any errors.
4548 @retval EFI_NOT_FOUND Device does not support this data class
4549 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
4550 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
4555 ScsiDiskInfoIdentify (
4556 IN EFI_DISK_INFO_PROTOCOL
*This
,
4557 IN OUT VOID
*IdentifyData
,
4558 IN OUT UINT32
*IdentifyDataSize
4562 SCSI_DISK_DEV
*ScsiDiskDevice
;
4564 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
4566 // Physical SCSI bus does not support this data class.
4568 return EFI_NOT_FOUND
;
4571 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4573 Status
= EFI_BUFFER_TOO_SMALL
;
4574 if (*IdentifyDataSize
>= sizeof (ScsiDiskDevice
->IdentifyData
)) {
4575 Status
= EFI_SUCCESS
;
4576 CopyMem (IdentifyData
, &ScsiDiskDevice
->IdentifyData
, sizeof (ScsiDiskDevice
->IdentifyData
));
4578 *IdentifyDataSize
= sizeof (ScsiDiskDevice
->IdentifyData
);
4583 Provides sense data information for the controller type.
4585 This function is used by the IDE bus driver to get sense data.
4586 Data format of Sense data is defined by the Interface GUID.
4588 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4589 @param[in, out] SenseData Pointer to the SenseData.
4590 @param[in, out] SenseDataSize Size of SenseData in bytes.
4591 @param[out] SenseDataNumber Pointer to the value for the sense data size.
4593 @retval EFI_SUCCESS The command was accepted without any errors.
4594 @retval EFI_NOT_FOUND Device does not support this data class.
4595 @retval EFI_DEVICE_ERROR Error reading SenseData from device.
4596 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
4601 ScsiDiskInfoSenseData (
4602 IN EFI_DISK_INFO_PROTOCOL
*This
,
4603 IN OUT VOID
*SenseData
,
4604 IN OUT UINT32
*SenseDataSize
,
4605 OUT UINT8
*SenseDataNumber
4608 return EFI_NOT_FOUND
;
4613 This function is used by the IDE bus driver to get controller information.
4615 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
4616 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
4617 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
4619 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
4620 @retval EFI_UNSUPPORTED This is not an IDE device.
4625 ScsiDiskInfoWhichIde (
4626 IN EFI_DISK_INFO_PROTOCOL
*This
,
4627 OUT UINT32
*IdeChannel
,
4628 OUT UINT32
*IdeDevice
4631 SCSI_DISK_DEV
*ScsiDiskDevice
;
4633 if (CompareGuid (&This
->Interface
, &gEfiDiskInfoScsiInterfaceGuid
) || CompareGuid (&This
->Interface
, &gEfiDiskInfoUfsInterfaceGuid
)) {
4635 // This is not an IDE physical device.
4637 return EFI_UNSUPPORTED
;
4640 ScsiDiskDevice
= SCSI_DISK_DEV_FROM_DISKINFO (This
);
4641 *IdeChannel
= ScsiDiskDevice
->Channel
;
4642 *IdeDevice
= ScsiDiskDevice
->Device
;
4649 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.
4651 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to
4652 implement Identify() interface for DiskInfo protocol. The ATA command is sent
4653 via SCSI Request Packet.
4655 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV
4657 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.
4658 @retval others Some error occurred during the identification that ATAPI device.
4662 AtapiIdentifyDevice (
4663 IN OUT SCSI_DISK_DEV
*ScsiDiskDevice
4666 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket
;
4670 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb
4672 ZeroMem (&CommandPacket
, sizeof (CommandPacket
));
4673 ZeroMem (Cdb
, sizeof (Cdb
));
4675 Cdb
[0] = ATA_CMD_IDENTIFY_DEVICE
;
4676 CommandPacket
.Timeout
= SCSI_DISK_TIMEOUT
;
4677 CommandPacket
.Cdb
= Cdb
;
4678 CommandPacket
.CdbLength
= (UINT8
) sizeof (Cdb
);
4679 CommandPacket
.InDataBuffer
= &ScsiDiskDevice
->IdentifyData
;
4680 CommandPacket
.InTransferLength
= sizeof (ScsiDiskDevice
->IdentifyData
);
4682 return ScsiDiskDevice
->ScsiIo
->ExecuteScsiCommand (ScsiDiskDevice
->ScsiIo
, &CommandPacket
, NULL
);
4687 Initialize the installation of DiskInfo protocol.
4689 This function prepares for the installation of DiskInfo protocol on the child handle.
4690 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further
4691 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID
4692 to be IDE/AHCI interface GUID.
4694 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.
4695 @param ChildHandle Child handle to install DiskInfo protocol.
4699 InitializeInstallDiskInfo (
4700 IN SCSI_DISK_DEV
*ScsiDiskDevice
,
4701 IN EFI_HANDLE ChildHandle
4705 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
4706 EFI_DEVICE_PATH_PROTOCOL
*ChildDevicePathNode
;
4707 ATAPI_DEVICE_PATH
*AtapiDevicePath
;
4708 SATA_DEVICE_PATH
*SataDevicePath
;
4709 UINTN IdentifyRetry
;
4711 Status
= gBS
->HandleProtocol (ChildHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**) &DevicePathNode
);
4713 // Device Path protocol must be installed on the device handle.
4715 ASSERT_EFI_ERROR (Status
);
4717 // Copy the DiskInfo protocol template.
4719 CopyMem (&ScsiDiskDevice
->DiskInfo
, &gScsiDiskInfoProtocolTemplate
, sizeof (gScsiDiskInfoProtocolTemplate
));
4721 while (!IsDevicePathEnd (DevicePathNode
)) {
4722 ChildDevicePathNode
= NextDevicePathNode (DevicePathNode
);
4723 if ((DevicePathType (DevicePathNode
) == HARDWARE_DEVICE_PATH
) &&
4724 (DevicePathSubType (DevicePathNode
) == HW_PCI_DP
) &&
4725 (DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
4726 ((DevicePathSubType (ChildDevicePathNode
) == MSG_ATAPI_DP
) ||
4727 (DevicePathSubType (ChildDevicePathNode
) == MSG_SATA_DP
))) {
4732 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol
4733 // with IDE/AHCI interface GUID.
4735 Status
= AtapiIdentifyDevice (ScsiDiskDevice
);
4736 if (!EFI_ERROR (Status
)) {
4737 if (DevicePathSubType(ChildDevicePathNode
) == MSG_ATAPI_DP
) {
4739 // We find the valid ATAPI device path
4741 AtapiDevicePath
= (ATAPI_DEVICE_PATH
*) ChildDevicePathNode
;
4742 ScsiDiskDevice
->Channel
= AtapiDevicePath
->PrimarySecondary
;
4743 ScsiDiskDevice
->Device
= AtapiDevicePath
->SlaveMaster
;
4745 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.
4747 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
);
4750 // We find the valid SATA device path
4752 SataDevicePath
= (SATA_DEVICE_PATH
*) ChildDevicePathNode
;
4753 ScsiDiskDevice
->Channel
= SataDevicePath
->HBAPortNumber
;
4754 ScsiDiskDevice
->Device
= SataDevicePath
->PortMultiplierPortNumber
;
4756 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.
4758 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoAhciInterfaceGuid
);
4762 } while (--IdentifyRetry
> 0);
4763 } else if ((DevicePathType (ChildDevicePathNode
) == MESSAGING_DEVICE_PATH
) &&
4764 (DevicePathSubType (ChildDevicePathNode
) == MSG_UFS_DP
)) {
4765 CopyGuid (&ScsiDiskDevice
->DiskInfo
.Interface
, &gEfiDiskInfoUfsInterfaceGuid
);
4768 DevicePathNode
= ChildDevicePathNode
;